diff --git a/go.mod b/go.mod index fff8d7f..5f9c0d7 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,14 @@ require ( github.com/gogo/protobuf v1.3.1 github.com/ipfs/go-log v1.0.4 github.com/libp2p/go-buffer-pool v0.0.2 + github.com/libp2p/go-libp2p-asn-util v0.0.0-20210211060025-0db24c10d3bd github.com/libp2p/go-libp2p-blankhost v0.2.0 - github.com/libp2p/go-libp2p-core v0.7.0 - github.com/libp2p/go-libp2p-swarm v0.3.0 - github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 + github.com/libp2p/go-libp2p-core v0.8.3 + github.com/libp2p/go-libp2p-peerstore v0.2.6 + github.com/libp2p/go-libp2p-swarm v0.4.3 + github.com/libp2p/go-libp2p-transport-upgrader v0.4.2 github.com/libp2p/go-msgio v0.0.6 + github.com/libp2p/go-tcp-transport v0.2.0 github.com/multiformats/go-multiaddr v0.3.1 github.com/multiformats/go-varint v0.0.6 ) diff --git a/go.sum b/go.sum index 54976bd..1e9d1a1 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,21 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +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-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= @@ -17,14 +28,18 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/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/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 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= @@ -39,28 +54,61 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/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.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 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.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 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/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.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -70,15 +118,19 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +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.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= @@ -86,8 +138,9 @@ github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5 h1:fL4YI+1g5V/b1Yxr1qAiXTMg1H8z9vx/VmJxBuQMHvU= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= +github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= @@ -96,9 +149,12 @@ github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsj github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/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= @@ -109,6 +165,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= @@ -116,56 +173,73 @@ github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwn github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= +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-conn-security-multistream v0.2.1 h1:ft6/POSK7F+vl/2qzegnHDaXFU0iWB4yVTYrioC6Zy0= +github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p-asn-util v0.0.0-20210211060025-0db24c10d3bd h1:4+wRQ07VJe0ogkb74jFJwhiPuuSbSY1zSUl+tFlNbpg= +github.com/libp2p/go-libp2p-asn-util v0.0.0-20210211060025-0db24c10d3bd/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.7.0 h1:4a0TMjrWNTZlNvcqxZmrMRDi/NQWrhwO2pkTuLSQ/IQ= github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.3 h1:BZTReEF6o8g/n4DwxTyeFannOeae35Xy0TD+mES3CNE= +github.com/libp2p/go-libp2p-core v0.8.3/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.3 h1:2zijwaJvpdesST2MXpI5w9wWFRgYtMcpRX7rrw0jmOo= github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= +github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= +github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U= github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-swarm v0.3.0 h1:w18ZLMccbvwgyR+dODEeA3r1zbFZj+YVq6PClXo77lY= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= +github.com/libp2p/go-libp2p-quic-transport v0.10.0 h1:koDCbWD9CCHwcHZL3/WEvP2A+e/o5/W5L3QS/2SPMA0= +github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= +github.com/libp2p/go-libp2p-swarm v0.4.3 h1:tAdkIj9gxMernQ6FTDPALnb8zAiw8xmcYz85FfA4oME= +github.com/libp2p/go-libp2p-swarm v0.4.3/go.mod h1:mmxP1pGBSc1Arw4F5DIjcpjFAmsRzA1KADuMtMuCT4g= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.3.0 h1:ZiBYstPamsi7y6NJZebRudUzsYmVkt998hltyLqf8+g= +github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= +github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= +github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= +github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= +github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-yamux v0.4.0 h1:qunEZzWwwmfSBYTtSyd81PlD1TjB5uuWcGYHWVXLbUg= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.2 h1:4JsnbfJzgZeRS9AWN7B9dPqn/LY/HoQTlO9gtdJTIYM= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= +github.com/libp2p/go-libp2p-yamux v0.5.0 h1:ZzmUhbQE+X7NuYUT2naxN31JyebZfRmpZVhKtRP13ys= +github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.2 h1:qOg1s+WdGLlpkrczDqmhYzyk3vCfsQ8+RxRTQjOZWwI= github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= +github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-netroute v0.1.2 h1:UHhB35chwgvcRI392znJA3RCBtZ3MpE3ahNCN5MR4Xg= github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.3 h1:1ngWRx61us/EpaKkdqkMjKk/ufr/JlIFYQAxV2XX8Ig= +github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= @@ -180,15 +254,26 @@ github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DX github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= github.com/libp2p/go-tcp-transport v0.2.0 h1:YoThc549fzmNJIh7XjHVtMIFaEDRtIrtWciG5LyYAPo= github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-yamux v1.4.0 h1:7nqe0T95T2CWh40IdJ/tp8RMor4ubc9/wYZpB2a/Hx0= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= +github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4= +github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= +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/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= +github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= +github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= +github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ= +github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= 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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= 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= @@ -199,6 +284,8 @@ github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKU github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= 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.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -224,7 +311,6 @@ github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDu github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= @@ -237,33 +323,74 @@ github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpK github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI= github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-multistream v0.2.1 h1:R5exp4cKvGlePuxg/bn4cnV53K4DxCe+uldxs7QzfrE= +github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/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/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_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/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/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/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= @@ -285,13 +412,17 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= 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/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= 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= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -308,20 +439,29 @@ go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKY go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +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-20190225124518-7f87c0fbb88b/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-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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= @@ -331,41 +471,69 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-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= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/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-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +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-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -375,33 +543,64 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/v2/client/client.go b/v2/client/client.go new file mode 100644 index 0000000..d1740e2 --- /dev/null +++ b/v2/client/client.go @@ -0,0 +1,66 @@ +package client + +import ( + "context" + "sync" + + "github.com/libp2p/go-libp2p-circuit/v2/proto" + + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + + logging "github.com/ipfs/go-log" + tptu "github.com/libp2p/go-libp2p-transport-upgrader" +) + +var log = logging.Logger("p2p-circuit") + +// Client implements the client-side of the p2p-circuit/v2 protocol: +// - it implements dialing through v2 relays +// - it listens for incoming connections through v2 relays. +// +// For backwards compatibility with v1 relays and older nodes, the client will +// also accept relay connections through v1 relays and fallback dial peers using p2p-circuit/v1. +// This allows us to use the v2 code as drop in replacement for v1 in a host without breaking +// existing code and interoperability with older nodes. +type Client struct { + ctx context.Context + host host.Host + upgrader *tptu.Upgrader + + incoming chan accept + + mx sync.Mutex + activeDials map[peer.ID]*completion + hopCount map[peer.ID]int +} + +type accept struct { + conn *Conn + writeResponse func() error +} + +type completion struct { + ch chan struct{} + relay peer.ID + err error +} + +// New constructs a new p2p-circuit/v2 client, attached to the given host and using the given +// upgrader to perform connection upgrades. +func New(ctx context.Context, h host.Host, upgrader *tptu.Upgrader) (*Client, error) { + return &Client{ + ctx: ctx, + host: h, + upgrader: upgrader, + incoming: make(chan accept), + activeDials: make(map[peer.ID]*completion), + hopCount: make(map[peer.ID]int), + }, nil +} + +// Start registers the circuit (client) protocol stream handlers +func (c *Client) Start() { + c.host.SetStreamHandler(proto.ProtoIDv1, c.handleStreamV1) + c.host.SetStreamHandler(proto.ProtoIDv2Stop, c.handleStreamV2) +} diff --git a/v2/client/conn.go b/v2/client/conn.go new file mode 100644 index 0000000..dc77076 --- /dev/null +++ b/v2/client/conn.go @@ -0,0 +1,145 @@ +package client + +import ( + "fmt" + "net" + "time" + + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +// HopTagWeight is the connection manager weight for connections carrying relay hop streams +var HopTagWeight = 5 + +type statLimitDuration struct{} +type statLimitData struct{} + +var ( + StatLimitDuration = statLimitDuration{} + StatLimitData = statLimitData{} +) + +type Conn struct { + stream network.Stream + remote peer.AddrInfo + stat network.Stat + + client *Client +} + +type NetAddr struct { + Relay string + Remote string +} + +var _ net.Addr = (*NetAddr)(nil) + +func (n *NetAddr) Network() string { + return "libp2p-circuit-relay" +} + +func (n *NetAddr) String() string { + return fmt.Sprintf("relay[%s-%s]", n.Remote, n.Relay) +} + +// Conn interface +var _ manet.Conn = (*Conn)(nil) + +func (c *Conn) Close() error { + c.untagHop() + return c.stream.Reset() +} + +func (c *Conn) Read(buf []byte) (int, error) { + return c.stream.Read(buf) +} + +func (c *Conn) Write(buf []byte) (int, error) { + return c.stream.Write(buf) +} + +func (c *Conn) SetDeadline(t time.Time) error { + return c.stream.SetDeadline(t) +} + +func (c *Conn) SetReadDeadline(t time.Time) error { + return c.stream.SetReadDeadline(t) +} + +func (c *Conn) SetWriteDeadline(t time.Time) error { + return c.stream.SetWriteDeadline(t) +} + +// TODO: is it okay to cast c.Conn().RemotePeer() into a multiaddr? might be "user input" +func (c *Conn) RemoteMultiaddr() ma.Multiaddr { + // TODO: We should be able to do this directly without converting to/from a string. + relayAddr, err := ma.NewComponent( + ma.ProtocolWithCode(ma.P_P2P).Name, + c.stream.Conn().RemotePeer().Pretty(), + ) + if err != nil { + panic(err) + } + return ma.Join(c.stream.Conn().RemoteMultiaddr(), relayAddr, circuitAddr) +} + +func (c *Conn) LocalMultiaddr() ma.Multiaddr { + return c.stream.Conn().LocalMultiaddr() +} + +func (c *Conn) LocalAddr() net.Addr { + na, err := manet.ToNetAddr(c.stream.Conn().LocalMultiaddr()) + if err != nil { + log.Error("failed to convert local multiaddr to net addr:", err) + return nil + } + return na +} + +func (c *Conn) RemoteAddr() net.Addr { + return &NetAddr{ + Relay: c.stream.Conn().RemotePeer().Pretty(), + Remote: c.remote.ID.Pretty(), + } +} + +// ConnStat interface +var _ network.ConnStat = (*Conn)(nil) + +func (c *Conn) Stat() network.Stat { + return c.stat +} + +// tagHop tags the underlying relay connection so that it can be (somewhat) protected from the +// connection manager as it is an important connection that proxies other connections. +// This is handled here so that the user code doesnt need to bother with this and avoid +// clown shoes situations where a high value peer connection is behind a relayed connection and it is +// implicitly because the connection manager closed the underlying relay connection. +func (c *Conn) tagHop() { + c.client.mx.Lock() + defer c.client.mx.Unlock() + + p := c.stream.Conn().RemotePeer() + c.client.hopCount[p]++ + if c.client.hopCount[p] == 1 { + c.client.host.ConnManager().TagPeer(p, "relay-hop-stream", HopTagWeight) + } +} + +// untagHop removes the relay-hop-stream tag if necessary; it is invoked when a relayed connection +// is closed. +func (c *Conn) untagHop() { + c.client.mx.Lock() + defer c.client.mx.Unlock() + + p := c.stream.Conn().RemotePeer() + c.client.hopCount[p]-- + if c.client.hopCount[p] == 0 { + c.client.host.ConnManager().UntagPeer(p, "relay-hop-stream") + delete(c.client.hopCount, p) + } +} diff --git a/v2/client/dial.go b/v2/client/dial.go new file mode 100644 index 0000000..0ce1c18 --- /dev/null +++ b/v2/client/dial.go @@ -0,0 +1,239 @@ +package client + +import ( + "context" + "fmt" + "time" + + pbv1 "github.com/libp2p/go-libp2p-circuit/pb" + pbv2 "github.com/libp2p/go-libp2p-circuit/v2/pb" + "github.com/libp2p/go-libp2p-circuit/v2/proto" + "github.com/libp2p/go-libp2p-circuit/v2/util" + + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + + ma "github.com/multiformats/go-multiaddr" +) + +const maxMessageSize = 4096 + +var DialTimeout = time.Minute +var DialRelayTimeout = 5 * time.Second + +// relay protocol errors; used for signalling deduplication +type relayError struct { + err string +} + +func (e relayError) Error() string { + return e.err +} + +func newRelayError(t string, args ...interface{}) error { + return relayError{err: fmt.Sprintf(t, args...)} +} + +func isRelayError(err error) bool { + _, ok := err.(relayError) + return ok +} + +// dialer +func (c *Client) dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (*Conn, error) { + // split /a/p2p-circuit/b into (/a, /p2p-circuit/b) + relayaddr, destaddr := ma.SplitFunc(a, func(c ma.Component) bool { + return c.Protocol().Code == ma.P_CIRCUIT + }) + + // If the address contained no /p2p-circuit part, the second part is nil. + if destaddr == nil { + return nil, fmt.Errorf("%s is not a relay address", a) + } + + if relayaddr == nil { + return nil, fmt.Errorf("can't dial a p2p-circuit without specifying a relay: %s", a) + } + + dinfo := peer.AddrInfo{ID: p} + + // Strip the /p2p-circuit prefix from the destaddr so that we can pass the destination address + // (if present) for active relays + _, destaddr = ma.SplitFirst(destaddr) + if destaddr != nil { + dinfo.Addrs = append(dinfo.Addrs, destaddr) + } + + rinfo, err := peer.AddrInfoFromP2pAddr(relayaddr) + if err != nil { + return nil, fmt.Errorf("error parsing relay multiaddr '%s': %w", relayaddr, err) + } + + // deduplicate active relay dials to the same peer +retry: + c.mx.Lock() + dedup, active := c.activeDials[p] + if !active { + dedup = &completion{ch: make(chan struct{}), relay: rinfo.ID} + c.activeDials[p] = dedup + } + c.mx.Unlock() + + if active { + select { + case <-dedup.ch: + if dedup.err != nil { + if dedup.relay != rinfo.ID { + // different relay, retry + goto retry + } + + if !isRelayError(dedup.err) { + // not a relay protocol error, retry + goto retry + } + + // don't try the same relay if it failed to connect with a protocol error + return nil, fmt.Errorf("concurrent active dial through the same relay failed with a protocol error") + } + + return nil, fmt.Errorf("concurrent active dial succeeded") + + case <-ctx.Done(): + return nil, ctx.Err() + } + } + + conn, err := c.dialPeer(ctx, *rinfo, dinfo) + + c.mx.Lock() + dedup.err = err + close(dedup.ch) + delete(c.activeDials, p) + c.mx.Unlock() + + return conn, err +} + +func (c *Client) dialPeer(ctx context.Context, relay, dest peer.AddrInfo) (*Conn, error) { + log.Debugf("dialing peer %s through relay %s", dest.ID, relay.ID) + + if len(relay.Addrs) > 0 { + c.host.Peerstore().AddAddrs(relay.ID, relay.Addrs, peerstore.TempAddrTTL) + } + + dialCtx, cancel := context.WithTimeout(ctx, DialRelayTimeout) + defer cancel() + s, err := c.host.NewStream(dialCtx, relay.ID, proto.ProtoIDv2Hop, proto.ProtoIDv1) + if err != nil { + return nil, fmt.Errorf("error opening hop stream to relay: %w", err) + } + + switch s.Protocol() { + case proto.ProtoIDv2Hop: + return c.connectV2(s, dest) + + case proto.ProtoIDv1: + return c.connectV1(s, dest) + + default: + s.Reset() + return nil, fmt.Errorf("unexpected stream protocol: %s", s.Protocol()) + } +} + +func (c *Client) connectV2(s network.Stream, dest peer.AddrInfo) (*Conn, error) { + rd := util.NewDelimitedReader(s, maxMessageSize) + wr := util.NewDelimitedWriter(s) + defer rd.Close() + + var msg pbv2.HopMessage + + msg.Type = pbv2.HopMessage_CONNECT.Enum() + msg.Peer = util.PeerInfoToPeerV2(dest) + + s.SetDeadline(time.Now().Add(DialTimeout)) + + err := wr.WriteMsg(&msg) + if err != nil { + s.Reset() + return nil, err + } + + msg.Reset() + + err = rd.ReadMsg(&msg) + if err != nil { + s.Reset() + return nil, err + } + + s.SetDeadline(time.Time{}) + + if msg.GetType() != pbv2.HopMessage_STATUS { + s.Reset() + return nil, newRelayError("unexpected relay response; not a status message (%d)", msg.GetType()) + } + + status := msg.GetStatus() + if status != pbv2.Status_OK { + s.Reset() + return nil, newRelayError("error opening relay circuit: %s (%d)", pbv2.Status_name[int32(status)], status) + } + + // check for a limit provided by the relay; if the limit is not nil, then this is a limited + // relay connection and we mark the connection as transient. + var stat network.Stat + if limit := msg.GetLimit(); limit != nil { + stat.Transient = true + stat.Extra = make(map[interface{}]interface{}) + stat.Extra[StatLimitDuration] = time.Duration(limit.GetDuration()) * time.Second + stat.Extra[StatLimitData] = limit.GetData() + } + + return &Conn{stream: s, remote: dest, stat: stat, client: c}, nil +} + +func (c *Client) connectV1(s network.Stream, dest peer.AddrInfo) (*Conn, error) { + rd := util.NewDelimitedReader(s, maxMessageSize) + wr := util.NewDelimitedWriter(s) + defer rd.Close() + + var msg pbv1.CircuitRelay + + msg.Type = pbv1.CircuitRelay_HOP.Enum() + msg.SrcPeer = util.PeerInfoToPeerV1(c.host.Peerstore().PeerInfo(c.host.ID())) + msg.DstPeer = util.PeerInfoToPeerV1(dest) + + s.SetDeadline(time.Now().Add(DialTimeout)) + + err := wr.WriteMsg(&msg) + if err != nil { + s.Reset() + return nil, err + } + + msg.Reset() + + err = rd.ReadMsg(&msg) + if err != nil { + s.Reset() + return nil, err + } + + s.SetDeadline(time.Time{}) + + if msg.GetType() != pbv1.CircuitRelay_STATUS { + s.Reset() + return nil, newRelayError("unexpected relay response; not a status message (%d)", msg.GetType()) + } + + status := msg.GetCode() + if status != pbv1.CircuitRelay_SUCCESS { + s.Reset() + return nil, newRelayError("error opening relay circuit: %s (%d)", pbv1.CircuitRelay_Status_name[int32(status)], status) + } + + return &Conn{stream: s, remote: dest, client: c}, nil +} diff --git a/v2/client/handlers.go b/v2/client/handlers.go new file mode 100644 index 0000000..9239fce --- /dev/null +++ b/v2/client/handlers.go @@ -0,0 +1,172 @@ +package client + +import ( + "time" + + pbv1 "github.com/libp2p/go-libp2p-circuit/pb" + pbv2 "github.com/libp2p/go-libp2p-circuit/v2/pb" + "github.com/libp2p/go-libp2p-circuit/v2/util" + + "github.com/libp2p/go-libp2p-core/network" +) + +var ( + StreamTimeout = 1 * time.Minute + AcceptTimeout = 10 * time.Second +) + +func (c *Client) handleStreamV2(s network.Stream) { + log.Debugf("new relay/v2 stream from: %s", s.Conn().RemotePeer()) + + s.SetReadDeadline(time.Now().Add(StreamTimeout)) + + rd := util.NewDelimitedReader(s, maxMessageSize) + defer rd.Close() + + writeResponse := func(status pbv2.Status) error { + wr := util.NewDelimitedWriter(s) + + var msg pbv2.StopMessage + msg.Type = pbv2.StopMessage_STATUS.Enum() + msg.Status = status.Enum() + + return wr.WriteMsg(&msg) + } + + handleError := func(status pbv2.Status) { + log.Debugf("protocol error: %s (%d)", pbv2.Status_name[int32(status)], status) + err := writeResponse(status) + if err != nil { + s.Reset() + log.Debugf("error writing circuit response: %s", err.Error()) + } else { + s.Close() + } + } + + var msg pbv2.StopMessage + + err := rd.ReadMsg(&msg) + if err != nil { + handleError(pbv2.Status_MALFORMED_MESSAGE) + return + } + // reset stream deadline as message has been read + s.SetReadDeadline(time.Time{}) + + if msg.GetType() != pbv2.StopMessage_CONNECT { + handleError(pbv2.Status_UNEXPECTED_MESSAGE) + return + } + + src, err := util.PeerToPeerInfoV2(msg.GetPeer()) + if err != nil { + handleError(pbv2.Status_MALFORMED_MESSAGE) + return + } + + // check for a limit provided by the relay; if the limit is not nil, then this is a limited + // relay connection and we mark the connection as transient. + var stat network.Stat + if limit := msg.GetLimit(); limit != nil { + stat.Transient = true + stat.Extra = make(map[interface{}]interface{}) + stat.Extra[StatLimitDuration] = time.Duration(limit.GetDuration()) * time.Second + stat.Extra[StatLimitData] = limit.GetData() + } + + log.Debugf("incoming relay connection from: %s", src.ID) + + select { + case c.incoming <- accept{ + conn: &Conn{stream: s, remote: src, stat: stat, client: c}, + writeResponse: func() error { + return writeResponse(pbv2.Status_OK) + }, + }: + case <-time.After(AcceptTimeout): + handleError(pbv2.Status_CONNECTION_FAILED) + } +} + +func (c *Client) handleStreamV1(s network.Stream) { + log.Debugf("new relay/v1 stream from: %s", s.Conn().RemotePeer()) + + s.SetReadDeadline(time.Now().Add(StreamTimeout)) + + rd := util.NewDelimitedReader(s, maxMessageSize) + defer rd.Close() + + writeResponse := func(status pbv1.CircuitRelay_Status) error { + wr := util.NewDelimitedWriter(s) + + var msg pbv1.CircuitRelay + msg.Type = pbv1.CircuitRelay_STATUS.Enum() + msg.Code = status.Enum() + + return wr.WriteMsg(&msg) + } + + handleError := func(status pbv1.CircuitRelay_Status) { + log.Debugf("protocol error: %s (%d)", pbv1.CircuitRelay_Status_name[int32(status)], status) + err := writeResponse(status) + if err != nil { + s.Reset() + log.Debugf("error writing circuit response: %s", err.Error()) + } else { + s.Close() + } + } + + var msg pbv1.CircuitRelay + + err := rd.ReadMsg(&msg) + if err != nil { + handleError(pbv1.CircuitRelay_MALFORMED_MESSAGE) + return + } + // reset stream deadline as message has been read + s.SetReadDeadline(time.Time{}) + + switch msg.GetType() { + case pbv1.CircuitRelay_STOP: + + case pbv1.CircuitRelay_HOP: + handleError(pbv1.CircuitRelay_HOP_CANT_SPEAK_RELAY) + return + + case pbv1.CircuitRelay_CAN_HOP: + handleError(pbv1.CircuitRelay_HOP_CANT_SPEAK_RELAY) + return + + default: + log.Debugf("unexpected relay handshake: %d", msg.GetType()) + handleError(pbv1.CircuitRelay_MALFORMED_MESSAGE) + return + } + + src, err := util.PeerToPeerInfoV1(msg.GetSrcPeer()) + if err != nil { + handleError(pbv1.CircuitRelay_STOP_SRC_MULTIADDR_INVALID) + return + } + + dst, err := util.PeerToPeerInfoV1(msg.GetDstPeer()) + if err != nil || dst.ID != c.host.ID() { + handleError(pbv1.CircuitRelay_STOP_DST_MULTIADDR_INVALID) + return + } + + log.Debugf("incoming relay connection from: %s", src.ID) + + select { + case c.incoming <- accept{ + conn: &Conn{stream: s, remote: src, client: c}, + writeResponse: func() error { + return writeResponse(pbv1.CircuitRelay_SUCCESS) + }, + }: + case <-time.After(AcceptTimeout): + handleError(pbv1.CircuitRelay_STOP_RELAY_REFUSED) + } +} diff --git a/v2/client/listen.go b/v2/client/listen.go new file mode 100644 index 0000000..fcfb9fa --- /dev/null +++ b/v2/client/listen.go @@ -0,0 +1,54 @@ +package client + +import ( + "net" + + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +var _ manet.Listener = (*Listener)(nil) + +type Listener Client + +func (c *Client) Listener() *Listener { + return (*Listener)(c) +} + +func (l *Listener) Accept() (manet.Conn, error) { + for { + select { + case evt := <-l.incoming: + err := evt.writeResponse() + if err != nil { + log.Debugf("error writing relay response: %s", err.Error()) + evt.conn.stream.Reset() + continue + } + + log.Debugf("accepted relay connection from %s through %s", evt.conn.remote.ID, evt.conn.RemoteMultiaddr()) + + evt.conn.tagHop() + return evt.conn, nil + + case <-l.ctx.Done(): + return nil, l.ctx.Err() + } + } +} + +func (l *Listener) Addr() net.Addr { + return &NetAddr{ + Relay: "any", + Remote: "any", + } +} + +func (l *Listener) Multiaddr() ma.Multiaddr { + return circuitAddr +} + +func (l *Listener) Close() error { + // noop for now + return nil +} diff --git a/v2/client/reservation.go b/v2/client/reservation.go new file mode 100644 index 0000000..49b0a47 --- /dev/null +++ b/v2/client/reservation.go @@ -0,0 +1,122 @@ +package client + +import ( + "context" + "fmt" + "time" + + pbv2 "github.com/libp2p/go-libp2p-circuit/v2/pb" + "github.com/libp2p/go-libp2p-circuit/v2/proto" + "github.com/libp2p/go-libp2p-circuit/v2/util" + + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/record" + + ma "github.com/multiformats/go-multiaddr" +) + +var ReserveTimeout = time.Minute + +// Reservation is a struct carrying information about a relay/v2 slot reservation. +type Reservation struct { + // Expiration is the expiration time of the reservation + Expiration time.Time + // Addrs contains the vouched public addresses of the reserving peer, which can be + // announced to the network + Addrs []ma.Multiaddr + + // LimitDuration is the time limit for which the relay will keep a relayed connection + // open. If 0, there is no limit. + LimitDuration time.Duration + // LimitData is the number of bytes that the relay will relay in each direction before + // resetting a relayed connection. + LimitData uint64 + + // Voucher is a signed reservation voucher provided by the relay + Voucher *proto.ReservationVoucher +} + +// Reserve reserves a slot in a relay and returns the reservation information. +// Clients must reserve slots in order for the relay to relay connections to them. +func Reserve(ctx context.Context, h host.Host, ai peer.AddrInfo) (*Reservation, error) { + if len(ai.Addrs) > 0 { + h.Peerstore().AddAddrs(ai.ID, ai.Addrs, peerstore.TempAddrTTL) + } + + s, err := h.NewStream(ctx, ai.ID, proto.ProtoIDv2Hop) + if err != nil { + return nil, err + } + defer s.Close() + + rd := util.NewDelimitedReader(s, maxMessageSize) + wr := util.NewDelimitedWriter(s) + defer rd.Close() + + var msg pbv2.HopMessage + msg.Type = pbv2.HopMessage_RESERVE.Enum() + + s.SetDeadline(time.Now().Add(ReserveTimeout)) + + if err := wr.WriteMsg(&msg); err != nil { + s.Reset() + return nil, fmt.Errorf("error writing reservation message: %w", err) + } + + msg.Reset() + + if err := rd.ReadMsg(&msg); err != nil { + s.Reset() + return nil, fmt.Errorf("error reading reservation response message: %w", err) + } + + if msg.GetType() != pbv2.HopMessage_STATUS { + return nil, fmt.Errorf("unexpected relay response: not a status message (%d)", msg.GetType()) + } + + if status := msg.GetStatus(); status != pbv2.Status_OK { + return nil, fmt.Errorf("reservation failed: %s (%d)", pbv2.Status_name[int32(status)], status) + } + + rsvp := msg.GetReservation() + if rsvp == nil { + return nil, fmt.Errorf("missing reservation info") + } + + result := &Reservation{} + result.Expiration = time.Unix(int64(rsvp.GetExpire()), 0) + + for _, ab := range rsvp.GetAddrs() { + a, err := ma.NewMultiaddrBytes(ab) + if err != nil { + log.Warnf("ignoring unparsable relay address: %s", err) + continue + } + result.Addrs = append(result.Addrs, a) + } + + voucherBytes := rsvp.GetVoucher() + if voucherBytes != nil { + _, rec, err := record.ConsumeEnvelope(voucherBytes, proto.RecordDomain) + if err != nil { + return nil, fmt.Errorf("error consuming voucher envelope: %w", err) + } + + voucher, ok := rec.(*proto.ReservationVoucher) + if !ok { + return nil, fmt.Errorf("unexpected voucher record type: %+T", rec) + } + + result.Voucher = voucher + } + + limit := msg.GetLimit() + if limit != nil { + result.LimitDuration = time.Duration(limit.GetDuration()) * time.Second + result.LimitData = limit.GetData() + } + + return result, nil +} diff --git a/v2/client/transport.go b/v2/client/transport.go new file mode 100644 index 0000000..406188c --- /dev/null +++ b/v2/client/transport.go @@ -0,0 +1,80 @@ +package client + +import ( + "context" + "fmt" + + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/transport" + + tptu "github.com/libp2p/go-libp2p-transport-upgrader" + ma "github.com/multiformats/go-multiaddr" +) + +var circuitProtocol = ma.ProtocolWithCode(ma.P_CIRCUIT) +var circuitAddr = ma.Cast(circuitProtocol.VCode) + +// AddTransport constructs a new p2p-circuit/v2 client and adds it as a transport to the +// host network +func AddTransport(ctx context.Context, h host.Host, upgrader *tptu.Upgrader) error { + n, ok := h.Network().(transport.TransportNetwork) + if !ok { + return fmt.Errorf("%v is not a transport network", h.Network()) + } + + c, err := New(ctx, h, upgrader) + if err != nil { + return fmt.Errorf("error constructing circuit client: %w", err) + } + + err = n.AddTransport(c) + if err != nil { + return fmt.Errorf("error adding circuit transport: %w", err) + } + + err = n.Listen(circuitAddr) + if err != nil { + return fmt.Errorf("error listening to circuit addr: %w", err) + } + + c.Start() + + return nil +} + +// Transport interface +var _ transport.Transport = (*Client)(nil) + +func (c *Client) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (transport.CapableConn, error) { + conn, err := c.dial(ctx, a, p) + if err != nil { + return nil, err + } + + conn.tagHop() + + return c.upgrader.UpgradeOutbound(ctx, c, conn, p) +} + +func (c *Client) CanDial(addr ma.Multiaddr) bool { + _, err := addr.ValueForProtocol(ma.P_CIRCUIT) + return err == nil +} + +func (c *Client) Listen(addr ma.Multiaddr) (transport.Listener, error) { + // TODO connect to the relay and reserve slot if specified + if _, err := addr.ValueForProtocol(ma.P_CIRCUIT); err != nil { + return nil, err + } + + return c.upgrader.UpgradeListener(c, c.Listener()), nil +} + +func (c *Client) Protocols() []int { + return []int{ma.P_CIRCUIT} +} + +func (c *Client) Proxy() bool { + return true +} diff --git a/v2/pb/Makefile b/v2/pb/Makefile new file mode 100644 index 0000000..c360a6f --- /dev/null +++ b/v2/pb/Makefile @@ -0,0 +1,11 @@ +PB = $(wildcard *.proto) +GO = $(PB:.proto=.pb.go) + +all: $(GO) + +%.pb.go: %.proto + protoc --gogofast_out=. $< + +clean: + rm -f *.pb.go + rm -f *.go diff --git a/v2/pb/circuit.pb.go b/v2/pb/circuit.pb.go new file mode 100644 index 0000000..f908d0d --- /dev/null +++ b/v2/pb/circuit.pb.go @@ -0,0 +1,1766 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: circuit.proto + +package circuit_pb + +import ( + fmt "fmt" + github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Status int32 + +const ( + Status_OK Status = 100 + Status_RESERVATION_REFUSED Status = 200 + Status_RESOURCE_LIMIT_EXCEEDED Status = 201 + Status_PERMISSION_DENIED Status = 202 + Status_CONNECTION_FAILED Status = 203 + Status_NO_RESERVATION Status = 204 + Status_MALFORMED_MESSAGE Status = 400 + Status_UNEXPECTED_MESSAGE Status = 401 +) + +var Status_name = map[int32]string{ + 100: "OK", + 200: "RESERVATION_REFUSED", + 201: "RESOURCE_LIMIT_EXCEEDED", + 202: "PERMISSION_DENIED", + 203: "CONNECTION_FAILED", + 204: "NO_RESERVATION", + 400: "MALFORMED_MESSAGE", + 401: "UNEXPECTED_MESSAGE", +} + +var Status_value = map[string]int32{ + "OK": 100, + "RESERVATION_REFUSED": 200, + "RESOURCE_LIMIT_EXCEEDED": 201, + "PERMISSION_DENIED": 202, + "CONNECTION_FAILED": 203, + "NO_RESERVATION": 204, + "MALFORMED_MESSAGE": 400, + "UNEXPECTED_MESSAGE": 401, +} + +func (x Status) Enum() *Status { + p := new(Status) + *p = x + return p +} + +func (x Status) String() string { + return proto.EnumName(Status_name, int32(x)) +} + +func (x *Status) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Status_value, data, "Status") + if err != nil { + return err + } + *x = Status(value) + return nil +} + +func (Status) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{0} +} + +type HopMessage_Type int32 + +const ( + HopMessage_RESERVE HopMessage_Type = 0 + HopMessage_CONNECT HopMessage_Type = 1 + HopMessage_STATUS HopMessage_Type = 2 +) + +var HopMessage_Type_name = map[int32]string{ + 0: "RESERVE", + 1: "CONNECT", + 2: "STATUS", +} + +var HopMessage_Type_value = map[string]int32{ + "RESERVE": 0, + "CONNECT": 1, + "STATUS": 2, +} + +func (x HopMessage_Type) Enum() *HopMessage_Type { + p := new(HopMessage_Type) + *p = x + return p +} + +func (x HopMessage_Type) String() string { + return proto.EnumName(HopMessage_Type_name, int32(x)) +} + +func (x *HopMessage_Type) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(HopMessage_Type_value, data, "HopMessage_Type") + if err != nil { + return err + } + *x = HopMessage_Type(value) + return nil +} + +func (HopMessage_Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{0, 0} +} + +type StopMessage_Type int32 + +const ( + StopMessage_CONNECT StopMessage_Type = 0 + StopMessage_STATUS StopMessage_Type = 1 +) + +var StopMessage_Type_name = map[int32]string{ + 0: "CONNECT", + 1: "STATUS", +} + +var StopMessage_Type_value = map[string]int32{ + "CONNECT": 0, + "STATUS": 1, +} + +func (x StopMessage_Type) Enum() *StopMessage_Type { + p := new(StopMessage_Type) + *p = x + return p +} + +func (x StopMessage_Type) String() string { + return proto.EnumName(StopMessage_Type_name, int32(x)) +} + +func (x *StopMessage_Type) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(StopMessage_Type_value, data, "StopMessage_Type") + if err != nil { + return err + } + *x = StopMessage_Type(value) + return nil +} + +func (StopMessage_Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{1, 0} +} + +type HopMessage struct { + Type *HopMessage_Type `protobuf:"varint,1,req,name=type,enum=circuit.pb.HopMessage_Type" json:"type,omitempty"` + Peer *Peer `protobuf:"bytes,2,opt,name=peer" json:"peer,omitempty"` + Reservation *Reservation `protobuf:"bytes,3,opt,name=reservation" json:"reservation,omitempty"` + Limit *Limit `protobuf:"bytes,4,opt,name=limit" json:"limit,omitempty"` + Status *Status `protobuf:"varint,5,opt,name=status,enum=circuit.pb.Status" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HopMessage) Reset() { *m = HopMessage{} } +func (m *HopMessage) String() string { return proto.CompactTextString(m) } +func (*HopMessage) ProtoMessage() {} +func (*HopMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{0} +} +func (m *HopMessage) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HopMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HopMessage.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *HopMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_HopMessage.Merge(m, src) +} +func (m *HopMessage) XXX_Size() int { + return m.Size() +} +func (m *HopMessage) XXX_DiscardUnknown() { + xxx_messageInfo_HopMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_HopMessage proto.InternalMessageInfo + +func (m *HopMessage) GetType() HopMessage_Type { + if m != nil && m.Type != nil { + return *m.Type + } + return HopMessage_RESERVE +} + +func (m *HopMessage) GetPeer() *Peer { + if m != nil { + return m.Peer + } + return nil +} + +func (m *HopMessage) GetReservation() *Reservation { + if m != nil { + return m.Reservation + } + return nil +} + +func (m *HopMessage) GetLimit() *Limit { + if m != nil { + return m.Limit + } + return nil +} + +func (m *HopMessage) GetStatus() Status { + if m != nil && m.Status != nil { + return *m.Status + } + return Status_OK +} + +type StopMessage struct { + Type *StopMessage_Type `protobuf:"varint,1,req,name=type,enum=circuit.pb.StopMessage_Type" json:"type,omitempty"` + Peer *Peer `protobuf:"bytes,2,opt,name=peer" json:"peer,omitempty"` + Limit *Limit `protobuf:"bytes,3,opt,name=limit" json:"limit,omitempty"` + Status *Status `protobuf:"varint,4,opt,name=status,enum=circuit.pb.Status" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StopMessage) Reset() { *m = StopMessage{} } +func (m *StopMessage) String() string { return proto.CompactTextString(m) } +func (*StopMessage) ProtoMessage() {} +func (*StopMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{1} +} +func (m *StopMessage) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StopMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StopMessage.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StopMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_StopMessage.Merge(m, src) +} +func (m *StopMessage) XXX_Size() int { + return m.Size() +} +func (m *StopMessage) XXX_DiscardUnknown() { + xxx_messageInfo_StopMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_StopMessage proto.InternalMessageInfo + +func (m *StopMessage) GetType() StopMessage_Type { + if m != nil && m.Type != nil { + return *m.Type + } + return StopMessage_CONNECT +} + +func (m *StopMessage) GetPeer() *Peer { + if m != nil { + return m.Peer + } + return nil +} + +func (m *StopMessage) GetLimit() *Limit { + if m != nil { + return m.Limit + } + return nil +} + +func (m *StopMessage) GetStatus() Status { + if m != nil && m.Status != nil { + return *m.Status + } + return Status_OK +} + +type Peer struct { + Id []byte `protobuf:"bytes,1,req,name=id" json:"id,omitempty"` + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Peer) Reset() { *m = Peer{} } +func (m *Peer) String() string { return proto.CompactTextString(m) } +func (*Peer) ProtoMessage() {} +func (*Peer) Descriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{2} +} +func (m *Peer) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Peer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Peer.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Peer) XXX_Merge(src proto.Message) { + xxx_messageInfo_Peer.Merge(m, src) +} +func (m *Peer) XXX_Size() int { + return m.Size() +} +func (m *Peer) XXX_DiscardUnknown() { + xxx_messageInfo_Peer.DiscardUnknown(m) +} + +var xxx_messageInfo_Peer proto.InternalMessageInfo + +func (m *Peer) GetId() []byte { + if m != nil { + return m.Id + } + return nil +} + +func (m *Peer) GetAddrs() [][]byte { + if m != nil { + return m.Addrs + } + return nil +} + +type Reservation struct { + Expire *uint64 `protobuf:"varint,1,opt,name=expire" json:"expire,omitempty"` + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` + Voucher []byte `protobuf:"bytes,3,opt,name=voucher" json:"voucher,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Reservation) Reset() { *m = Reservation{} } +func (m *Reservation) String() string { return proto.CompactTextString(m) } +func (*Reservation) ProtoMessage() {} +func (*Reservation) Descriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{3} +} +func (m *Reservation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Reservation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Reservation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Reservation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Reservation.Merge(m, src) +} +func (m *Reservation) XXX_Size() int { + return m.Size() +} +func (m *Reservation) XXX_DiscardUnknown() { + xxx_messageInfo_Reservation.DiscardUnknown(m) +} + +var xxx_messageInfo_Reservation proto.InternalMessageInfo + +func (m *Reservation) GetExpire() uint64 { + if m != nil && m.Expire != nil { + return *m.Expire + } + return 0 +} + +func (m *Reservation) GetAddrs() [][]byte { + if m != nil { + return m.Addrs + } + return nil +} + +func (m *Reservation) GetVoucher() []byte { + if m != nil { + return m.Voucher + } + return nil +} + +type Limit struct { + Duration *uint32 `protobuf:"varint,1,opt,name=duration" json:"duration,omitempty"` + Data *uint64 `protobuf:"varint,2,opt,name=data" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Limit) Reset() { *m = Limit{} } +func (m *Limit) String() string { return proto.CompactTextString(m) } +func (*Limit) ProtoMessage() {} +func (*Limit) Descriptor() ([]byte, []int) { + return fileDescriptor_ed01bbc211f15e47, []int{4} +} +func (m *Limit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Limit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Limit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Limit) XXX_Merge(src proto.Message) { + xxx_messageInfo_Limit.Merge(m, src) +} +func (m *Limit) XXX_Size() int { + return m.Size() +} +func (m *Limit) XXX_DiscardUnknown() { + xxx_messageInfo_Limit.DiscardUnknown(m) +} + +var xxx_messageInfo_Limit proto.InternalMessageInfo + +func (m *Limit) GetDuration() uint32 { + if m != nil && m.Duration != nil { + return *m.Duration + } + return 0 +} + +func (m *Limit) GetData() uint64 { + if m != nil && m.Data != nil { + return *m.Data + } + return 0 +} + +func init() { + proto.RegisterEnum("circuit.pb.Status", Status_name, Status_value) + proto.RegisterEnum("circuit.pb.HopMessage_Type", HopMessage_Type_name, HopMessage_Type_value) + proto.RegisterEnum("circuit.pb.StopMessage_Type", StopMessage_Type_name, StopMessage_Type_value) + proto.RegisterType((*HopMessage)(nil), "circuit.pb.HopMessage") + proto.RegisterType((*StopMessage)(nil), "circuit.pb.StopMessage") + proto.RegisterType((*Peer)(nil), "circuit.pb.Peer") + proto.RegisterType((*Reservation)(nil), "circuit.pb.Reservation") + proto.RegisterType((*Limit)(nil), "circuit.pb.Limit") +} + +func init() { proto.RegisterFile("circuit.proto", fileDescriptor_ed01bbc211f15e47) } + +var fileDescriptor_ed01bbc211f15e47 = []byte{ + // 516 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x92, 0xcf, 0x8a, 0xd3, 0x50, + 0x14, 0xc6, 0xe7, 0xa6, 0x69, 0x47, 0x4e, 0x3b, 0xe5, 0xce, 0x19, 0x99, 0x09, 0x3a, 0x8c, 0xa5, + 0x08, 0x96, 0x41, 0xaa, 0x74, 0x23, 0x2e, 0x6b, 0x73, 0xaa, 0xc1, 0x26, 0x29, 0xf7, 0xa6, 0x32, + 0xbb, 0x12, 0x9b, 0x8b, 0x06, 0xd4, 0x86, 0x24, 0x1d, 0x9c, 0xb7, 0xd0, 0x47, 0xf0, 0x45, 0x5c, + 0x8f, 0x7f, 0x16, 0xee, 0xdd, 0x48, 0x9f, 0x44, 0x72, 0xdb, 0x69, 0x33, 0x20, 0x28, 0xb8, 0xcb, + 0x77, 0xbf, 0xef, 0xe4, 0xe6, 0xf7, 0x9d, 0xc0, 0xde, 0x2c, 0x4e, 0x67, 0x8b, 0x38, 0xef, 0x26, + 0xe9, 0x3c, 0x9f, 0x23, 0x6c, 0xe4, 0xcb, 0xf6, 0x27, 0x03, 0xe0, 0xd9, 0x3c, 0x71, 0x55, 0x96, + 0x85, 0xaf, 0x14, 0x3e, 0x00, 0x33, 0xbf, 0x48, 0x94, 0xc5, 0x5a, 0x46, 0xa7, 0xd9, 0xbb, 0xdd, + 0xdd, 0x26, 0xbb, 0xdb, 0x54, 0x37, 0xb8, 0x48, 0x94, 0xd0, 0x41, 0xbc, 0x0b, 0x66, 0xa2, 0x54, + 0x6a, 0x19, 0x2d, 0xd6, 0xa9, 0xf7, 0x78, 0x79, 0x60, 0xac, 0x54, 0x2a, 0xb4, 0x8b, 0x8f, 0xa1, + 0x9e, 0xaa, 0x4c, 0xa5, 0xe7, 0x61, 0x1e, 0xcf, 0xdf, 0x59, 0x15, 0x1d, 0x3e, 0x2a, 0x87, 0xc5, + 0xd6, 0x16, 0xe5, 0x2c, 0xde, 0x83, 0xea, 0x9b, 0xf8, 0x6d, 0x9c, 0x5b, 0xa6, 0x1e, 0xda, 0x2f, + 0x0f, 0x8d, 0x0a, 0x43, 0xac, 0x7c, 0x3c, 0x85, 0x5a, 0x96, 0x87, 0xf9, 0x22, 0xb3, 0xaa, 0x2d, + 0xd6, 0x69, 0xf6, 0xb0, 0x9c, 0x94, 0xda, 0x11, 0xeb, 0x44, 0xfb, 0x3e, 0x98, 0x05, 0x03, 0xd6, + 0x61, 0x57, 0x90, 0x24, 0xf1, 0x82, 0xf8, 0x4e, 0x21, 0x06, 0xbe, 0xe7, 0xd1, 0x20, 0xe0, 0x0c, + 0x01, 0x6a, 0x32, 0xe8, 0x07, 0x13, 0xc9, 0x8d, 0xf6, 0x4f, 0x06, 0x75, 0x99, 0x6f, 0x4b, 0x7a, + 0x78, 0xad, 0xa4, 0xe3, 0xeb, 0xf7, 0xfc, 0x47, 0x4b, 0x1b, 0xd4, 0xca, 0x3f, 0xa3, 0x9a, 0x7f, + 0x45, 0xbd, 0xb3, 0x45, 0xbd, 0xa2, 0xdb, 0x29, 0xd1, 0xb1, 0xa2, 0x8b, 0xe2, 0x1b, 0xb0, 0x09, + 0x46, 0x1c, 0x69, 0xa6, 0x86, 0x30, 0xe2, 0x08, 0x6f, 0x42, 0x35, 0x8c, 0xa2, 0x34, 0xb3, 0x8c, + 0x56, 0xa5, 0xd3, 0x10, 0x2b, 0xd1, 0x9e, 0x40, 0xbd, 0xb4, 0x2a, 0x3c, 0x84, 0x9a, 0x7a, 0x9f, + 0xc4, 0x69, 0x51, 0x06, 0xeb, 0x98, 0x62, 0xad, 0xfe, 0x3c, 0x8c, 0x16, 0xec, 0x9e, 0xcf, 0x17, + 0xb3, 0xd7, 0x2a, 0xd5, 0x88, 0x0d, 0x71, 0x25, 0xdb, 0x8f, 0xa0, 0xaa, 0x09, 0xf1, 0x16, 0xdc, + 0x88, 0x16, 0xe9, 0xea, 0x37, 0x29, 0x5e, 0xb9, 0x27, 0x36, 0x1a, 0x11, 0xcc, 0x28, 0xcc, 0x43, + 0xdd, 0xa2, 0x29, 0xf4, 0xf3, 0xe9, 0x67, 0x06, 0xb5, 0x15, 0x31, 0xd6, 0xc0, 0xf0, 0x9f, 0xf3, + 0x08, 0x2d, 0x38, 0x58, 0x2d, 0xb5, 0x1f, 0x38, 0xbe, 0x37, 0x15, 0x34, 0x9c, 0x48, 0xb2, 0xf9, + 0x25, 0xc3, 0x63, 0x38, 0x12, 0x24, 0xfd, 0x89, 0x18, 0xd0, 0x74, 0xe4, 0xb8, 0x4e, 0x30, 0xa5, + 0xb3, 0x01, 0x91, 0x4d, 0x36, 0xff, 0xc2, 0xf0, 0x10, 0xf6, 0xc7, 0x24, 0x5c, 0x47, 0xca, 0x62, + 0xcc, 0x26, 0xcf, 0x21, 0x9b, 0x7f, 0xd5, 0xe7, 0xeb, 0xe6, 0x8a, 0xf3, 0x61, 0xdf, 0x19, 0x91, + 0xcd, 0xbf, 0x31, 0x3c, 0x80, 0xa6, 0xe7, 0x4f, 0x4b, 0x57, 0xf1, 0xef, 0x3a, 0xec, 0xf6, 0x47, + 0x43, 0x5f, 0xb8, 0x64, 0x4f, 0x5d, 0x92, 0xb2, 0xff, 0x94, 0xf8, 0x87, 0x0a, 0x1e, 0x01, 0x4e, + 0x3c, 0x3a, 0x1b, 0xd3, 0x20, 0x28, 0x19, 0x1f, 0x2b, 0x4f, 0x1a, 0x97, 0xcb, 0x13, 0xf6, 0x63, + 0x79, 0xc2, 0x7e, 0x2d, 0x4f, 0xd8, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa7, 0x24, 0x77, 0x69, + 0xaa, 0x03, 0x00, 0x00, +} + +func (m *HopMessage) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HopMessage) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HopMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Status != nil { + i = encodeVarintCircuit(dAtA, i, uint64(*m.Status)) + i-- + dAtA[i] = 0x28 + } + if m.Limit != nil { + { + size, err := m.Limit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCircuit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.Reservation != nil { + { + size, err := m.Reservation.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCircuit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Peer != nil { + { + size, err := m.Peer.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCircuit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Type == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("type") + } else { + i = encodeVarintCircuit(dAtA, i, uint64(*m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *StopMessage) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StopMessage) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StopMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Status != nil { + i = encodeVarintCircuit(dAtA, i, uint64(*m.Status)) + i-- + dAtA[i] = 0x20 + } + if m.Limit != nil { + { + size, err := m.Limit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCircuit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Peer != nil { + { + size, err := m.Peer.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCircuit(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Type == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("type") + } else { + i = encodeVarintCircuit(dAtA, i, uint64(*m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Peer) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Peer) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Peer) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Addrs) > 0 { + for iNdEx := len(m.Addrs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Addrs[iNdEx]) + copy(dAtA[i:], m.Addrs[iNdEx]) + i = encodeVarintCircuit(dAtA, i, uint64(len(m.Addrs[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Id == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("id") + } else { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintCircuit(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Reservation) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Reservation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Reservation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Voucher != nil { + i -= len(m.Voucher) + copy(dAtA[i:], m.Voucher) + i = encodeVarintCircuit(dAtA, i, uint64(len(m.Voucher))) + i-- + dAtA[i] = 0x1a + } + if len(m.Addrs) > 0 { + for iNdEx := len(m.Addrs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Addrs[iNdEx]) + copy(dAtA[i:], m.Addrs[iNdEx]) + i = encodeVarintCircuit(dAtA, i, uint64(len(m.Addrs[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Expire != nil { + i = encodeVarintCircuit(dAtA, i, uint64(*m.Expire)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Limit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Limit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Limit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Data != nil { + i = encodeVarintCircuit(dAtA, i, uint64(*m.Data)) + i-- + dAtA[i] = 0x10 + } + if m.Duration != nil { + i = encodeVarintCircuit(dAtA, i, uint64(*m.Duration)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintCircuit(dAtA []byte, offset int, v uint64) int { + offset -= sovCircuit(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *HopMessage) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != nil { + n += 1 + sovCircuit(uint64(*m.Type)) + } + if m.Peer != nil { + l = m.Peer.Size() + n += 1 + l + sovCircuit(uint64(l)) + } + if m.Reservation != nil { + l = m.Reservation.Size() + n += 1 + l + sovCircuit(uint64(l)) + } + if m.Limit != nil { + l = m.Limit.Size() + n += 1 + l + sovCircuit(uint64(l)) + } + if m.Status != nil { + n += 1 + sovCircuit(uint64(*m.Status)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *StopMessage) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != nil { + n += 1 + sovCircuit(uint64(*m.Type)) + } + if m.Peer != nil { + l = m.Peer.Size() + n += 1 + l + sovCircuit(uint64(l)) + } + if m.Limit != nil { + l = m.Limit.Size() + n += 1 + l + sovCircuit(uint64(l)) + } + if m.Status != nil { + n += 1 + sovCircuit(uint64(*m.Status)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Peer) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != nil { + l = len(m.Id) + n += 1 + l + sovCircuit(uint64(l)) + } + if len(m.Addrs) > 0 { + for _, b := range m.Addrs { + l = len(b) + n += 1 + l + sovCircuit(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Reservation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Expire != nil { + n += 1 + sovCircuit(uint64(*m.Expire)) + } + if len(m.Addrs) > 0 { + for _, b := range m.Addrs { + l = len(b) + n += 1 + l + sovCircuit(uint64(l)) + } + } + if m.Voucher != nil { + l = len(m.Voucher) + n += 1 + l + sovCircuit(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Limit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Duration != nil { + n += 1 + sovCircuit(uint64(*m.Duration)) + } + if m.Data != nil { + n += 1 + sovCircuit(uint64(*m.Data)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovCircuit(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCircuit(x uint64) (n int) { + return sovCircuit(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *HopMessage) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HopMessage: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HopMessage: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var v HopMessage_Type + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= HopMessage_Type(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Type = &v + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Peer", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Peer == nil { + m.Peer = &Peer{} + } + if err := m.Peer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reservation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Reservation == nil { + m.Reservation = &Reservation{} + } + if err := m.Reservation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Limit == nil { + m.Limit = &Limit{} + } + if err := m.Limit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var v Status + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= Status(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Status = &v + default: + iNdEx = preIndex + skippy, err := skipCircuit(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("type") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StopMessage) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StopMessage: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StopMessage: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var v StopMessage_Type + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= StopMessage_Type(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Type = &v + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Peer", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Peer == nil { + m.Peer = &Peer{} + } + if err := m.Peer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Limit == nil { + m.Limit = &Limit{} + } + if err := m.Limit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var v Status + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= Status(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Status = &v + default: + iNdEx = preIndex + skippy, err := skipCircuit(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("type") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Peer) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Peer: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Peer: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = append(m.Id[:0], dAtA[iNdEx:postIndex]...) + if m.Id == nil { + m.Id = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addrs", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addrs = append(m.Addrs, make([]byte, postIndex-iNdEx)) + copy(m.Addrs[len(m.Addrs)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCircuit(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("id") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Reservation) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Reservation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Reservation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Expire", wireType) + } + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Expire = &v + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addrs", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addrs = append(m.Addrs, make([]byte, postIndex-iNdEx)) + copy(m.Addrs[len(m.Addrs)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Voucher", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCircuit + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCircuit + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Voucher = append(m.Voucher[:0], dAtA[iNdEx:postIndex]...) + if m.Voucher == nil { + m.Voucher = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCircuit(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Limit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Limit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Limit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Duration", wireType) + } + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Duration = &v + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCircuit + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Data = &v + default: + iNdEx = preIndex + skippy, err := skipCircuit(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCircuit + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCircuit(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCircuit + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCircuit + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCircuit + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthCircuit + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCircuit + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCircuit + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCircuit = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCircuit = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCircuit = fmt.Errorf("proto: unexpected end of group") +) diff --git a/v2/pb/circuit.proto b/v2/pb/circuit.proto new file mode 100644 index 0000000..b73555c --- /dev/null +++ b/v2/pb/circuit.proto @@ -0,0 +1,60 @@ +syntax = "proto2"; + +package circuit.pb; + +message HopMessage { + enum Type { + RESERVE = 0; + CONNECT = 1; + STATUS = 2; + } + + required Type type = 1; + + optional Peer peer = 2; + optional Reservation reservation = 3; + optional Limit limit = 4; + + optional Status status = 5; +} + +message StopMessage { + enum Type { + CONNECT = 0; + STATUS = 1; + } + + required Type type = 1; + + optional Peer peer = 2; + optional Limit limit = 3; + + optional Status status = 4; +} + +message Peer { + required bytes id = 1; + repeated bytes addrs = 2; +} + +message Reservation { + optional uint64 expire = 1; // Unix expiration time (UTC) + repeated bytes addrs = 2; // relay addrs for reserving peer + optional bytes voucher = 3; // reservation voucher +} + +message Limit { + optional uint32 duration = 1; // seconds + optional uint64 data = 2; // bytes +} + +enum Status { + OK = 100; + RESERVATION_REFUSED = 200; + RESOURCE_LIMIT_EXCEEDED = 201; + PERMISSION_DENIED = 202; + CONNECTION_FAILED = 203; + NO_RESERVATION = 204; + MALFORMED_MESSAGE = 400; + UNEXPECTED_MESSAGE = 401; +} diff --git a/v2/pb/voucher.pb.go b/v2/pb/voucher.pb.go new file mode 100644 index 0000000..6fed008 --- /dev/null +++ b/v2/pb/voucher.pb.go @@ -0,0 +1,438 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: voucher.proto + +package circuit_pb + +import ( + fmt "fmt" + github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type ReservationVoucher struct { + Relay []byte `protobuf:"bytes,1,req,name=relay" json:"relay,omitempty"` + Peer []byte `protobuf:"bytes,2,req,name=peer" json:"peer,omitempty"` + Expiration *uint64 `protobuf:"varint,3,req,name=expiration" json:"expiration,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReservationVoucher) Reset() { *m = ReservationVoucher{} } +func (m *ReservationVoucher) String() string { return proto.CompactTextString(m) } +func (*ReservationVoucher) ProtoMessage() {} +func (*ReservationVoucher) Descriptor() ([]byte, []int) { + return fileDescriptor_a22a9b0d3335ba25, []int{0} +} +func (m *ReservationVoucher) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReservationVoucher) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReservationVoucher.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ReservationVoucher) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReservationVoucher.Merge(m, src) +} +func (m *ReservationVoucher) XXX_Size() int { + return m.Size() +} +func (m *ReservationVoucher) XXX_DiscardUnknown() { + xxx_messageInfo_ReservationVoucher.DiscardUnknown(m) +} + +var xxx_messageInfo_ReservationVoucher proto.InternalMessageInfo + +func (m *ReservationVoucher) GetRelay() []byte { + if m != nil { + return m.Relay + } + return nil +} + +func (m *ReservationVoucher) GetPeer() []byte { + if m != nil { + return m.Peer + } + return nil +} + +func (m *ReservationVoucher) GetExpiration() uint64 { + if m != nil && m.Expiration != nil { + return *m.Expiration + } + return 0 +} + +func init() { + proto.RegisterType((*ReservationVoucher)(nil), "circuit.pb.ReservationVoucher") +} + +func init() { proto.RegisterFile("voucher.proto", fileDescriptor_a22a9b0d3335ba25) } + +var fileDescriptor_a22a9b0d3335ba25 = []byte{ + // 135 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0xcb, 0x2f, 0x4d, + 0xce, 0x48, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4a, 0xce, 0x2c, 0x4a, 0x2e, + 0xcd, 0x2c, 0xd1, 0x2b, 0x48, 0x52, 0x8a, 0xe3, 0x12, 0x0a, 0x4a, 0x2d, 0x4e, 0x2d, 0x2a, 0x4b, + 0x2c, 0xc9, 0xcc, 0xcf, 0x0b, 0x83, 0xa8, 0x13, 0x12, 0xe1, 0x62, 0x2d, 0x4a, 0xcd, 0x49, 0xac, + 0x94, 0x60, 0x54, 0x60, 0xd2, 0xe0, 0x09, 0x82, 0x70, 0x84, 0x84, 0xb8, 0x58, 0x0a, 0x52, 0x53, + 0x8b, 0x24, 0x98, 0xc0, 0x82, 0x60, 0xb6, 0x90, 0x1c, 0x17, 0x57, 0x6a, 0x45, 0x41, 0x66, 0x11, + 0x58, 0xbb, 0x04, 0xb3, 0x02, 0x93, 0x06, 0x4b, 0x10, 0x92, 0x88, 0x13, 0xcf, 0x89, 0x47, 0x72, + 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x08, 0x08, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0x81, 0x3a, 0xee, 0x89, 0x00, 0x00, 0x00, +} + +func (m *ReservationVoucher) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ReservationVoucher) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReservationVoucher) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Expiration == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("expiration") + } else { + i = encodeVarintVoucher(dAtA, i, uint64(*m.Expiration)) + i-- + dAtA[i] = 0x18 + } + if m.Peer == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("peer") + } else { + i -= len(m.Peer) + copy(dAtA[i:], m.Peer) + i = encodeVarintVoucher(dAtA, i, uint64(len(m.Peer))) + i-- + dAtA[i] = 0x12 + } + if m.Relay == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("relay") + } else { + i -= len(m.Relay) + copy(dAtA[i:], m.Relay) + i = encodeVarintVoucher(dAtA, i, uint64(len(m.Relay))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintVoucher(dAtA []byte, offset int, v uint64) int { + offset -= sovVoucher(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ReservationVoucher) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Relay != nil { + l = len(m.Relay) + n += 1 + l + sovVoucher(uint64(l)) + } + if m.Peer != nil { + l = len(m.Peer) + n += 1 + l + sovVoucher(uint64(l)) + } + if m.Expiration != nil { + n += 1 + sovVoucher(uint64(*m.Expiration)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovVoucher(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozVoucher(x uint64) (n int) { + return sovVoucher(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ReservationVoucher) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVoucher + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReservationVoucher: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReservationVoucher: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Relay", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVoucher + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthVoucher + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthVoucher + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Relay = append(m.Relay[:0], dAtA[iNdEx:postIndex]...) + if m.Relay == nil { + m.Relay = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Peer", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVoucher + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthVoucher + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthVoucher + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Peer = append(m.Peer[:0], dAtA[iNdEx:postIndex]...) + if m.Peer == nil { + m.Peer = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000002) + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Expiration", wireType) + } + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVoucher + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Expiration = &v + hasFields[0] |= uint64(0x00000004) + default: + iNdEx = preIndex + skippy, err := skipVoucher(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthVoucher + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthVoucher + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("relay") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("peer") + } + if hasFields[0]&uint64(0x00000004) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("expiration") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipVoucher(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowVoucher + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowVoucher + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowVoucher + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthVoucher + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupVoucher + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthVoucher + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthVoucher = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowVoucher = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupVoucher = fmt.Errorf("proto: unexpected end of group") +) diff --git a/v2/pb/voucher.proto b/v2/pb/voucher.proto new file mode 100644 index 0000000..0864402 --- /dev/null +++ b/v2/pb/voucher.proto @@ -0,0 +1,9 @@ +syntax = "proto2"; + +package circuit.pb; + +message ReservationVoucher { + required bytes relay = 1; + required bytes peer = 2; + required uint64 expiration = 3; +} diff --git a/v2/proto/protocol.go b/v2/proto/protocol.go new file mode 100644 index 0000000..d27fc50 --- /dev/null +++ b/v2/proto/protocol.go @@ -0,0 +1,7 @@ +package proto + +const ( + ProtoIDv1 = "/libp2p/circuit/relay/0.1.0" + ProtoIDv2Hop = "/libp2p/circuit/relay/0.2.0/hop" + ProtoIDv2Stop = "/libp2p/circuit/relay/0.2.0/stop" +) diff --git a/v2/proto/voucher.go b/v2/proto/voucher.go new file mode 100644 index 0000000..76db111 --- /dev/null +++ b/v2/proto/voucher.go @@ -0,0 +1,72 @@ +package proto + +import ( + "time" + + pbv2 "github.com/libp2p/go-libp2p-circuit/v2/pb" + + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/record" +) + +const RecordDomain = "libp2p-relay-rsvp" + +// TODO: register in multicodec table in https://github.com/multiformats/multicodec +var RecordCodec = []byte{0x03, 0x02} + +func init() { + record.RegisterType(&ReservationVoucher{}) +} + +type ReservationVoucher struct { + // Relay is the ID of the peer providing relay service + Relay peer.ID + // Peer is the ID of the peer receiving relay service through Relay + Peer peer.ID + // Expiration is the expiration time of the reservation + Expiration time.Time +} + +var _ record.Record = (*ReservationVoucher)(nil) + +func (rv *ReservationVoucher) Domain() string { + return RecordDomain +} + +func (rv *ReservationVoucher) Codec() []byte { + return RecordCodec +} + +func (rv *ReservationVoucher) MarshalRecord() ([]byte, error) { + relay := []byte(rv.Relay) + peer := []byte(rv.Peer) + expiration := uint64(rv.Expiration.Unix()) + pbrv := &pbv2.ReservationVoucher{ + Relay: relay, + Peer: peer, + Expiration: &expiration, + } + + return pbrv.Marshal() +} + +func (rv *ReservationVoucher) UnmarshalRecord(blob []byte) error { + pbrv := pbv2.ReservationVoucher{} + err := pbrv.Unmarshal(blob) + if err != nil { + return err + } + + rv.Relay, err = peer.IDFromBytes(pbrv.GetRelay()) + if err != nil { + return err + } + + rv.Peer, err = peer.IDFromBytes(pbrv.GetPeer()) + if err != nil { + return err + } + + rv.Expiration = time.Unix(int64(pbrv.GetExpiration()), 0) + return nil +} diff --git a/v2/proto/voucher_test.go b/v2/proto/voucher_test.go new file mode 100644 index 0000000..148bd77 --- /dev/null +++ b/v2/proto/voucher_test.go @@ -0,0 +1,68 @@ +package proto + +import ( + "testing" + "time" + + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/record" +) + +func TestReservationVoucher(t *testing.T) { + relayPrivk, relayPubk, err := crypto.GenerateKeyPair(crypto.Ed25519, 0) + if err != nil { + t.Fatal(err) + } + + _, peerPubk, err := crypto.GenerateKeyPair(crypto.Ed25519, 0) + if err != nil { + t.Fatal(err) + } + + relayID, err := peer.IDFromPublicKey(relayPubk) + if err != nil { + t.Fatal(err) + } + + peerID, err := peer.IDFromPublicKey(peerPubk) + if err != nil { + t.Fatal(err) + } + + rsvp := &ReservationVoucher{ + Relay: relayID, + Peer: peerID, + Expiration: time.Now().Add(time.Hour), + } + + envelope, err := record.Seal(rsvp, relayPrivk) + if err != nil { + t.Fatal(err) + } + + blob, err := envelope.Marshal() + if err != nil { + t.Fatal(err) + } + + _, rec, err := record.ConsumeEnvelope(blob, RecordDomain) + if err != nil { + t.Fatal(err) + } + + rsvp2, ok := rec.(*ReservationVoucher) + if !ok { + t.Fatalf("invalid record type %+T", rec) + } + + if rsvp.Relay != rsvp2.Relay { + t.Fatal("relay IDs don't match") + } + if rsvp.Peer != rsvp2.Peer { + t.Fatal("peer IDs don't match") + } + if rsvp.Expiration.Unix() != rsvp2.Expiration.Unix() { + t.Fatal("expirations don't match") + } +} diff --git a/v2/relay/acl.go b/v2/relay/acl.go new file mode 100644 index 0000000..0501051 --- /dev/null +++ b/v2/relay/acl.go @@ -0,0 +1,17 @@ +package relay + +import ( + "github.com/libp2p/go-libp2p-core/peer" + + ma "github.com/multiformats/go-multiaddr" +) + +// ACLFilter is an Access Control mechanism for relayed connect. +type ACLFilter interface { + // AllowReserve returns true if a reservation from a peer with the given peer ID and multiaddr + // is allowed. + AllowReserve(p peer.ID, a ma.Multiaddr) bool + // AllowConnect returns true if a source peer, with a given multiaddr is allowed to connect + // to a destination peer. + AllowConnect(src peer.ID, srcAddr ma.Multiaddr, dest peer.ID) bool +} diff --git a/v2/relay/ipcs.go b/v2/relay/ipcs.go new file mode 100644 index 0000000..167e08e --- /dev/null +++ b/v2/relay/ipcs.go @@ -0,0 +1,110 @@ +package relay + +import ( + "errors" + "net" + + "github.com/libp2p/go-libp2p-core/peer" + + asnutil "github.com/libp2p/go-libp2p-asn-util" + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +var ( + ErrNoIP = errors.New("no IP address associated with peer") + ErrTooManyPeersInIP = errors.New("too many peers in IP address") + ErrTooManyPeersInASN = errors.New("too many peers in ASN") +) + +// IPConstraints implements reservation constraints per IP +type IPConstraints struct { + iplimit, asnlimit int + + peers map[peer.ID]net.IP + ips map[string]map[peer.ID]struct{} + asns map[string]map[peer.ID]struct{} +} + +// NewIPConstraints creates a new IPConstraints object. +// The methods are *not* thread-safe; an external lock must be held if synchronization +// is required. +func NewIPConstraints(rc Resources) *IPConstraints { + return &IPConstraints{ + iplimit: rc.MaxReservationsPerIP, + asnlimit: rc.MaxReservationsPerASN, + + peers: make(map[peer.ID]net.IP), + ips: make(map[string]map[peer.ID]struct{}), + asns: make(map[string]map[peer.ID]struct{}), + } +} + +// AddReservation adds a reservation for a given peer with a given multiaddr. +// If adding this reservation violates IP constraints, an error is returned. +func (ipcs *IPConstraints) AddReservation(p peer.ID, a ma.Multiaddr) error { + ip, err := manet.ToIP(a) + if err != nil { + return ErrNoIP + } + + ips := ip.String() + peersInIP := ipcs.ips[ips] + if len(peersInIP) >= ipcs.iplimit { + return ErrTooManyPeersInIP + } + + var peersInAsn map[peer.ID]struct{} + asn, _ := asnutil.Store.AsnForIPv6(ip) + peersInAsn = ipcs.asns[asn] + if len(peersInAsn) >= ipcs.asnlimit { + return ErrTooManyPeersInASN + } + + ipcs.peers[p] = ip + + if peersInIP == nil { + peersInIP = make(map[peer.ID]struct{}) + ipcs.ips[ips] = peersInIP + } + peersInIP[p] = struct{}{} + + if asn != "" { + if peersInAsn == nil { + peersInAsn = make(map[peer.ID]struct{}) + ipcs.asns[asn] = peersInAsn + } + peersInAsn[p] = struct{}{} + } + + return nil +} + +// RemoveReservation removes a peer from the constraints. +func (ipcs *IPConstraints) RemoveReservation(p peer.ID) { + ip, ok := ipcs.peers[p] + if !ok { + return + } + + ips := ip.String() + asn, _ := asnutil.Store.AsnForIPv6(ip) + + delete(ipcs.peers, p) + + peersInIP, ok := ipcs.ips[ips] + if ok { + delete(peersInIP, p) + if len(peersInIP) == 0 { + delete(ipcs.ips, ips) + } + } + + peersInAsn, ok := ipcs.asns[asn] + if ok { + delete(peersInAsn, p) + if len(peersInAsn) == 0 { + delete(ipcs.asns, asn) + } + } +} diff --git a/v2/relay/options.go b/v2/relay/options.go new file mode 100644 index 0000000..3464115 --- /dev/null +++ b/v2/relay/options.go @@ -0,0 +1,27 @@ +package relay + +type Option func(*Relay) error + +// WithResources is a Relay option that sets specific relay resources for the relay. +func WithResources(rc Resources) Option { + return func(r *Relay) error { + r.rc = rc + return nil + } +} + +// WithLimit is a Relay option that sets only the relayed connection limits for the relay. +func WithLimit(limit *RelayLimit) Option { + return func(r *Relay) error { + r.rc.Limit = limit + return nil + } +} + +// WithACL is a Relay option that supplies an ACLFilter for access control. +func WithACL(acl ACLFilter) Option { + return func(r *Relay) error { + r.acl = acl + return nil + } +} diff --git a/v2/relay/relay.go b/v2/relay/relay.go new file mode 100644 index 0000000..f1fa5ad --- /dev/null +++ b/v2/relay/relay.go @@ -0,0 +1,522 @@ +package relay + +import ( + "context" + "fmt" + "io" + "sync" + "sync/atomic" + "time" + + pbv2 "github.com/libp2p/go-libp2p-circuit/v2/pb" + "github.com/libp2p/go-libp2p-circuit/v2/proto" + "github.com/libp2p/go-libp2p-circuit/v2/util" + + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/record" + + logging "github.com/ipfs/go-log" + pool "github.com/libp2p/go-buffer-pool" + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +const ( + ReservationTagWeight = 10 + + StreamTimeout = time.Minute + ConnectTimeout = 30 * time.Second + HandshakeTimeout = time.Minute + + maxMessageSize = 4096 +) + +var log = logging.Logger("relay") + +// Relay is the (limited) relay service object. +type Relay struct { + closed uint32 + ctx context.Context + cancel func() + + host host.Host + rc Resources + acl ACLFilter + ipcs *IPConstraints + + mx sync.Mutex + rsvp map[peer.ID]time.Time + conns map[peer.ID]int + + selfAddr ma.Multiaddr +} + +// New constructs a new limited relay that can provide relay services in the given host. +func New(h host.Host, opts ...Option) (*Relay, error) { + ctx, cancel := context.WithCancel(context.Background()) + + r := &Relay{ + ctx: ctx, + cancel: cancel, + host: h, + rc: DefaultResources(), + acl: nil, + rsvp: make(map[peer.ID]time.Time), + conns: make(map[peer.ID]int), + } + + for _, opt := range opts { + err := opt(r) + if err != nil { + return nil, fmt.Errorf("error applying relay option: %w", err) + } + } + + r.ipcs = NewIPConstraints(r.rc) + r.selfAddr = ma.StringCast(fmt.Sprintf("/p2p/%s", h.ID())) + + h.SetStreamHandler(proto.ProtoIDv2Hop, r.handleStream) + h.Network().Notify( + &network.NotifyBundle{ + DisconnectedF: r.disconnected, + }) + go r.background() + + return r, nil +} + +func (r *Relay) Close() error { + if atomic.CompareAndSwapUint32(&r.closed, 0, 1) { + r.host.RemoveStreamHandler(proto.ProtoIDv2Hop) + r.cancel() + r.mx.Lock() + for p := range r.rsvp { + r.host.ConnManager().UntagPeer(p, "relay-reservation") + } + r.mx.Unlock() + } + return nil +} + +func (r *Relay) handleStream(s network.Stream) { + s.SetReadDeadline(time.Now().Add(StreamTimeout)) + + log.Infof("new relay stream from: %s", s.Conn().RemotePeer()) + + rd := util.NewDelimitedReader(s, maxMessageSize) + defer rd.Close() + + var msg pbv2.HopMessage + + err := rd.ReadMsg(&msg) + if err != nil { + r.handleError(s, pbv2.Status_MALFORMED_MESSAGE) + return + } + // reset stream deadline as message has been read + s.SetReadDeadline(time.Time{}) + + switch msg.GetType() { + case pbv2.HopMessage_RESERVE: + r.handleReserve(s, &msg) + + case pbv2.HopMessage_CONNECT: + r.handleConnect(s, &msg) + + default: + r.handleError(s, pbv2.Status_MALFORMED_MESSAGE) + } +} + +func (r *Relay) handleReserve(s network.Stream, msg *pbv2.HopMessage) { + defer s.Close() + + p := s.Conn().RemotePeer() + a := s.Conn().RemoteMultiaddr() + + if util.IsRelayAddr(a) { + log.Debugf("refusing relay reservation for %s; reservation attempt over relay connection") + r.handleError(s, pbv2.Status_PERMISSION_DENIED) + return + } + + if r.acl != nil && !r.acl.AllowReserve(p, a) { + log.Debugf("refusing relay reservation for %s; permission denied", p) + r.handleError(s, pbv2.Status_PERMISSION_DENIED) + return + } + + r.mx.Lock() + now := time.Now() + + _, exists := r.rsvp[p] + if !exists { + active := len(r.rsvp) + if active >= r.rc.MaxReservations { + r.mx.Unlock() + log.Debugf("refusing relay reservation for %s; too many reservations", p) + r.handleError(s, pbv2.Status_RESERVATION_REFUSED) + return + } + if err := r.ipcs.AddReservation(p, a); err != nil { + r.mx.Unlock() + log.Debugf("refusing relay reservation for %s; IP constraint violation: %s", p, err) + r.handleError(s, pbv2.Status_RESERVATION_REFUSED) + return + } + } + + expire := now.Add(r.rc.ReservationTTL) + r.rsvp[p] = expire + r.host.ConnManager().TagPeer(p, "relay-reservation", ReservationTagWeight) + r.mx.Unlock() + + log.Debugf("reserving relay slot for %s", p) + + err := r.writeResponse(s, pbv2.Status_OK, r.makeReservationMsg(p, expire), r.makeLimitMsg(p)) + if err != nil { + s.Reset() + log.Debugf("error writing reservation response; retracting reservation for %s", p) + r.mx.Lock() + delete(r.rsvp, p) + r.ipcs.RemoveReservation(p) + r.host.ConnManager().UntagPeer(p, "relay-reservation") + r.mx.Unlock() + } +} + +func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) { + src := s.Conn().RemotePeer() + a := s.Conn().RemoteMultiaddr() + + if util.IsRelayAddr(a) { + log.Debugf("refusing connection from %s; connection attempt over relay connection") + r.handleError(s, pbv2.Status_PERMISSION_DENIED) + return + } + + dest, err := util.PeerToPeerInfoV2(msg.GetPeer()) + if err != nil { + r.handleError(s, pbv2.Status_MALFORMED_MESSAGE) + return + } + + if r.acl != nil && !r.acl.AllowConnect(src, s.Conn().RemoteMultiaddr(), dest.ID) { + log.Debugf("refusing connection from %s to %s; permission denied", src, dest.ID) + r.handleError(s, pbv2.Status_PERMISSION_DENIED) + return + } + + r.mx.Lock() + _, rsvp := r.rsvp[dest.ID] + if !rsvp { + r.mx.Unlock() + log.Debugf("refusing connection from %s to %s; no reservation", src, dest.ID) + r.handleError(s, pbv2.Status_NO_RESERVATION) + return + } + + srcConns := r.conns[src] + if srcConns >= r.rc.MaxCircuits { + r.mx.Unlock() + log.Debugf("refusing connection from %s to %s; too many connections from %s", src, dest.ID, src) + r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return + } + r.conns[src]++ + + destConns := r.conns[dest.ID] + if destConns >= r.rc.MaxCircuits { + r.conns[src]-- + r.mx.Unlock() + log.Debugf("refusing connection from %s to %s; too many connecitons to %s", src, dest.ID, dest.ID) + r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED) + return + } + r.conns[dest.ID]++ + r.mx.Unlock() + + cleanup := func() { + r.mx.Lock() + r.conns[src]-- + r.conns[dest.ID]-- + r.mx.Unlock() + } + + ctx, cancel := context.WithTimeout(r.ctx, ConnectTimeout) + defer cancel() + + ctx = network.WithNoDial(ctx, "relay connect") + + bs, err := r.host.NewStream(ctx, dest.ID, proto.ProtoIDv2Stop) + if err != nil { + log.Debugf("error opening relay stream to %s: %s", dest.ID, err) + cleanup() + r.handleError(s, pbv2.Status_CONNECTION_FAILED) + return + } + + // handshake + rd := util.NewDelimitedReader(bs, maxMessageSize) + wr := util.NewDelimitedWriter(bs) + defer rd.Close() + + var stopmsg pbv2.StopMessage + stopmsg.Type = pbv2.StopMessage_CONNECT.Enum() + stopmsg.Peer = util.PeerInfoToPeerV2(peer.AddrInfo{ID: src}) + stopmsg.Limit = r.makeLimitMsg(dest.ID) + + bs.SetDeadline(time.Now().Add(HandshakeTimeout)) + + err = wr.WriteMsg(&stopmsg) + if err != nil { + log.Debugf("error writing stop handshake") + bs.Reset() + cleanup() + r.handleError(s, pbv2.Status_CONNECTION_FAILED) + return + } + + stopmsg.Reset() + + err = rd.ReadMsg(&stopmsg) + if err != nil { + log.Debugf("error reading stop response: %s", err.Error()) + bs.Reset() + cleanup() + r.handleError(s, pbv2.Status_CONNECTION_FAILED) + return + } + + if t := stopmsg.GetType(); t != pbv2.StopMessage_STATUS { + log.Debugf("unexpected stop response; not a status message (%d)", t) + bs.Reset() + cleanup() + r.handleError(s, pbv2.Status_CONNECTION_FAILED) + return + } + + if status := stopmsg.GetStatus(); status != pbv2.Status_OK { + log.Debugf("relay stop failure: %d", status) + bs.Reset() + cleanup() + r.handleError(s, pbv2.Status_CONNECTION_FAILED) + return + } + + var response pbv2.HopMessage + response.Type = pbv2.HopMessage_STATUS.Enum() + response.Status = pbv2.Status_OK.Enum() + response.Limit = r.makeLimitMsg(dest.ID) + + wr = util.NewDelimitedWriter(s) + err = wr.WriteMsg(&response) + if err != nil { + log.Debugf("error writing relay response: %s", err) + bs.Reset() + s.Reset() + cleanup() + return + } + + // reset deadline + bs.SetDeadline(time.Time{}) + + log.Infof("relaying connection from %s to %s", src, dest.ID) + + goroutines := new(int32) + *goroutines = 2 + + done := func() { + if atomic.AddInt32(goroutines, -1) == 0 { + s.Close() + bs.Close() + cleanup() + } + } + + if r.rc.Limit != nil { + deadline := time.Now().Add(r.rc.Limit.Duration) + s.SetDeadline(deadline) + bs.SetDeadline(deadline) + go r.relayLimited(s, bs, src, dest.ID, r.rc.Limit.Data, done) + go r.relayLimited(bs, s, dest.ID, src, r.rc.Limit.Data, done) + } else { + go r.relayUnlimited(s, bs, src, dest.ID, done) + go r.relayUnlimited(bs, s, dest.ID, src, done) + } +} + +func (r *Relay) relayLimited(src, dest network.Stream, srcID, destID peer.ID, limit int64, done func()) { + defer done() + + buf := pool.Get(r.rc.BufferSize) + defer pool.Put(buf) + + limitedSrc := io.LimitReader(src, limit) + + count, err := io.CopyBuffer(dest, limitedSrc, buf) + if err != nil { + log.Debugf("relay copy error: %s", err) + // Reset both. + src.Reset() + dest.Reset() + } else { + // propagate the close + dest.CloseWrite() + if count == limit { + // we've reached the limit, discard further input + src.CloseRead() + } + } + + log.Debugf("relayed %d bytes from %s to %s", count, srcID, destID) +} + +func (r *Relay) relayUnlimited(src, dest network.Stream, srcID, destID peer.ID, done func()) { + defer done() + + buf := pool.Get(r.rc.BufferSize) + defer pool.Put(buf) + + count, err := io.CopyBuffer(dest, src, buf) + if err != nil { + log.Debugf("relay copy error: %s", err) + // Reset both. + src.Reset() + dest.Reset() + } else { + // propagate the close + dest.CloseWrite() + } + + log.Debugf("relayed %d bytes from %s to %s", count, srcID, destID) +} + +func (r *Relay) handleError(s network.Stream, status pbv2.Status) { + log.Debugf("relay error: %s (%d)", pbv2.Status_name[int32(status)], status) + err := r.writeResponse(s, status, nil, nil) + if err != nil { + s.Reset() + log.Debugf("error writing relay response: %s", err.Error()) + } else { + s.Close() + } +} + +func (r *Relay) writeResponse(s network.Stream, status pbv2.Status, rsvp *pbv2.Reservation, limit *pbv2.Limit) error { + wr := util.NewDelimitedWriter(s) + + var msg pbv2.HopMessage + msg.Type = pbv2.HopMessage_STATUS.Enum() + msg.Status = status.Enum() + msg.Reservation = rsvp + msg.Limit = limit + + return wr.WriteMsg(&msg) +} + +func (r *Relay) makeReservationMsg(p peer.ID, expire time.Time) *pbv2.Reservation { + expireUnix := uint64(expire.Unix()) + + var addrBytes [][]byte + for _, addr := range r.host.Addrs() { + if !manet.IsPublicAddr(addr) { + continue + } + + addr = addr.Encapsulate(r.selfAddr) + addrBytes = append(addrBytes, addr.Bytes()) + } + + rsvp := &pbv2.Reservation{ + Expire: &expireUnix, + Addrs: addrBytes, + } + + voucher := &proto.ReservationVoucher{ + Relay: r.host.ID(), + Peer: p, + Expiration: expire, + } + + envelope, err := record.Seal(voucher, r.host.Peerstore().PrivKey(r.host.ID())) + if err != nil { + log.Errorf("error sealing voucher for %s: %s", p, err) + return rsvp + } + + blob, err := envelope.Marshal() + if err != nil { + log.Errorf("error marshalling voucher for %s: %s", p, err) + return rsvp + } + + rsvp.Voucher = blob + + return rsvp +} + +func (r *Relay) makeLimitMsg(p peer.ID) *pbv2.Limit { + if r.rc.Limit == nil { + return nil + } + + duration := uint32(r.rc.Limit.Duration / time.Second) + data := uint64(r.rc.Limit.Data) + + return &pbv2.Limit{ + Duration: &duration, + Data: &data, + } +} + +func (r *Relay) background() { + ticker := time.NewTicker(time.Minute) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + r.gc() + case <-r.ctx.Done(): + return + } + } +} + +func (r *Relay) gc() { + r.mx.Lock() + defer r.mx.Unlock() + + now := time.Now() + + for p, expire := range r.rsvp { + if expire.Before(now) { + delete(r.rsvp, p) + r.ipcs.RemoveReservation(p) + r.host.ConnManager().UntagPeer(p, "relay-reservation") + } + } + + for p, count := range r.conns { + if count == 0 { + delete(r.conns, p) + } + } +} + +func (r *Relay) disconnected(n network.Network, c network.Conn) { + p := c.RemotePeer() + if n.Connectedness(p) == network.Connected { + return + } + + r.mx.Lock() + defer r.mx.Unlock() + + delete(r.rsvp, p) + r.ipcs.RemoveReservation(p) +} diff --git a/v2/relay/resources.go b/v2/relay/resources.go new file mode 100644 index 0000000..345b527 --- /dev/null +++ b/v2/relay/resources.go @@ -0,0 +1,62 @@ +package relay + +import ( + "time" +) + +// Resources are the resource limits associated with the relay service. +type Resources struct { + // Limit is the (optional) relayed connection limits. + Limit *RelayLimit + + // ReservationTTL is the duration of a new (or refreshed reservation). + // Defaults to 1hr. + ReservationTTL time.Duration + + // MaxReservations is the maximum number of active relay slots; defaults to 128. + MaxReservations int + // MaxCircuits is the maximum number of open relay connections for each peer; defaults to 16. + MaxCircuits int + // BufferSize is the size of the relayed connection buffers; defaults to 2048. + BufferSize int + + // MaxReservationsPerIP is the maximum number of reservations originating from the same + // IP address; default is 4. + MaxReservationsPerIP int + // MaxReservationsPerASN is the maximum number of reservations origination from the same + // ASN; default is 32 + MaxReservationsPerASN int +} + +// RelayLimit are the per relayed connection resource limits. +type RelayLimit struct { + // Duration is the time limit before resetting a relayed connection; defaults to 2min. + Duration time.Duration + // Data is the limit of data relayed (on each direction) before resetting the connection. + // Defaults to 128KB + Data int64 +} + +// DefaultResources returns a Resources object with the default filled in. +func DefaultResources() Resources { + return Resources{ + Limit: DefaultLimit(), + + ReservationTTL: time.Hour, + + MaxReservations: 128, + MaxCircuits: 16, + BufferSize: 2048, + + MaxReservationsPerIP: 4, + MaxReservationsPerASN: 32, + } +} + +// DefaultLimit returns a RelayLimit object with the defaults filled in. +func DefaultLimit() *RelayLimit { + return &RelayLimit{ + Duration: 2 * time.Minute, + Data: 1 << 17, // 128K + } +} diff --git a/v2/test/compat_test.go b/v2/test/compat_test.go new file mode 100644 index 0000000..bcecba0 --- /dev/null +++ b/v2/test/compat_test.go @@ -0,0 +1,177 @@ +package test + +import ( + "bytes" + "context" + "fmt" + "io" + "testing" + + v1 "github.com/libp2p/go-libp2p-circuit" + + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + tptu "github.com/libp2p/go-libp2p-transport-upgrader" + ma "github.com/multiformats/go-multiaddr" +) + +func addTransportV1(t *testing.T, ctx context.Context, h host.Host, upgrader *tptu.Upgrader) { + err := v1.AddRelayTransport(ctx, h, upgrader) + if err != nil { + t.Fatal(err) + } +} + +func TestRelayCompatV2DialV1(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts, upgraders := getNetHosts(t, ctx, 3) + addTransportV1(t, ctx, hosts[0], upgraders[0]) + addTransport(t, ctx, hosts[2], upgraders[2]) + + rch := make(chan []byte, 1) + hosts[0].SetStreamHandler("test", func(s network.Stream) { + defer s.Close() + defer close(rch) + + buf := make([]byte, 1024) + nread := 0 + for nread < len(buf) { + n, err := s.Read(buf[nread:]) + nread += n + if err != nil { + if err == io.EOF { + break + } + t.Fatal(err) + } + } + + rch <- buf[:nread] + }) + + _, err := v1.NewRelay(ctx, hosts[1], upgraders[1], v1.OptHop) + if err != nil { + t.Fatal(err) + } + + connect(t, hosts[0], hosts[1]) + connect(t, hosts[1], hosts[2]) + + raddr, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s/p2p-circuit/p2p/%s", hosts[1].ID(), hosts[0].ID())) + if err != nil { + t.Fatal(err) + } + + err = hosts[2].Connect(ctx, peer.AddrInfo{ID: hosts[0].ID(), Addrs: []ma.Multiaddr{raddr}}) + if err != nil { + t.Fatal(err) + } + + conns := hosts[2].Network().ConnsToPeer(hosts[0].ID()) + if len(conns) != 1 { + t.Fatalf("expected 1 connection, but got %d", len(conns)) + } + if conns[0].Stat().Transient { + t.Fatal("expected non transient connection") + } + + s, err := hosts[2].NewStream(ctx, hosts[0].ID(), "test") + if err != nil { + t.Fatal(err) + } + + msg := []byte("relay works!") + nwritten, err := s.Write(msg) + if err != nil { + t.Fatal(err) + } + if nwritten != len(msg) { + t.Fatalf("expected to write %d bytes, but wrote %d instead", len(msg), nwritten) + } + s.CloseWrite() + + got := <-rch + if !bytes.Equal(msg, got) { + t.Fatalf("Wrong echo; expected %s but got %s", string(msg), string(got)) + } +} + +func TestRelayCompatV1DialV2(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts, upgraders := getNetHosts(t, ctx, 3) + addTransport(t, ctx, hosts[0], upgraders[0]) + addTransportV1(t, ctx, hosts[2], upgraders[2]) + + rch := make(chan []byte, 1) + hosts[0].SetStreamHandler("test", func(s network.Stream) { + defer s.Close() + defer close(rch) + + buf := make([]byte, 1024) + nread := 0 + for nread < len(buf) { + n, err := s.Read(buf[nread:]) + nread += n + if err != nil { + if err == io.EOF { + break + } + t.Fatal(err) + } + } + + rch <- buf[:nread] + }) + + _, err := v1.NewRelay(ctx, hosts[1], upgraders[1], v1.OptHop) + if err != nil { + t.Fatal(err) + } + + connect(t, hosts[0], hosts[1]) + connect(t, hosts[1], hosts[2]) + + raddr, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s/p2p-circuit/p2p/%s", hosts[1].ID(), hosts[0].ID())) + if err != nil { + t.Fatal(err) + } + + err = hosts[2].Connect(ctx, peer.AddrInfo{ID: hosts[0].ID(), Addrs: []ma.Multiaddr{raddr}}) + if err != nil { + t.Fatal(err) + } + + conns := hosts[2].Network().ConnsToPeer(hosts[0].ID()) + if len(conns) != 1 { + t.Fatalf("expected 1 connection, but got %d", len(conns)) + } + if conns[0].Stat().Transient { + t.Fatal("expected non transient connection") + } + + s, err := hosts[2].NewStream(ctx, hosts[0].ID(), "test") + if err != nil { + t.Fatal(err) + } + + msg := []byte("relay works!") + nwritten, err := s.Write(msg) + if err != nil { + t.Fatal(err) + } + if nwritten != len(msg) { + t.Fatalf("expected to write %d bytes, but wrote %d instead", len(msg), nwritten) + } + s.CloseWrite() + + got := <-rch + if !bytes.Equal(msg, got) { + t.Fatalf("Wrong echo; expected %s but got %s", string(msg), string(got)) + } +} diff --git a/v2/test/e2e_test.go b/v2/test/e2e_test.go new file mode 100644 index 0000000..7f640f5 --- /dev/null +++ b/v2/test/e2e_test.go @@ -0,0 +1,361 @@ +package test + +import ( + "bytes" + "context" + "fmt" + "io" + "math/rand" + "testing" + "time" + + "github.com/libp2p/go-libp2p-circuit/v2/client" + "github.com/libp2p/go-libp2p-circuit/v2/relay" + + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/mux" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + logging "github.com/ipfs/go-log" + bhost "github.com/libp2p/go-libp2p-blankhost" + metrics "github.com/libp2p/go-libp2p-core/metrics" + pstoremem "github.com/libp2p/go-libp2p-peerstore/pstoremem" + swarm "github.com/libp2p/go-libp2p-swarm" + swarmt "github.com/libp2p/go-libp2p-swarm/testing" + tptu "github.com/libp2p/go-libp2p-transport-upgrader" + tcp "github.com/libp2p/go-tcp-transport" + ma "github.com/multiformats/go-multiaddr" +) + +func init() { + // TODO temporary for debugging purposes; to be removed for merge. + logging.SetLogLevel("relay", "DEBUG") + logging.SetLogLevel("p2p-circuit", "DEBUG") +} + +func getNetHosts(t *testing.T, ctx context.Context, n int) (hosts []host.Host, upgraders []*tptu.Upgrader) { + for i := 0; i < n; i++ { + privk, pubk, err := crypto.GenerateKeyPair(crypto.Ed25519, 0) + if err != nil { + t.Fatal(err) + } + + p, err := peer.IDFromPublicKey(pubk) + if err != nil { + t.Fatal(err) + } + + ps := pstoremem.NewPeerstore() + err = ps.AddPrivKey(p, privk) + if err != nil { + t.Fatal(err) + } + + bwr := metrics.NewBandwidthCounter() + netw := swarm.NewSwarm(ctx, p, ps, bwr) + + upgrader := swarmt.GenUpgrader(netw) + upgraders = append(upgraders, upgrader) + + err = netw.AddTransport(tcp.NewTCPTransport(upgrader)) + if err != nil { + t.Fatal(err) + } + + err = netw.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")) + if err != nil { + t.Fatal(err) + } + + h := bhost.NewBlankHost(netw) + + hosts = append(hosts, h) + } + + return hosts, upgraders +} + +func connect(t *testing.T, a, b host.Host) { + pi := peer.AddrInfo{ID: a.ID(), Addrs: a.Addrs()} + err := b.Connect(context.Background(), pi) + if err != nil { + t.Fatal(err) + } +} + +func addTransport(t *testing.T, ctx context.Context, h host.Host, upgrader *tptu.Upgrader) { + err := client.AddTransport(ctx, h, upgrader) + if err != nil { + t.Fatal(err) + } +} + +func TestBasicRelay(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts, upgraders := getNetHosts(t, ctx, 3) + addTransport(t, ctx, hosts[0], upgraders[0]) + addTransport(t, ctx, hosts[2], upgraders[2]) + + rch := make(chan []byte, 1) + hosts[0].SetStreamHandler("test", func(s network.Stream) { + defer s.Close() + defer close(rch) + + buf := make([]byte, 1024) + nread := 0 + for nread < len(buf) { + n, err := s.Read(buf[nread:]) + nread += n + if err != nil { + if err == io.EOF { + break + } + t.Fatal(err) + } + } + + rch <- buf[:nread] + }) + + r, err := relay.New(hosts[1]) + if err != nil { + t.Fatal(err) + } + defer r.Close() + + connect(t, hosts[0], hosts[1]) + connect(t, hosts[1], hosts[2]) + + rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID()) + rsvp, err := client.Reserve(ctx, hosts[0], rinfo) + if err != nil { + t.Fatal(err) + } + + if rsvp.Voucher == nil { + t.Fatal("no reservation voucher") + } + + raddr, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s/p2p-circuit/p2p/%s", hosts[1].ID(), hosts[0].ID())) + if err != nil { + t.Fatal(err) + } + + err = hosts[2].Connect(ctx, peer.AddrInfo{ID: hosts[0].ID(), Addrs: []ma.Multiaddr{raddr}}) + if err != nil { + t.Fatal(err) + } + + conns := hosts[2].Network().ConnsToPeer(hosts[0].ID()) + if len(conns) != 1 { + t.Fatalf("expected 1 connection, but got %d", len(conns)) + } + if !conns[0].Stat().Transient { + t.Fatal("expected transient connection") + } + + s, err := hosts[2].NewStream(network.WithUseTransient(ctx, "test"), hosts[0].ID(), "test") + if err != nil { + t.Fatal(err) + } + + msg := []byte("relay works!") + nwritten, err := s.Write(msg) + if err != nil { + t.Fatal(err) + } + if nwritten != len(msg) { + t.Fatalf("expected to write %d bytes, but wrote %d instead", len(msg), nwritten) + } + s.CloseWrite() + + got := <-rch + if !bytes.Equal(msg, got) { + t.Fatalf("Wrong echo; expected %s but got %s", string(msg), string(got)) + } +} + +func TestRelayLimitTime(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts, upgraders := getNetHosts(t, ctx, 3) + addTransport(t, ctx, hosts[0], upgraders[0]) + addTransport(t, ctx, hosts[2], upgraders[2]) + + rch := make(chan error, 1) + hosts[0].SetStreamHandler("test", func(s network.Stream) { + defer s.Close() + defer close(rch) + + buf := make([]byte, 1024) + _, err := s.Read(buf) + rch <- err + }) + + rc := relay.DefaultResources() + rc.Limit.Duration = time.Second + + r, err := relay.New(hosts[1], relay.WithResources(rc)) + if err != nil { + t.Fatal(err) + } + defer r.Close() + + connect(t, hosts[0], hosts[1]) + connect(t, hosts[1], hosts[2]) + + rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID()) + _, err = client.Reserve(ctx, hosts[0], rinfo) + if err != nil { + t.Fatal(err) + } + + raddr, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s/p2p-circuit/p2p/%s", hosts[1].ID(), hosts[0].ID())) + if err != nil { + t.Fatal(err) + } + + err = hosts[2].Connect(ctx, peer.AddrInfo{ID: hosts[0].ID(), Addrs: []ma.Multiaddr{raddr}}) + if err != nil { + t.Fatal(err) + } + + conns := hosts[2].Network().ConnsToPeer(hosts[0].ID()) + if len(conns) != 1 { + t.Fatalf("expected 1 connection, but got %d", len(conns)) + } + if !conns[0].Stat().Transient { + t.Fatal("expected transient connection") + } + + s, err := hosts[2].NewStream(network.WithUseTransient(ctx, "test"), hosts[0].ID(), "test") + if err != nil { + t.Fatal(err) + } + + time.Sleep(2 * time.Second) + n, err := s.Write([]byte("should be closed")) + if n > 0 { + t.Fatalf("expected to write 0 bytes, wrote %d", n) + } + if err != mux.ErrReset { + t.Fatalf("expected reset, but got %s", err) + } + + err = <-rch + if err != mux.ErrReset { + t.Fatalf("expected reset, but got %s", err) + } +} + +func TestRelayLimitData(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts, upgraders := getNetHosts(t, ctx, 3) + addTransport(t, ctx, hosts[0], upgraders[0]) + addTransport(t, ctx, hosts[2], upgraders[2]) + + rch := make(chan int, 1) + hosts[0].SetStreamHandler("test", func(s network.Stream) { + defer s.Close() + defer close(rch) + + buf := make([]byte, 1024) + for i := 0; i < 3; i++ { + n, err := s.Read(buf) + if err != nil { + t.Fatal(err) + } + rch <- n + } + + n, err := s.Read(buf) + if err != mux.ErrReset { + t.Fatalf("expected reset but got %s", err) + } + rch <- n + }) + + rc := relay.DefaultResources() + rc.Limit.Duration = time.Second + rc.Limit.Data = 4096 + + r, err := relay.New(hosts[1], relay.WithResources(rc)) + if err != nil { + t.Fatal(err) + } + defer r.Close() + + connect(t, hosts[0], hosts[1]) + connect(t, hosts[1], hosts[2]) + + rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID()) + _, err = client.Reserve(ctx, hosts[0], rinfo) + if err != nil { + t.Fatal(err) + } + + raddr, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s/p2p-circuit/p2p/%s", hosts[1].ID(), hosts[0].ID())) + if err != nil { + t.Fatal(err) + } + + err = hosts[2].Connect(ctx, peer.AddrInfo{ID: hosts[0].ID(), Addrs: []ma.Multiaddr{raddr}}) + if err != nil { + t.Fatal(err) + } + + conns := hosts[2].Network().ConnsToPeer(hosts[0].ID()) + if len(conns) != 1 { + t.Fatalf("expected 1 connection, but got %d", len(conns)) + } + if !conns[0].Stat().Transient { + t.Fatal("expected transient connection") + } + + s, err := hosts[2].NewStream(network.WithUseTransient(ctx, "test"), hosts[0].ID(), "test") + if err != nil { + t.Fatal(err) + } + + buf := make([]byte, 1024) + for i := 0; i < 3; i++ { + _, err = rand.Read(buf) + if err != nil { + t.Fatal(err) + } + + n, err := s.Write(buf) + if err != nil { + t.Fatal(err) + } + if n != len(buf) { + t.Fatalf("expected to write %d bytes but wrote %d", len(buf), n) + } + + n = <-rch + if n != len(buf) { + t.Fatalf("expected to read %d bytes but read %d", len(buf), n) + } + } + + buf = make([]byte, 4096) + _, err = rand.Read(buf) + if err != nil { + t.Fatal(err) + } + + s.Write(buf) + + n := <-rch + if n != 0 { + t.Fatalf("expected to read 0 bytes but read %d", n) + } + +} diff --git a/v2/test/empty.go b/v2/test/empty.go new file mode 100644 index 0000000..56e5404 --- /dev/null +++ b/v2/test/empty.go @@ -0,0 +1 @@ +package test diff --git a/v2/test/ipcs_test.go b/v2/test/ipcs_test.go new file mode 100644 index 0000000..09a1a9b --- /dev/null +++ b/v2/test/ipcs_test.go @@ -0,0 +1,69 @@ +package test + +import ( + "fmt" + "net" + "testing" + + "github.com/libp2p/go-libp2p-circuit/v2/relay" + + "github.com/libp2p/go-libp2p-core/peer" + + ma "github.com/multiformats/go-multiaddr" +) + +func TestIPConstraints(t *testing.T) { + ipcs := relay.NewIPConstraints(relay.Resources{ + MaxReservationsPerIP: 1, + MaxReservationsPerASN: 2, + }) + + peerA := peer.ID("A") + peerB := peer.ID("B") + peerC := peer.ID("C") + peerD := peer.ID("D") + peerE := peer.ID("E") + + ipA := net.ParseIP("1.2.3.4") + ipB := ipA + ipC := net.ParseIP("2001:200::1") + ipD := net.ParseIP("2001:200::2") + ipE := net.ParseIP("2001:200::3") + + err := ipcs.AddReservation(peerA, ma.StringCast(fmt.Sprintf("/ip4/%s/tcp/1234", ipA))) + if err != nil { + t.Fatal(err) + } + + err = ipcs.AddReservation(peerB, ma.StringCast(fmt.Sprintf("/ip4/%s/tcp/1234", ipB))) + if err != relay.ErrTooManyPeersInIP { + t.Fatalf("unexpected error: %s", err) + } + + ipcs.RemoveReservation(peerA) + err = ipcs.AddReservation(peerB, ma.StringCast(fmt.Sprintf("/ip4/%s/tcp/1234", ipB))) + if err != nil { + t.Fatal(err) + } + + err = ipcs.AddReservation(peerC, ma.StringCast(fmt.Sprintf("/ip6/%s/tcp/1234", ipC))) + if err != nil { + t.Fatal(err) + } + + err = ipcs.AddReservation(peerD, ma.StringCast(fmt.Sprintf("/ip6/%s/tcp/1234", ipD))) + if err != nil { + t.Fatal(err) + } + + err = ipcs.AddReservation(peerE, ma.StringCast(fmt.Sprintf("/ip6/%s/tcp/1234", ipE))) + if err != relay.ErrTooManyPeersInASN { + t.Fatalf("unexpected error: %s", err) + } + + ipcs.RemoveReservation(peerD) + err = ipcs.AddReservation(peerE, ma.StringCast(fmt.Sprintf("/ip6/%s/tcp/1234", ipE))) + if err != nil { + t.Fatal(err) + } +} diff --git a/v2/util/io.go b/v2/util/io.go new file mode 100644 index 0000000..911bad1 --- /dev/null +++ b/v2/util/io.go @@ -0,0 +1,67 @@ +package util + +import ( + "errors" + "io" + + pool "github.com/libp2p/go-buffer-pool" + "github.com/libp2p/go-msgio/protoio" + + "github.com/gogo/protobuf/proto" + "github.com/multiformats/go-varint" +) + +type DelimitedReader struct { + r io.Reader + buf []byte +} + +// The gogo protobuf NewDelimitedReader is buffered, which may eat up stream data. +// So we need to implement a compatible delimited reader that reads unbuffered. +// There is a slowdown from unbuffered reading: when reading the message +// it can take multiple single byte Reads to read the length and another Read +// to read the message payload. +// However, this is not critical performance degradation as +// - the reader is utilized to read one (dialer, stop) or two messages (hop) during +// the handshake, so it's a drop in the water for the connection lifetime. +// - messages are small (max 4k) and the length fits in a couple of bytes, +// so overall we have at most three reads per message. +func NewDelimitedReader(r io.Reader, maxSize int) *DelimitedReader { + return &DelimitedReader{r: r, buf: pool.Get(maxSize)} +} + +func (d *DelimitedReader) Close() { + if d.buf != nil { + pool.Put(d.buf) + d.buf = nil + } +} + +func (d *DelimitedReader) ReadByte() (byte, error) { + buf := d.buf[:1] + _, err := d.r.Read(buf) + return buf[0], err +} + +func (d *DelimitedReader) ReadMsg(msg proto.Message) error { + mlen, err := varint.ReadUvarint(d) + if err != nil { + return err + } + + if uint64(len(d.buf)) < mlen { + return errors.New("message too large") + } + + buf := d.buf[:mlen] + _, err = io.ReadFull(d.r, buf) + if err != nil { + return err + } + + return proto.Unmarshal(buf, msg) +} + +func NewDelimitedWriter(w io.Writer) protoio.WriteCloser { + return protoio.NewDelimitedWriter(w) +} diff --git a/v2/util/ma.go b/v2/util/ma.go new file mode 100644 index 0000000..0dd820e --- /dev/null +++ b/v2/util/ma.go @@ -0,0 +1,10 @@ +package util + +import ( + ma "github.com/multiformats/go-multiaddr" +) + +func IsRelayAddr(a ma.Multiaddr) bool { + _, err := a.ValueForProtocol(ma.P_CIRCUIT) + return err == nil +} diff --git a/v2/util/pbconv.go b/v2/util/pbconv.go new file mode 100644 index 0000000..a5d7690 --- /dev/null +++ b/v2/util/pbconv.go @@ -0,0 +1,97 @@ +package util + +import ( + "errors" + + pbv1 "github.com/libp2p/go-libp2p-circuit/pb" + pbv2 "github.com/libp2p/go-libp2p-circuit/v2/pb" + + "github.com/libp2p/go-libp2p-core/peer" + + ma "github.com/multiformats/go-multiaddr" +) + +func PeerToPeerInfoV1(p *pbv1.CircuitRelay_Peer) (peer.AddrInfo, error) { + if p == nil { + return peer.AddrInfo{}, errors.New("nil peer") + } + + id, err := peer.IDFromBytes(p.Id) + if err != nil { + return peer.AddrInfo{}, err + } + + var addrs []ma.Multiaddr + if len(p.Addrs) > 0 { + addrs = make([]ma.Multiaddr, 0, len(p.Addrs)) + } + + for _, addrBytes := range p.Addrs { + a, err := ma.NewMultiaddrBytes(addrBytes) + if err == nil { + addrs = append(addrs, a) + } + } + + return peer.AddrInfo{ID: id, Addrs: addrs}, nil +} + +func PeerInfoToPeerV1(pi peer.AddrInfo) *pbv1.CircuitRelay_Peer { + var addrs [][]byte + if len(pi.Addrs) > 0 { + addrs = make([][]byte, 0, len(pi.Addrs)) + } + + for _, addr := range pi.Addrs { + addrs = append(addrs, addr.Bytes()) + } + + p := new(pbv1.CircuitRelay_Peer) + p.Id = []byte(pi.ID) + p.Addrs = addrs + + return p +} + +func PeerToPeerInfoV2(p *pbv2.Peer) (peer.AddrInfo, error) { + if p == nil { + return peer.AddrInfo{}, errors.New("nil peer") + } + + id, err := peer.IDFromBytes(p.Id) + if err != nil { + return peer.AddrInfo{}, err + } + + var addrs []ma.Multiaddr + if len(p.Addrs) > 0 { + addrs = make([]ma.Multiaddr, 0, len(p.Addrs)) + } + + for _, addrBytes := range p.Addrs { + a, err := ma.NewMultiaddrBytes(addrBytes) + if err == nil { + addrs = append(addrs, a) + } + } + + return peer.AddrInfo{ID: id, Addrs: addrs}, nil +} + +func PeerInfoToPeerV2(pi peer.AddrInfo) *pbv2.Peer { + var addrs [][]byte + + if len(pi.Addrs) > 0 { + addrs = make([][]byte, 0, len(pi.Addrs)) + } + + for _, addr := range pi.Addrs { + addrs = append(addrs, addr.Bytes()) + } + + p := new(pbv2.Peer) + p.Id = []byte(pi.ID) + p.Addrs = addrs + + return p +}