diff --git a/.circleci/config.yml b/.circleci/config.yml index 68d7e7266..f6cc134f0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: circleci/golang:1.11 + - image: circleci/golang:1.12 environment: GO111MODULE: "on" steps: diff --git a/.gx/lastpubver b/.gx/lastpubver deleted file mode 100644 index 92e2e3457..000000000 --- a/.gx/lastpubver +++ /dev/null @@ -1 +0,0 @@ -4.4.33: QmeGCQM8Zo66nwuQFnKzbKwGFgJBAcquVSL3KZMZw85T1L diff --git a/.travis.yml b/.travis.yml index e4b634737..ea3900d91 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,14 +4,13 @@ os: language: go go: - - 1.11.x + - 1.12.x env: global: - GOTFLAGS="-race" - IPFS_REUSEPORT=false matrix: - - BUILD_DEPTYPE=gx - BUILD_DEPTYPE=gomod @@ -25,7 +24,6 @@ script: cache: directories: - - $GOPATH/src/gx - $GOPATH/pkg/mod - /home/travis/.cache/go-build diff --git a/Makefile b/Makefile deleted file mode 100644 index b1b62d7cd..000000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -export IPFS_API ?= v04x.ipfs.io - -gx: - go get -u github.com/whyrusleeping/gx - go get -u github.com/whyrusleeping/gx-go - -deps: gx - gx --verbose install --global - gx-go rewrite - -publish: - gx-go rewrite --undo - -mod_deps: - env GO111MODULE=on go mod download diff --git a/README.md b/README.md index f27a49871..c774998a3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # go-libp2p-kad-dht -[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) -[![](https://img.shields.io/badge/project-libp2p-blue.svg?style=flat-square)](http://github.com/libp2p/libp2p) -[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) -[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai) +[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](https://libp2p.io) +[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23yellow) [![GoDoc](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht?status.svg)](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht) [![Build Status](https://travis-ci.org/libp2p/go-libp2p-kad-dht.svg?branch=master)](https://travis-ci.org/libp2p/go-libp2p-kad-dht) +[![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io) > A Kademlia DHT implementation on go-libp2p @@ -37,3 +37,7 @@ Small note: If editing the README, please conform to the [standard-readme](https ## License [MIT](LICENSE) © Protocol Labs Inc. + +--- + +The last gx published version of this module was: 4.4.34: QmXuNFLZc6Nb5akB4sZsxK3doShsFKT1sZFvxLXJvZQwAW diff --git a/dht.go b/dht.go index 0085a5ae4..da3c5cc33 100644 --- a/dht.go +++ b/dht.go @@ -4,11 +4,21 @@ import ( "bytes" "context" "errors" + "fmt" "sync" "time" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/protocol" + "github.com/libp2p/go-libp2p-core/routing" + + "go.opencensus.io/tag" "golang.org/x/xerrors" + "github.com/libp2p/go-libp2p-kad-dht/metrics" opts "github.com/libp2p/go-libp2p-kad-dht/opts" pb "github.com/libp2p/go-libp2p-kad-dht/pb" providers "github.com/libp2p/go-libp2p-kad-dht/providers" @@ -19,15 +29,9 @@ import ( logging "github.com/ipfs/go-log" goprocess "github.com/jbenet/goprocess" goprocessctx "github.com/jbenet/goprocess/context" - host "github.com/libp2p/go-libp2p-host" kb "github.com/libp2p/go-libp2p-kbucket" - inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" - pstore "github.com/libp2p/go-libp2p-peerstore" - protocol "github.com/libp2p/go-libp2p-protocol" record "github.com/libp2p/go-libp2p-record" recpb "github.com/libp2p/go-libp2p-record/pb" - routing "github.com/libp2p/go-libp2p-routing" base32 "github.com/whyrusleeping/base32" ) @@ -38,11 +42,11 @@ var logger = logging.Logger("dht") const NumBootstrapQueries = 5 // IpfsDHT is an implementation of Kademlia with S/Kademlia modifications. -// It is used to implement the base IpfsRouting module. +// It is used to implement the base Routing module. type IpfsDHT struct { - host host.Host // the network services we need - self peer.ID // Local peer (yourself) - peerstore pstore.Peerstore // Peer Registry + host host.Host // the network services we need + self peer.ID // Local peer (yourself) + peerstore peerstore.Peerstore // Peer Registry datastore ds.Datastore // Local data @@ -68,7 +72,7 @@ type IpfsDHT struct { // guarantee, but we can use them to aid refactoring. var ( _ routing.ContentRouting = (*IpfsDHT)(nil) - _ routing.IpfsRouting = (*IpfsDHT)(nil) + _ routing.Routing = (*IpfsDHT)(nil) _ routing.PeerRouting = (*IpfsDHT)(nil) _ routing.PubKeyFetcher = (*IpfsDHT)(nil) _ routing.ValueStore = (*IpfsDHT)(nil) @@ -136,7 +140,7 @@ func makeDHT(ctx context.Context, h host.Host, dstore ds.Batching, protocols []p cmgr.UntagPeer(p, "kbucket") } - return &IpfsDHT{ + dht := &IpfsDHT{ datastore: dstore, self: h.ID(), peerstore: h.Peerstore(), @@ -148,6 +152,10 @@ func makeDHT(ctx context.Context, h host.Host, dstore ds.Batching, protocols []p routingTable: rt, protocols: protocols, } + + dht.ctx = dht.newContextWithLocalTags(ctx) + + return dht } // putValueToPeer stores the given key/value pair at the peer 'p' @@ -175,7 +183,7 @@ var errInvalidRecord = errors.New("received invalid record") // key. It returns either the value or a list of closer peers. // NOTE: It will update the dht's peerstore with any new addresses // it finds for the given peer. -func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID, key string) (*recpb.Record, []*pstore.PeerInfo, error) { +func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID, key string) (*recpb.Record, []*peer.AddrInfo, error) { pmes, err := dht.getValueSingle(ctx, p, key) if err != nil { @@ -271,12 +279,12 @@ func (dht *IpfsDHT) Update(ctx context.Context, p peer.ID) { } // FindLocal looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in. -func (dht *IpfsDHT) FindLocal(id peer.ID) pstore.PeerInfo { +func (dht *IpfsDHT) FindLocal(id peer.ID) peer.AddrInfo { switch dht.host.Network().Connectedness(id) { - case inet.Connected, inet.CanConnect: + case network.Connected, network.CanConnect: return dht.peerstore.PeerInfo(id) default: - return pstore.PeerInfo{} + return peer.AddrInfo{} } } @@ -413,3 +421,19 @@ func (dht *IpfsDHT) Ping(ctx context.Context, p peer.ID) error { } return nil } + +// newContextWithLocalTags returns a new context.Context with the InstanceID and +// PeerID keys populated. It will also take any extra tags that need adding to +// the context as tag.Mutators. +func (dht *IpfsDHT) newContextWithLocalTags(ctx context.Context, extraTags ...tag.Mutator) context.Context { + extraTags = append( + extraTags, + tag.Upsert(metrics.KeyPeerID, dht.self.Pretty()), + tag.Upsert(metrics.KeyInstanceID, fmt.Sprintf("%p", dht)), + ) + ctx, _ = tag.New( + ctx, + extraTags..., + ) // ignoring error as it is unrelated to the actual function of this code. + return ctx +} diff --git a/dht_bootstrap.go b/dht_bootstrap.go index b70d81b17..0dd188482 100644 --- a/dht_bootstrap.go +++ b/dht_bootstrap.go @@ -6,11 +6,11 @@ import ( "fmt" "time" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/routing" + u "github.com/ipfs/go-ipfs-util" - peer "github.com/libp2p/go-libp2p-peer" - pstore "github.com/libp2p/go-libp2p-peerstore" - routing "github.com/libp2p/go-libp2p-routing" - multiaddr "github.com/multiformats/go-multiaddr" + "github.com/multiformats/go-multiaddr" _ "github.com/multiformats/go-multiaddr-dns" ) @@ -112,7 +112,7 @@ func newRandomPeerId() peer.ID { } // Traverse the DHT toward the given ID. -func (dht *IpfsDHT) walk(ctx context.Context, target peer.ID) (pstore.PeerInfo, error) { +func (dht *IpfsDHT) walk(ctx context.Context, target peer.ID) (peer.AddrInfo, error) { // TODO: Extract the query action (traversal logic?) inside FindPeer, // don't actually call through the FindPeer machinery, which can return // things out of the peer store etc. diff --git a/dht_net.go b/dht_net.go index b05f3b778..685b155be 100644 --- a/dht_net.go +++ b/dht_net.go @@ -8,21 +8,24 @@ import ( "sync" "time" - ggio "github.com/gogo/protobuf/io" - ctxio "github.com/jbenet/go-context/io" + "github.com/libp2p/go-libp2p-core/helpers" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + "github.com/libp2p/go-libp2p-kad-dht/metrics" pb "github.com/libp2p/go-libp2p-kad-dht/pb" - inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" + + ggio "github.com/gogo/protobuf/io" + + "github.com/libp2p/go-msgio" + "go.opencensus.io/stats" + "go.opencensus.io/tag" ) var dhtReadMessageTimeout = time.Minute +var dhtStreamIdleTimeout = 10 * time.Minute var ErrReadTimeout = fmt.Errorf("timed out reading response") -type bufferedWriteCloser interface { - ggio.WriteCloser - Flush() error -} - // The Protobuf writer performs multiple small writes when writing a message. // We need to buffer those writes, to make sure that we're not sending a new // packet for every single write. @@ -31,20 +34,34 @@ type bufferedDelimitedWriter struct { ggio.WriteCloser } -func newBufferedDelimitedWriter(str io.Writer) bufferedWriteCloser { - w := bufio.NewWriter(str) - return &bufferedDelimitedWriter{ - Writer: w, - WriteCloser: ggio.NewDelimitedWriter(w), +var writerPool = sync.Pool{ + New: func() interface{} { + w := bufio.NewWriter(nil) + return &bufferedDelimitedWriter{ + Writer: w, + WriteCloser: ggio.NewDelimitedWriter(w), + } + }, +} + +func writeMsg(w io.Writer, mes *pb.Message) error { + bw := writerPool.Get().(*bufferedDelimitedWriter) + bw.Reset(w) + err := bw.WriteMsg(mes) + if err == nil { + err = bw.Flush() } + bw.Reset(nil) + writerPool.Put(bw) + return err } func (w *bufferedDelimitedWriter) Flush() error { return w.Writer.Flush() } -// handleNewStream implements the inet.StreamHandler -func (dht *IpfsDHT) handleNewStream(s inet.Stream) { +// handleNewStream implements the network.StreamHandler +func (dht *IpfsDHT) handleNewStream(s network.Stream) { defer s.Reset() if dht.handleNewMessage(s) { // Gracefully close the stream for writes. @@ -53,37 +70,71 @@ func (dht *IpfsDHT) handleNewStream(s inet.Stream) { } // Returns true on orderly completion of writes (so we can Close the stream). -func (dht *IpfsDHT) handleNewMessage(s inet.Stream) bool { - ctx := dht.Context() - cr := ctxio.NewReader(ctx, s) // ok to use. we defer close stream in this func - cw := ctxio.NewWriter(ctx, s) // ok to use. we defer close stream in this func - r := ggio.NewDelimitedReader(cr, inet.MessageSizeMax) - w := newBufferedDelimitedWriter(cw) +func (dht *IpfsDHT) handleNewMessage(s network.Stream) bool { + ctx := dht.ctx + r := msgio.NewVarintReaderSize(s, network.MessageSizeMax) + mPeer := s.Conn().RemotePeer() + timer := time.AfterFunc(dhtStreamIdleTimeout, func() { s.Reset() }) + defer timer.Stop() + for { var req pb.Message - switch err := r.ReadMsg(&req); err { - case io.EOF: - return true - default: + msgbytes, err := r.ReadMsg() + if err != nil { + defer r.ReleaseMsg(msgbytes) + if err == io.EOF { + return true + } // This string test is necessary because there isn't a single stream reset error // instance in use. if err.Error() != "stream reset" { logger.Debugf("error reading message: %#v", err) } + stats.RecordWithTags( + ctx, + []tag.Mutator{tag.Upsert(metrics.KeyMessageType, "UNKNOWN")}, + metrics.ReceivedMessageErrors.M(1), + ) return false - case nil: } + err = req.Unmarshal(msgbytes) + r.ReleaseMsg(msgbytes) + if err != nil { + logger.Debugf("error unmarshalling message: %#v", err) + stats.RecordWithTags( + ctx, + []tag.Mutator{tag.Upsert(metrics.KeyMessageType, "UNKNOWN")}, + metrics.ReceivedMessageErrors.M(1), + ) + return false + } + + timer.Reset(dhtStreamIdleTimeout) + + startTime := time.Now() + ctx, _ = tag.New( + ctx, + tag.Upsert(metrics.KeyMessageType, req.GetType().String()), + ) + + stats.Record( + ctx, + metrics.ReceivedMessages.M(1), + metrics.ReceivedBytes.M(int64(req.Size())), + ) handler := dht.handlerForMsgType(req.GetType()) if handler == nil { + stats.Record(ctx, metrics.ReceivedMessageErrors.M(1)) logger.Warningf("can't handle received message of type %v", req.GetType()) return false } resp, err := handler(ctx, mPeer, &req) if err != nil { + stats.Record(ctx, metrics.ReceivedMessageErrors.M(1)) logger.Debugf("error handling message: %v", err) return false } @@ -95,24 +146,27 @@ func (dht *IpfsDHT) handleNewMessage(s inet.Stream) bool { } // send out response msg - err = w.WriteMsg(resp) - if err == nil { - err = w.Flush() - } + err = writeMsg(s, resp) if err != nil { + stats.Record(ctx, metrics.ReceivedMessageErrors.M(1)) logger.Debugf("error writing response: %v", err) return false } + elapsedTime := time.Since(startTime) + latencyMillis := float64(elapsedTime) / float64(time.Millisecond) + stats.Record(ctx, metrics.InboundRequestLatency.M(latencyMillis)) } } // sendRequest sends out a request, but also makes sure to // measure the RTT for latency measurements. func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) { + ctx, _ = tag.New(ctx, metrics.UpsertMessageType(pmes)) ms, err := dht.messageSenderForPeer(ctx, p) if err != nil { + stats.Record(ctx, metrics.SentRequestErrors.M(1)) return nil, err } @@ -120,12 +174,21 @@ func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message rpmes, err := ms.SendRequest(ctx, pmes) if err != nil { + stats.Record(ctx, metrics.SentRequestErrors.M(1)) return nil, err } // update the peer (on valid msgs only) dht.updateFromMessage(ctx, p, rpmes) + stats.Record( + ctx, + metrics.SentRequests.M(1), + metrics.SentBytes.M(int64(pmes.Size())), + metrics.OutboundRequestLatency.M( + float64(time.Since(start))/float64(time.Millisecond), + ), + ) dht.peerstore.RecordLatency(p, time.Since(start)) logger.Event(ctx, "dhtReceivedMessage", dht.self, p, rpmes) return rpmes, nil @@ -133,14 +196,24 @@ func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message // sendMessage sends out a message func (dht *IpfsDHT) sendMessage(ctx context.Context, p peer.ID, pmes *pb.Message) error { + ctx, _ = tag.New(ctx, metrics.UpsertMessageType(pmes)) + ms, err := dht.messageSenderForPeer(ctx, p) if err != nil { + stats.Record(ctx, metrics.SentMessageErrors.M(1)) return err } if err := ms.SendMessage(ctx, pmes); err != nil { + stats.Record(ctx, metrics.SentMessageErrors.M(1)) return err } + + stats.Record( + ctx, + metrics.SentMessages.M(1), + metrics.SentBytes.M(int64(pmes.Size())), + ) logger.Event(ctx, "dhtSentMessage", dht.self, p, pmes) return nil } @@ -187,9 +260,8 @@ func (dht *IpfsDHT) messageSenderForPeer(ctx context.Context, p peer.ID) (*messa } type messageSender struct { - s inet.Stream - r ggio.ReadCloser - w bufferedWriteCloser + s network.Stream + r msgio.ReadCloser lk sync.Mutex p peer.ID dht *IpfsDHT @@ -232,8 +304,7 @@ func (ms *messageSender) prep(ctx context.Context) error { return err } - ms.r = ggio.NewDelimitedReader(nstr, inet.MessageSizeMax) - ms.w = newBufferedDelimitedWriter(nstr) + ms.r = msgio.NewVarintReaderSize(nstr, network.MessageSizeMax) ms.s = nstr return nil @@ -260,17 +331,16 @@ func (ms *messageSender) SendMessage(ctx context.Context, pmes *pb.Message) erro if retry { logger.Info("error writing message, bailing: ", err) return err - } else { - logger.Info("error writing message, trying again: ", err) - retry = true - continue } + logger.Info("error writing message, trying again: ", err) + retry = true + continue } logger.Event(ctx, "dhtSentMessage", ms.dht.self, ms.p, pmes) if ms.singleMes > streamReuseTries { - go inet.FullClose(ms.s) + go helpers.FullClose(ms.s) ms.s = nil } else if retry { ms.singleMes++ @@ -296,11 +366,10 @@ func (ms *messageSender) SendRequest(ctx context.Context, pmes *pb.Message) (*pb if retry { logger.Info("error writing message, bailing: ", err) return nil, err - } else { - logger.Info("error writing message, trying again: ", err) - retry = true - continue } + logger.Info("error writing message, trying again: ", err) + retry = true + continue } mes := new(pb.Message) @@ -311,17 +380,16 @@ func (ms *messageSender) SendRequest(ctx context.Context, pmes *pb.Message) (*pb if retry { logger.Info("error reading message, bailing: ", err) return nil, err - } else { - logger.Info("error reading message, trying again: ", err) - retry = true - continue } + logger.Info("error reading message, trying again: ", err) + retry = true + continue } logger.Event(ctx, "dhtSentMessage", ms.dht.self, ms.p, pmes) if ms.singleMes > streamReuseTries { - go inet.FullClose(ms.s) + go helpers.FullClose(ms.s) ms.s = nil } else if retry { ms.singleMes++ @@ -332,16 +400,19 @@ func (ms *messageSender) SendRequest(ctx context.Context, pmes *pb.Message) (*pb } func (ms *messageSender) writeMsg(pmes *pb.Message) error { - if err := ms.w.WriteMsg(pmes); err != nil { - return err - } - return ms.w.Flush() + return writeMsg(ms.s, pmes) } func (ms *messageSender) ctxReadMsg(ctx context.Context, mes *pb.Message) error { errc := make(chan error, 1) - go func(r ggio.ReadCloser) { - errc <- r.ReadMsg(mes) + go func(r msgio.ReadCloser) { + bytes, err := r.ReadMsg() + defer r.ReleaseMsg(bytes) + if err != nil { + errc <- err + return + } + errc <- mes.Unmarshal(bytes) }(ms.r) t := time.NewTimer(dhtReadMessageTimeout) diff --git a/dht_test.go b/dht_test.go index d751c77a5..fc819067e 100644 --- a/dht_test.go +++ b/dht_test.go @@ -12,6 +12,10 @@ import ( "testing" "time" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/routing" + multistream "github.com/multiformats/go-multistream" "golang.org/x/xerrors" @@ -25,14 +29,11 @@ import ( cid "github.com/ipfs/go-cid" u "github.com/ipfs/go-ipfs-util" kb "github.com/libp2p/go-libp2p-kbucket" - peer "github.com/libp2p/go-libp2p-peer" - pstore "github.com/libp2p/go-libp2p-peerstore" record "github.com/libp2p/go-libp2p-record" - routing "github.com/libp2p/go-libp2p-routing" swarmt "github.com/libp2p/go-libp2p-swarm/testing" + ci "github.com/libp2p/go-libp2p-testing/ci" + travisci "github.com/libp2p/go-libp2p-testing/ci/travis" bhost "github.com/libp2p/go-libp2p/p2p/host/basic" - ci "github.com/libp2p/go-testutil/ci" - travisci "github.com/libp2p/go-testutil/ci/travis" ma "github.com/multiformats/go-multiaddr" ) @@ -127,8 +128,8 @@ func connectNoSync(t *testing.T, ctx context.Context, a, b *IpfsDHT) { t.Fatal("peers setup incorrectly: no local address") } - a.peerstore.AddAddrs(idB, addrB, pstore.TempAddrTTL) - pi := pstore.PeerInfo{ID: idB} + a.peerstore.AddAddrs(idB, addrB, peerstore.TempAddrTTL) + pi := peer.AddrInfo{ID: idB} if err := a.host.Connect(ctx, pi); err != nil { t.Fatal(err) } @@ -757,13 +758,13 @@ func TestProvidesMany(t *testing.T) { } } - providers := make(map[string]peer.ID) + providers := make(map[cid.Cid]peer.ID) d := 0 for _, c := range testCaseCids { d = (d + 1) % len(dhts) dht := dhts[d] - providers[c.KeyString()] = dht.self + providers[c] = dht.self t.Logf("announcing provider for %s", c) if err := dht.Provide(ctx, c, true); err != nil { @@ -783,7 +784,7 @@ func TestProvidesMany(t *testing.T) { getProvider := func(dht *IpfsDHT, k cid.Cid) { defer wg.Done() - expected := providers[k.KeyString()] + expected := providers[k] provchan := dht.FindProvidersAsync(ctxT, k, 1) select { @@ -1012,7 +1013,7 @@ func TestFindPeersConnectedToPeer(t *testing.T) { } // shouldFind := []peer.ID{peers[1], peers[3]} - var found []*pstore.PeerInfo + var found []*peer.AddrInfo for nextp := range pchan { found = append(found, nextp) } @@ -1056,14 +1057,14 @@ func TestConnectCollision(t *testing.T) { errs := make(chan error) go func() { - dhtA.peerstore.AddAddr(peerB, addrB, pstore.TempAddrTTL) - pi := pstore.PeerInfo{ID: peerB} + dhtA.peerstore.AddAddr(peerB, addrB, peerstore.TempAddrTTL) + pi := peer.AddrInfo{ID: peerB} err := dhtA.host.Connect(ctx, pi) errs <- err }() go func() { - dhtB.peerstore.AddAddr(peerA, addrA, pstore.TempAddrTTL) - pi := pstore.PeerInfo{ID: peerA} + dhtB.peerstore.AddAddr(peerA, addrA, peerstore.TempAddrTTL) + pi := peer.AddrInfo{ID: peerA} err := dhtB.host.Connect(ctx, pi) errs <- err }() @@ -1373,7 +1374,7 @@ func TestPing(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() ds := setupDHTS(t, ctx, 2) - ds[0].Host().Peerstore().AddAddrs(ds[1].PeerID(), ds[1].Host().Addrs(), pstore.AddressTTL) + ds[0].Host().Peerstore().AddAddrs(ds[1].PeerID(), ds[1].Host().Addrs(), peerstore.AddressTTL) assert.NoError(t, ds[0].Ping(context.Background(), ds[1].PeerID())) } @@ -1382,7 +1383,7 @@ func TestClientModeAtInit(t *testing.T) { defer cancel() pinger := setupDHT(ctx, t, false) client := setupDHT(ctx, t, true) - pinger.Host().Peerstore().AddAddrs(client.PeerID(), client.Host().Addrs(), pstore.AddressTTL) + pinger.Host().Peerstore().AddAddrs(client.PeerID(), client.Host().Addrs(), peerstore.AddressTTL) err := pinger.Ping(context.Background(), client.PeerID()) assert.True(t, xerrors.Is(err, multistream.ErrNotSupported)) } diff --git a/dial_queue.go b/dial_queue.go index 6635d8206..23bd352d1 100644 --- a/dial_queue.go +++ b/dial_queue.go @@ -6,7 +6,7 @@ import ( "sync" "time" - peer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-core/peer" queue "github.com/libp2p/go-libp2p-peerstore/queue" ) @@ -110,18 +110,13 @@ func newDialQueue(params *dqParams) (*dialQueue, error) { dieCh: make(chan struct{}, params.config.maxParallelism), } - go dq.control() return dq, nil } // Start initiates action on this dial queue. It should only be called once; subsequent calls are ignored. func (dq *dialQueue) Start() { dq.startOnce.Do(func() { - tgt := int(dq.dqParams.config.minParallelism) - for i := 0; i < tgt; i++ { - go dq.worker() - } - dq.nWorkers = uint(tgt) + go dq.control() }) } @@ -139,6 +134,16 @@ func (dq *dialQueue) control() { waiting = nil }() + // start workers + + tgt := int(dq.dqParams.config.minParallelism) + for i := 0; i < tgt; i++ { + go dq.worker() + } + dq.nWorkers = uint(tgt) + + // control workers + for { // First process any backlog of dial jobs and waiters -- making progress is the priority. // This block is copied below; couldn't find a more concise way of doing this. diff --git a/dial_queue_test.go b/dial_queue_test.go index ccc7b730a..e97bb9519 100644 --- a/dial_queue_test.go +++ b/dial_queue_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - peer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-core/peer" queue "github.com/libp2p/go-libp2p-peerstore/queue" ) diff --git a/ext_test.go b/ext_test.go index 1612d9802..cb0ac7634 100644 --- a/ext_test.go +++ b/ext_test.go @@ -6,13 +6,14 @@ import ( "testing" "time" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/routing" + ggio "github.com/gogo/protobuf/io" u "github.com/ipfs/go-ipfs-util" pb "github.com/libp2p/go-libp2p-kad-dht/pb" - inet "github.com/libp2p/go-libp2p-net" - pstore "github.com/libp2p/go-libp2p-peerstore" record "github.com/libp2p/go-libp2p-record" - routing "github.com/libp2p/go-libp2p-routing" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" ) @@ -35,7 +36,7 @@ func TestGetFailures(t *testing.T) { d.Update(ctx, hosts[1].ID()) // Reply with failures to every message - hosts[1].SetStreamHandler(d.protocols[0], func(s inet.Stream) { + hosts[1].SetStreamHandler(d.protocols[0], func(s network.Stream) { time.Sleep(400 * time.Millisecond) s.Close() }) @@ -58,10 +59,10 @@ func TestGetFailures(t *testing.T) { t.Log("Timeout test passed.") // Reply with failures to every message - hosts[1].SetStreamHandler(d.protocols[0], func(s inet.Stream) { + hosts[1].SetStreamHandler(d.protocols[0], func(s network.Stream) { defer s.Close() - pbr := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + pbr := ggio.NewDelimitedReader(s, network.MessageSizeMax) pbw := ggio.NewDelimitedWriter(s) pmes := new(pb.Message) @@ -116,7 +117,7 @@ func TestGetFailures(t *testing.T) { } defer s.Close() - pbr := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + pbr := ggio.NewDelimitedReader(s, network.MessageSizeMax) pbw := ggio.NewDelimitedWriter(s) if err := pbw.WriteMsg(&req); err != nil { @@ -160,10 +161,10 @@ func TestNotFound(t *testing.T) { // Reply with random peers to every message for _, host := range hosts { host := host // shadow loop var - host.SetStreamHandler(d.protocols[0], func(s inet.Stream) { + host.SetStreamHandler(d.protocols[0], func(s network.Stream) { defer s.Close() - pbr := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + pbr := ggio.NewDelimitedReader(s, network.MessageSizeMax) pbw := ggio.NewDelimitedWriter(s) pmes := new(pb.Message) @@ -175,7 +176,7 @@ func TestNotFound(t *testing.T) { case pb.Message_GET_VALUE: resp := &pb.Message{Type: pmes.Type} - ps := []pstore.PeerInfo{} + ps := []peer.AddrInfo{} for i := 0; i < 7; i++ { p := hosts[rand.Intn(len(hosts))].ID() pi := host.Peerstore().PeerInfo(p) @@ -239,10 +240,10 @@ func TestLessThanKResponses(t *testing.T) { // Reply with random peers to every message for _, host := range hosts { host := host // shadow loop var - host.SetStreamHandler(d.protocols[0], func(s inet.Stream) { + host.SetStreamHandler(d.protocols[0], func(s network.Stream) { defer s.Close() - pbr := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + pbr := ggio.NewDelimitedReader(s, network.MessageSizeMax) pbw := ggio.NewDelimitedWriter(s) pmes := new(pb.Message) @@ -255,7 +256,7 @@ func TestLessThanKResponses(t *testing.T) { pi := host.Peerstore().PeerInfo(hosts[1].ID()) resp := &pb.Message{ Type: pmes.Type, - CloserPeers: pb.PeerInfosToPBPeers(d.host.Network(), []pstore.PeerInfo{pi}), + CloserPeers: pb.PeerInfosToPBPeers(d.host.Network(), []peer.AddrInfo{pi}), } if err := pbw.WriteMsg(resp); err != nil { @@ -305,10 +306,10 @@ func TestMultipleQueries(t *testing.T) { // It would be nice to be able to just get a value and succeed but then // we'd need to deal with selectors and validators... - hosts[1].SetStreamHandler(d.protocols[0], func(s inet.Stream) { + hosts[1].SetStreamHandler(d.protocols[0], func(s network.Stream) { defer s.Close() - pbr := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + pbr := ggio.NewDelimitedReader(s, network.MessageSizeMax) pbw := ggio.NewDelimitedWriter(s) pmes := new(pb.Message) @@ -321,7 +322,7 @@ func TestMultipleQueries(t *testing.T) { pi := hosts[1].Peerstore().PeerInfo(hosts[0].ID()) resp := &pb.Message{ Type: pmes.Type, - CloserPeers: pb.PeerInfosToPBPeers(d.host.Network(), []pstore.PeerInfo{pi}), + CloserPeers: pb.PeerInfosToPBPeers(d.host.Network(), []peer.AddrInfo{pi}), } if err := pbw.WriteMsg(resp); err != nil { diff --git a/go.mod b/go.mod index 4735dc393..a266cdf30 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,29 @@ -module github.com/libp2p/go-libp2p-kad-dht +module github.com/aarshkshah1992/go-libp2p-kad-dht require ( github.com/gogo/protobuf v1.2.1 github.com/hashicorp/golang-lru v0.5.1 - github.com/ipfs/go-cid v0.0.1 - github.com/ipfs/go-datastore v0.0.1 + github.com/ipfs/go-cid v0.0.2 + github.com/ipfs/go-datastore v0.0.5 github.com/ipfs/go-ipfs-util v0.0.1 github.com/ipfs/go-log v0.0.1 github.com/ipfs/go-todocounter v0.0.1 - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 - github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 - github.com/libp2p/go-libp2p v0.0.2 - github.com/libp2p/go-libp2p-crypto v0.0.1 - github.com/libp2p/go-libp2p-host v0.0.1 - github.com/libp2p/go-libp2p-kbucket v0.0.1 - github.com/libp2p/go-libp2p-net v0.0.1 - github.com/libp2p/go-libp2p-peer v0.0.1 - github.com/libp2p/go-libp2p-peerstore v0.0.1 - github.com/libp2p/go-libp2p-protocol v0.0.1 - github.com/libp2p/go-libp2p-record v0.0.1 - github.com/libp2p/go-libp2p-routing v0.0.1 - github.com/libp2p/go-libp2p-swarm v0.0.1 - github.com/libp2p/go-testutil v0.0.1 - github.com/mr-tron/base58 v1.1.0 - github.com/multiformats/go-multiaddr v0.0.1 + github.com/jbenet/goprocess v0.1.3 + github.com/libp2p/go-libp2p v0.1.0 + github.com/libp2p/go-libp2p-core v0.0.1 + github.com/libp2p/go-libp2p-kbucket v0.2.0 + github.com/libp2p/go-libp2p-peerstore v0.1.0 + github.com/libp2p/go-libp2p-record v0.1.0 + github.com/libp2p/go-libp2p-routing v0.1.0 + github.com/libp2p/go-libp2p-swarm v0.1.0 + github.com/libp2p/go-libp2p-testing v0.0.3 + github.com/libp2p/go-msgio v0.0.4 + github.com/mr-tron/base58 v1.1.2 + github.com/multiformats/go-multiaddr v0.0.4 github.com/multiformats/go-multiaddr-dns v0.0.2 - github.com/multiformats/go-multistream v0.0.1 + github.com/multiformats/go-multistream v0.1.0 github.com/stretchr/testify v1.3.0 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc - golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3 + go.opencensus.io v0.21.0 + golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522 ) diff --git a/go.sum b/go.sum index 914d2bd84..bd8387422 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 h1:qkOC5Gd33k54tobS36cXdAzJbeHaduLtnLQQwNoIi78= @@ -10,26 +12,29 @@ 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/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/fd/go-nat v1.0.0 h1:DPyQ97sxA9ThrWYRPcWUz/z9TnpTIGRYODIQc/dy64M= -github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= @@ -38,16 +43,22 @@ github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyF github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= 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= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324 h1:PV190X5/DzQ/tbFFG5YpT5mH6q+cHlfgqI5JuRnH9oE= -github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-datastore v0.0.1 h1:AW/KZCScnBWlSb5JbnEnLKFWXL224LBEh/9KXXOrUms= github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5 h1:q3OfiOZV5rlsK1H5V8benjeUApRfMGs4Mrhmr6NriQo= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= @@ -59,23 +70,27 @@ github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-todocounter v0.0.1 h1:kITWA5ZcQZfrUnDNkRn04Xzh0YFaDFXsoO2A81Eb6Lw= github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= -github.com/jackpal/gateway v1.0.4 h1:LS5EHkLuQ6jzaHwULi0vL+JO0mU/n4yUtK8oUjHHOlM= -github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec h1:DQqZhhDvrTrEQ3Qod5yfavcA064e53xlQ+xajiorXgM= github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +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 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A= github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -85,121 +100,139 @@ github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDE github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-buffer-pool v0.0.1 h1:9Rrn/H46cXjaA2HQ5Y8lyhOS1NhTkZ4yuEs2r3Eechg= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-conn-security v0.0.1 h1:4kMMrqrt9EUNCNjX1xagSJC+bq16uqjMe9lk1KBMVNs= -github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= -github.com/libp2p/go-conn-security-multistream v0.0.1 h1:XefjAQRHcnUaxKb26RGupToucx3uU4ecbOZ3aACXlDU= -github.com/libp2p/go-conn-security-multistream v0.0.1/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= +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.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s= github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-libp2p v0.0.1 h1:oEjzhRzymY7NILTMzOKNVOpNZGpcQHrHriWw91pbJNM= -github.com/libp2p/go-libp2p v0.0.1/go.mod h1:bmRs8I0vwn6iRaVssZnJx/epY6WPSKiLoK1vyle4EX0= -github.com/libp2p/go-libp2p v0.0.2 h1:+jvgi0Zy3y4TKXJKApchCk3pCBPZf1T54z3+vKie3gw= -github.com/libp2p/go-libp2p v0.0.2/go.mod h1:Qu8bWqFXiocPloabFGUcVG4kk94fLvfC8mWTDdFC9wE= -github.com/libp2p/go-libp2p-autonat v0.0.1/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= -github.com/libp2p/go-libp2p-autonat v0.0.2 h1:ilo9QPzNPf1hMkqaPG55yzvhILf5ZtijstJhcii+l3s= -github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= -github.com/libp2p/go-libp2p-blankhost v0.0.1 h1:/mZuuiwntNR8RywnCFlGHLKrKLYne+qciBpQXWqp5fk= -github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= -github.com/libp2p/go-libp2p-circuit v0.0.1 h1:DYbjyQ5ZY3QVAVYZWG4uzBQ6Wmcd1C82Bk8Q/pJlM1I= -github.com/libp2p/go-libp2p-circuit v0.0.1/go.mod h1:Dqm0s/BiV63j8EEAs8hr1H5HudqvCAeXxDyic59lCwE= -github.com/libp2p/go-libp2p-crypto v0.0.1 h1:JNQd8CmoGTohO/akqrH16ewsqZpci2CbgYH/LmYl8gw= -github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= -github.com/libp2p/go-libp2p-discovery v0.0.1 h1:VkjCKmJQMwpDUwtA8Qc1z3TQAHJgQ5nGQ6cdN0wQXOw= -github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI= -github.com/libp2p/go-libp2p-host v0.0.1 h1:dnqusU+DheGcdxrE718kG4XgHNuL2n9eEv8Rg5zy8hQ= -github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= -github.com/libp2p/go-libp2p-interface-connmgr v0.0.1 h1:Q9EkNSLAOF+u90L88qmE9z/fTdjLh8OsJwGw74mkwk4= -github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= -github.com/libp2p/go-libp2p-interface-pnet v0.0.1 h1:7GnzRrBTJHEsofi1ahFdPN9Si6skwXQE9UqR2S+Pkh8= -github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= -github.com/libp2p/go-libp2p-kbucket v0.0.1 h1:7H5hM851hkEpLOFjrVNSrrxo6J4bWrUQxxv+z1JW9xk= -github.com/libp2p/go-libp2p-kbucket v0.0.1/go.mod h1:Y0iQDHRTk/ZgM8PC4jExoF+E4j+yXWwRkdldkMa5Xm4= -github.com/libp2p/go-libp2p-loggables v0.0.1 h1:HVww9oAnINIxbt69LJNkxD8lnbfgteXR97Xm4p3l9ps= -github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= -github.com/libp2p/go-libp2p-metrics v0.0.1 h1:yumdPC/P2VzINdmcKZd0pciSUCpou+s0lwYCjBbzQZU= -github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= -github.com/libp2p/go-libp2p-nat v0.0.1 h1:on/zju7XE+JXc8gH+vTKmIh2UJFC1K8kGnJYluQrlz4= -github.com/libp2p/go-libp2p-nat v0.0.1/go.mod h1:4L6ajyUIlJvx1Cbh5pc6Ma6vMDpKXf3GgLO5u7W0oQ4= -github.com/libp2p/go-libp2p-nat v0.0.2 h1:sKI5hiCsGFhuEKdXMsF9mywQu2qhfoIGX6a+VG6zelE= -github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ= -github.com/libp2p/go-libp2p-net v0.0.1 h1:xJ4Vh4yKF/XKb8fd1Ev0ebAGzVjMxXzrxG2kjtU+F5Q= -github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= -github.com/libp2p/go-libp2p-netutil v0.0.1 h1:LgD6+skofkOx8z6odD9+MZHKjupv3ng1u6KRhaADTnA= -github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= -github.com/libp2p/go-libp2p-peer v0.0.1 h1:0qwAOljzYewINrU+Kndoc+1jAL7vzY/oY2Go4DCGfyY= -github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= -github.com/libp2p/go-libp2p-peerstore v0.0.1 h1:twKovq8YK5trLrd3nB7PD2Zu9JcyAIdm7Bz9yBWjhq8= -github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= -github.com/libp2p/go-libp2p-protocol v0.0.1 h1:+zkEmZ2yFDi5adpVE3t9dqh/N9TbpFWywowzeEzBbLM= -github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= -github.com/libp2p/go-libp2p-record v0.0.1 h1:zN7AS3X46qmwsw5JLxdDuI43cH5UYwovKxHPjKBYQxw= -github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= -github.com/libp2p/go-libp2p-routing v0.0.1 h1:hPMAWktf9rYi3ME4MG48qE7dq1ofJxiQbfdvpNntjhc= -github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= -github.com/libp2p/go-libp2p-secio v0.0.1 h1:CqE/RdsizOwItdgLe632iyft/w0tshDLmZGAiKDcUAI= -github.com/libp2p/go-libp2p-secio v0.0.1/go.mod h1:IdG6iQybdcYmbTzxp4J5dwtUEDTOvZrT0opIDVNPrJs= -github.com/libp2p/go-libp2p-swarm v0.0.1 h1:Vne+hjaDwXqzgNwQ2vb2YKbnbOTyXjtS47stT66Apc4= -github.com/libp2p/go-libp2p-swarm v0.0.1/go.mod h1:mh+KZxkbd3lQnveQ3j2q60BM1Cw2mX36XXQqwfPOShs= -github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= -github.com/libp2p/go-libp2p-transport v0.0.4 h1:/CPHQMN75/IQwkhBxxIo6p6PtL3rwFZtlzBROT3e8mw= -github.com/libp2p/go-libp2p-transport v0.0.4/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= -github.com/libp2p/go-libp2p-transport-upgrader v0.0.1 h1:rNtXkY6dty46mxYOHHAZQchI7gQdJStF683FhVnei/k= -github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m+JmZCe5RUXG10UMEx4kWe9Ipj5c= -github.com/libp2p/go-maddr-filter v0.0.1 h1:apvYTg0aIxxQyBX+XHKOR+0+lYhGs1Yv+JmTH9nyl5I= -github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-mplex v0.0.1 h1:dn2XGSrUxLtz3/8u85bGrwhUEKPX8MOF3lpmcWBZCWc= -github.com/libp2p/go-mplex v0.0.1/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-msgio v0.0.1 h1:znj97n5FtXGCLDwe9x8jpHmY770SW4WStBGcCDh6GJw= -github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-libp2p v0.1.0 h1:8VXadcPNni74ODoZ+7326LMAppFYmz1fRQOUuT5iZvQ= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-blankhost v0.1.1 h1:X919sCh+KLqJcNRApj43xCSiQRYqOSI88Fdf55ngf78= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-core v0.0.1 h1:HSTZtFIq/W5Ue43Zw+uWZyy2Vl5WtF0zDjKN8/DT/1I= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-kbucket v0.2.0 h1:FB2a0VkOTNGTP5gu/I444u4WabNM9V1zCkQcWb7zajI= +github.com/libp2p/go-libp2p-kbucket v0.2.0/go.mod h1:JNymBToym3QXKBMKGy3m29+xprg0EVr/GJFHxFEdgh8= +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.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-nat v0.0.4 h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0 h1:MKh7pRNPHSh1fLPj8u/M/s/napdmeNpoi9BRy9lPN0E= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-record v0.1.0 h1:wHwBGbFzymoIl69BpgwIu0O6ta3TXGcMPvHUAcodzRc= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-routing v0.1.0 h1:hFnj3WR3E2tOcKaGpyzfP4gvFZ3t8JkQmbapN0Ct+oU= +github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE= +github.com/libp2p/go-libp2p-secio v0.1.0 h1:NNP5KLxuP97sE5Bu3iuwOWyT/dKEGMN5zSLMWdB7GTQ= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-swarm v0.1.0 h1:HrFk2p0awrGEgch9JXK/qp/hfjqQfgNxpLWnCiWPg5s= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3 h1:bdij4bKaaND7tCsaXVjRfYkMpvoOeKj9AVQGJllA6jM= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-yamux v0.2.0 h1:TSPZ5cMMz/wdoYsye/wU1TE4G3LDGMoeEN0xgnCKU/I= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-maddr-filter v0.0.4 h1:hx8HIuuwk34KePddrp2mM5ivgPkZ09JH4AvsALRbFUs= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-mplex v0.0.3 h1:YiMaevQcZtFU6DmKIF8xEO0vaui5kM5HJ1V1xkWQv14= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-msgio v0.0.2 h1:ivPvEKHxmVkTClHzg6RXTYHqaJQ0V9cDbq+6lKb3UV0= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.3 h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport-transport v0.0.1 h1:UIRneNxLDmEGNjGHpIiWzSWkZ5bhxMCP9x3Vh7BSc7E= -github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= github.com/libp2p/go-stream-muxer v0.0.1 h1:Ce6e2Pyu+b5MC1k3eeFtAax0pW4gc6MosYSLV05UeLw= github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-tcp-transport v0.0.1 h1:WyvJVw2lYAnr6CU+GZZ4oCt06fvORlmvBlFX2+ZpZDM= -github.com/libp2p/go-tcp-transport v0.0.1/go.mod h1:mnjg0o0O5TmXUaUIanYPUqkW4+u6mK0en8rlpA6BBTs= -github.com/libp2p/go-testutil v0.0.1 h1:Xg+O0G2HIMfHqBOBDcMS1iSZJ3GEcId4qOxCQvsGZHk= -github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= -github.com/libp2p/go-ws-transport v0.0.1 h1:9ytMqq86Xvp8rcnC/1ZNuH612eXLDglvcu4ZHseJl8s= -github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww= +github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0 h1:IGhowvEqyMFknOar4FWCKSWE0zL36UFKQtiRQD60/8o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-yamux v1.2.2 h1:s6J6o7+ajoQMjHe7BEnq+EynOj5D2EoG8CuQgL3F2vg= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 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 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0 h1:U41/2erhAKcmSI14xh/ZTUdBPOzDOIfS93ibzUSl8KM= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= 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 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-multiaddr v0.0.1 h1:/QUV3VBMDI6pi6xfiw7lr6xhDWWvQKn9udPn68kLSdY= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4 h1:WgMSI84/eRLdbptXMkMWDXPjPq7SPLIgGUVm2eroyU4= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2 h1:/Bbsgsy3R6e3jf2qBahzNHzww6usYaZ0NhNH3sqdFS8= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-fmt v0.0.1 h1:5YjeOIzbX8OTKVaN72aOzGIYW7PnrZrnkDyOfAWRSMA= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= github.com/multiformats/go-multiaddr-net v0.0.1 h1:76O59E3FavvHqNg7jvzWzsPSW5JSi/ek0E4eiDVbg9g= github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multistream v0.0.1 h1:JV4VfSdY9n7ECTtY59/TlSyFCzRILvYx4T4Ws8ZgihU= -github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.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/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek= +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= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -212,33 +245,44 @@ github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6 github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg= github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= -github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible h1:iqksILj8STw03EJQe7Laj4ubnw+ojOyik18cd5vPL1o= -github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDbeKFZInPUrAG+bjuJmUXONGdEFW7XL0SpTY1y4= -github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible h1:BdYHctE9HJZLquG9tpTdwWcbG4FaX6tVKPGjCGgiVxo= -github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ= -github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible h1:IGm/UP/JpEFS6D787sZnZg7RA6fZIR9c/Ms9DeAVNuk= -github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= -github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible h1:nVkExQ7pYlN9e45LcqTCOiDD0904fjtm0flnHZGbXkw= -github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= 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/whyrusleeping/yamux v1.1.5 h1:4CK3aUUJQu0qpKZv5gEWJjNOQtdbdDhVVS6PJ+HimdE= -github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= +go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/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 h1:+/WWzjwW6gidDJnMKWLKLX1gxn7irUTF1fLpQovfQ5M= golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28DveNzzgmbXR+ENoPjUeIU= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190227160552-c95aed5357e7 h1:C2F/nMkR/9sfUTpvR3QrjBuTdvMUC/cFajkphs1YLQo= golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= 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-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20180909124046-d0be0721c37e/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= @@ -246,12 +290,21 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpbl golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3 h1:P6iTFmrTQqWrqLZPX1VMzCUbCRCAUXSUsSpkEOvWzJ0= -golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/xerrors v0.0.0-20190513163551-3ee3066db522 h1:bhOzK9QyoD0ogCnFro1m2mz41+Ib0oOhfJnBp5MR4K4= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +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-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -261,3 +314,4 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/handlers.go b/handlers.go index 99ad280fc..aaeef7ca6 100644 --- a/handlers.go +++ b/handlers.go @@ -7,14 +7,16 @@ import ( "fmt" "time" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + pstore "github.com/libp2p/go-libp2p-peerstore" + proto "github.com/gogo/protobuf/proto" cid "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" u "github.com/ipfs/go-ipfs-util" pb "github.com/libp2p/go-libp2p-kad-dht/pb" - inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" - pstore "github.com/libp2p/go-libp2p-peerstore" recpb "github.com/libp2p/go-libp2p-record/pb" base32 "github.com/whyrusleeping/base32" ) @@ -69,6 +71,7 @@ func (dht *IpfsDHT) handleGetValue(ctx context.Context, p peer.ID, pmes *pb.Mess // Find closest peer on given cluster to desired key and reply with that info closer := dht.betterPeersToQuery(pmes, p, CloserPeerCount) if len(closer) > 0 { + // TODO: pstore.PeerInfos should move to core (=> peerstore.AddrInfos). closerinfos := pstore.PeerInfos(dht.peerstore, closer) for _, pi := range closerinfos { logger.Debugf("handleGetValue returning closer peer: '%s'", pi.ID) @@ -265,7 +268,7 @@ func (dht *IpfsDHT) handleFindPeer(ctx context.Context, p peer.ID, pmes *pb.Mess // add a progressive, asynchronous `SearchPeer` function // and improve peer routing in the host. switch dht.host.Network().Connectedness(targetPid) { - case inet.Connected, inet.CanConnect: + case network.Connected, network.CanConnect: closest = append(closest, targetPid) } } @@ -276,9 +279,10 @@ func (dht *IpfsDHT) handleFindPeer(ctx context.Context, p peer.ID, pmes *pb.Mess return resp, nil } + // TODO: pstore.PeerInfos should move to core (=> peerstore.AddrInfos). closestinfos := pstore.PeerInfos(dht.peerstore, closest) // possibly an over-allocation but this array is temporary anyways. - withAddresses := make([]pstore.PeerInfo, 0, len(closestinfos)) + withAddresses := make([]peer.AddrInfo, 0, len(closestinfos)) for _, pi := range closestinfos { if len(pi.Addrs) > 0 { withAddresses = append(withAddresses, pi) @@ -321,6 +325,7 @@ func (dht *IpfsDHT) handleGetProviders(ctx context.Context, p peer.ID, pmes *pb. } if len(providers) > 0 { + // TODO: pstore.PeerInfos should move to core (=> peerstore.AddrInfos). infos := pstore.PeerInfos(dht.peerstore, providers) resp.ProviderPeers = pb.PeerInfosToPBPeers(dht.host.Network(), infos) logger.Debugf("%s have %d providers: %s", reqDesc, len(providers), infos) @@ -329,6 +334,7 @@ func (dht *IpfsDHT) handleGetProviders(ctx context.Context, p peer.ID, pmes *pb. // Also send closer peers. closer := dht.betterPeersToQuery(pmes, p, CloserPeerCount) if closer != nil { + // TODO: pstore.PeerInfos should move to core (=> peerstore.AddrInfos). infos := pstore.PeerInfos(dht.peerstore, closer) resp.CloserPeers = pb.PeerInfosToPBPeers(dht.host.Network(), infos) logger.Debugf("%s have %d closer peers: %s", reqDesc, len(closer), infos) @@ -368,7 +374,7 @@ func (dht *IpfsDHT) handleAddProvider(ctx context.Context, p peer.ID, pmes *pb.M logger.Debugf("received provider %s for %s (addrs: %s)", p, c, pi.Addrs) if pi.ID != dht.self { // don't add own addrs. // add the received addresses to our peerstore. - dht.peerstore.AddAddrs(pi.ID, pi.Addrs, pstore.ProviderAddrTTL) + dht.peerstore.AddAddrs(pi.ID, pi.Addrs, peerstore.ProviderAddrTTL) } dht.providers.AddProvider(ctx, c, p) } diff --git a/lookup.go b/lookup.go index 9d482292a..3706bb3dd 100644 --- a/lookup.go +++ b/lookup.go @@ -4,12 +4,14 @@ import ( "context" "fmt" "strings" + "time" + + "github.com/libp2p/go-libp2p-core/peer" cid "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" pb "github.com/libp2p/go-libp2p-kad-dht/pb" kb "github.com/libp2p/go-libp2p-kbucket" - peer "github.com/libp2p/go-libp2p-peer" notif "github.com/libp2p/go-libp2p-routing/notifications" ) @@ -92,8 +94,10 @@ func (dht *IpfsDHT) GetClosestPeers(ctx context.Context, key string) (<-chan pee go func() { defer close(out) defer e.Done() + timedCtx, cancel := context.WithTimeout(ctx, time.Minute) + defer cancel() // run it! - res, err := query.Run(ctx, tablepeers) + res, err := query.Run(timedCtx, tablepeers) if err != nil { logger.Debugf("closestPeers query run error: %s", err) } diff --git a/metrics/metrics.go b/metrics/metrics.go new file mode 100644 index 000000000..bbe480154 --- /dev/null +++ b/metrics/metrics.go @@ -0,0 +1,95 @@ +package metrics + +import ( + pb "github.com/libp2p/go-libp2p-kad-dht/pb" + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" +) + +var ( + defaultBytesDistribution = view.Distribution(1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296) + defaultMillisecondsDistribution = view.Distribution(0.01, 0.05, 0.1, 0.3, 0.6, 0.8, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000) +) + +// Keys +var ( + KeyMessageType, _ = tag.NewKey("message_type") + KeyPeerID, _ = tag.NewKey("peer_id") + // KeyInstanceID identifies a dht instance by the pointer address. + // Useful for differentiating between different dhts that have the same peer id. + KeyInstanceID, _ = tag.NewKey("instance_id") +) + +// UpsertMessageType is a convenience upserts the message type +// of a pb.Message into the KeyMessageType. +func UpsertMessageType(m *pb.Message) tag.Mutator { + return tag.Upsert(KeyMessageType, m.Type.String()) +} + +// Measures +var ( + ReceivedMessages = stats.Int64("libp2p.io/dht/kad/received_messages", "Total number of messages received per RPC", stats.UnitDimensionless) + ReceivedMessageErrors = stats.Int64("libp2p.io/dht/kad/received_message_errors", "Total number of errors for messages received per RPC", stats.UnitDimensionless) + ReceivedBytes = stats.Int64("libp2p.io/dht/kad/received_bytes", "Total received bytes per RPC", stats.UnitBytes) + InboundRequestLatency = stats.Float64("libp2p.io/dht/kad/inbound_request_latency", "Latency per RPC", stats.UnitMilliseconds) + OutboundRequestLatency = stats.Float64("libp2p.io/dht/kad/outbound_request_latency", "Latency per RPC", stats.UnitMilliseconds) + SentMessages = stats.Int64("libp2p.io/dht/kad/sent_messages", "Total number of messages sent per RPC", stats.UnitDimensionless) + SentMessageErrors = stats.Int64("libp2p.io/dht/kad/sent_message_errors", "Total number of errors for messages sent per RPC", stats.UnitDimensionless) + SentRequests = stats.Int64("libp2p.io/dht/kad/sent_requests", "Total number of requests sent per RPC", stats.UnitDimensionless) + SentRequestErrors = stats.Int64("libp2p.io/dht/kad/sent_request_errors", "Total number of errors for requests sent per RPC", stats.UnitDimensionless) + SentBytes = stats.Int64("libp2p.io/dht/kad/sent_bytes", "Total sent bytes per RPC", stats.UnitBytes) +) + +var DefaultViews = []*view.View{ + &view.View{ + Measure: ReceivedMessages, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: view.Count(), + }, + &view.View{ + Measure: ReceivedMessageErrors, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: view.Count(), + }, + &view.View{ + Measure: ReceivedBytes, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: defaultBytesDistribution, + }, + &view.View{ + Measure: InboundRequestLatency, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: defaultMillisecondsDistribution, + }, + &view.View{ + Measure: OutboundRequestLatency, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: defaultMillisecondsDistribution, + }, + &view.View{ + Measure: SentMessages, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: view.Count(), + }, + &view.View{ + Measure: SentMessageErrors, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: view.Count(), + }, + &view.View{ + Measure: SentRequests, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: view.Count(), + }, + &view.View{ + Measure: SentRequestErrors, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: view.Count(), + }, + &view.View{ + Measure: SentBytes, + TagKeys: []tag.Key{KeyMessageType, KeyPeerID, KeyInstanceID}, + Aggregation: defaultBytesDistribution, + }, +} diff --git a/nofile_test_posix.go b/nofile_test_posix.go index 11ad5583f..efd1b383c 100644 --- a/nofile_test_posix.go +++ b/nofile_test_posix.go @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows,!wasm package dht diff --git a/notif.go b/notif.go index fbcb073be..3af758492 100644 --- a/notif.go +++ b/notif.go @@ -1,7 +1,9 @@ package dht import ( - inet "github.com/libp2p/go-libp2p-net" + "github.com/libp2p/go-libp2p-core/helpers" + "github.com/libp2p/go-libp2p-core/network" + ma "github.com/multiformats/go-multiaddr" mstream "github.com/multiformats/go-multistream" ) @@ -13,7 +15,7 @@ func (nn *netNotifiee) DHT() *IpfsDHT { return (*IpfsDHT)(nn) } -func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) { +func (nn *netNotifiee) Connected(n network.Network, v network.Conn) { dht := nn.DHT() select { case <-dht.Process().Closing(): @@ -29,7 +31,7 @@ func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) { // notifications are serialized but it's nice to be consistent. dht.plk.Lock() defer dht.plk.Unlock() - if dht.host.Network().Connectedness(p) == inet.Connected { + if dht.host.Network().Connectedness(p) == network.Connected { dht.Update(dht.Context(), p) } return @@ -41,7 +43,7 @@ func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) { go nn.testConnection(v) } -func (nn *netNotifiee) testConnection(v inet.Conn) { +func (nn *netNotifiee) testConnection(v network.Conn) { dht := nn.DHT() p := v.RemotePeer() @@ -53,7 +55,7 @@ func (nn *netNotifiee) testConnection(v inet.Conn) { // Connection error return } - defer inet.FullClose(s) + defer helpers.FullClose(s) selected, err := mstream.SelectOneOf(dht.protocolStrs(), s) if err != nil { @@ -68,12 +70,12 @@ func (nn *netNotifiee) testConnection(v inet.Conn) { // event and add the peer to the routing table after removing it. dht.plk.Lock() defer dht.plk.Unlock() - if dht.host.Network().Connectedness(p) == inet.Connected { + if dht.host.Network().Connectedness(p) == network.Connected { dht.Update(dht.Context(), p) } } -func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) { +func (nn *netNotifiee) Disconnected(n network.Network, v network.Conn) { dht := nn.DHT() select { case <-dht.Process().Closing(): @@ -87,7 +89,7 @@ func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) { // we don't concurrently process a connect event. dht.plk.Lock() defer dht.plk.Unlock() - if dht.host.Network().Connectedness(p) == inet.Connected { + if dht.host.Network().Connectedness(p) == network.Connected { // We're still connected. return } @@ -110,7 +112,7 @@ func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) { }() } -func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {} -func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {} -func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) {} -func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {} +func (nn *netNotifiee) OpenedStream(n network.Network, v network.Stream) {} +func (nn *netNotifiee) ClosedStream(n network.Network, v network.Stream) {} +func (nn *netNotifiee) Listen(n network.Network, a ma.Multiaddr) {} +func (nn *netNotifiee) ListenClose(n network.Network, a ma.Multiaddr) {} diff --git a/notify_test.go b/notify_test.go index 7df9ee4c9..3a15a8e82 100644 --- a/notify_test.go +++ b/notify_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - tu "github.com/libp2p/go-testutil" + tu "github.com/libp2p/go-libp2p-testing/etc" ) func TestNotifieeMultipleConn(t *testing.T) { diff --git a/opts/options.go b/opts/options.go index 164f39329..93ce6c0de 100644 --- a/opts/options.go +++ b/opts/options.go @@ -5,13 +5,18 @@ import ( ds "github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-datastore/sync" - "github.com/libp2p/go-libp2p-protocol" + protocol "github.com/libp2p/go-libp2p-core/protocol" record "github.com/libp2p/go-libp2p-record" ) -var ProtocolDHT protocol.ID = "/ipfs/kad/1.0.0" -var ProtocolDHTOld protocol.ID = "/ipfs/dht" -var DefaultProtocols = []protocol.ID{ProtocolDHT, ProtocolDHTOld} +// Deprecated: The old format did not support more than one message per stream, and is not supported +// or relevant with stream pooling. ProtocolDHT should be used instead. +const ProtocolDHTOld protocol.ID = "/ipfs/dht" + +var ( + ProtocolDHT protocol.ID = "/ipfs/kad/1.0.0" + DefaultProtocols = []protocol.ID{ProtocolDHT} +) // Options is a structure containing all the options that can be used when constructing a DHT. type Options struct { diff --git a/package.json b/package.json deleted file mode 100644 index 30ac77eff..000000000 --- a/package.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "bugs": { - "url": "https://github.com/libp2p/go-libp2p-kad-dht" - }, - "gx": { - "dvcsimport": "github.com/libp2p/go-libp2p-kad-dht", - "goversion": "1.5.2" - }, - "gxDependencies": [ - { - "hash": "QmbkT7eMTyXfpeyB3ZMxxcxg7XH8t6uXp49jqzz4HB7BGF", - "name": "go-log", - "version": "1.5.9" - }, - { - "author": "whyrusleeping", - "hash": "QmTW4SdgBWq9GjsBsHeUx8WuGxzhgzAf88UMH2w62PC8yK", - "name": "go-libp2p-crypto", - "version": "2.0.7" - }, - { - "author": "whyrusleeping", - "hash": "QmYVXrKrKHDC9FobgmcmshCDyWwdrfwfanNQN4oxJ9Fk3h", - "name": "go-libp2p-peer", - "version": "3.1.2" - }, - { - "hash": "QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP", - "name": "goprocess", - "version": "1.0.0" - }, - { - "hash": "QmddjPSGZb3ieihSseFeCfVRpZzcqczPNsD2DvarSwnjJB", - "name": "gogo-protobuf", - "version": "1.2.1" - }, - { - "author": "jbenet", - "hash": "QmTKsRYeY4simJyf37K93juSq75Lo8MVCDJ7owjmf46u8W", - "name": "go-context", - "version": "1.0.0" - }, - { - "author": "jbenet", - "hash": "QmUadX5EcvrBmxAV9sE7wUWtWSqxns5K84qKJBixmcT1w9", - "name": "go-datastore", - "version": "3.6.1" - }, - { - "author": "hashicorp", - "hash": "QmQjMHF8ptRgx4E57UFMiT4YM6kqaJeYxZ1MCDX23aw4rK", - "name": "golang-lru", - "version": "2017.10.18" - }, - { - "author": "whyrusleeping", - "hash": "QmaCTz9RkrU13bm9kMB54f7atgqM4qkjDZpRwRoJiWXEqs", - "name": "go-libp2p-peerstore", - "version": "2.0.19" - }, - { - "author": "whyrusleeping", - "hash": "QmfVj3x4D6Jkq9SEoi5n2NmoUomLwoeiwnYz2KQa15wRw6", - "name": "base32", - "version": "0.0.2" - }, - { - "author": "whyrusleeping", - "hash": "QmWapVoHjtKhn4MhvKNoPTkJKADFGACfXPFnt7combwp5W", - "name": "go-testutil", - "version": "1.2.19" - }, - { - "author": "whyrusleeping", - "hash": "QmbeHtaBy9nZsW4cHRcvgVY4CnDhXudE2Dr6qDxS7yg9rX", - "name": "go-libp2p-record", - "version": "4.1.15" - }, - { - "author": "whyrusleeping", - "hash": "QmSNE1XryoCMnZCbRaj1D23k6YKCaTQ386eJciu1pAfu8M", - "name": "go-libp2p-kbucket", - "version": "2.2.23" - }, - { - "author": "whyrusleeping", - "hash": "QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf", - "name": "go-libp2p-routing", - "version": "2.7.13" - }, - { - "author": "whyrusleeping", - "hash": "QmQNQhNmY4STU1MURjH9vYEMpx2ncMS4gbwxXWtrEjzVAq", - "name": "go-todocounter", - "version": "1.0.1" - }, - { - "author": "whyrusleeping", - "hash": "QmTbxNB1NwDesLmKTscr4udL2tVP7MaxvXnD1D9yX7g3PN", - "name": "go-cid", - "version": "0.9.3" - }, - { - "author": "whyrusleeping", - "hash": "QmUbSLukzZYZvEYxynj9Dtd1WrGLxxg9R4U68vCMPWHmRU", - "name": "go-libp2p-loggables", - "version": "1.1.33" - }, - { - "author": "whyrusleeping", - "hash": "QmYrWiWM4qtrnCeT3R14jY3ZZyirDNJgwK57q4qFYePgbd", - "name": "go-libp2p-host", - "version": "3.0.26" - }, - { - "author": "whyrusleeping", - "hash": "QmTRN7hRxvGkxKxDdeudty7sRet4L7ZKZCqKsXHa79wmAc", - "name": "go-libp2p", - "version": "6.0.41" - }, - { - "author": "whyrusleeping", - "hash": "QmY3ArotKMKaL7YGfbQfyDrib6RVraLqZYWXZvVgZktBxp", - "name": "go-libp2p-net", - "version": "3.0.30" - }, - { - "author": "whyrusleeping", - "hash": "QmNohiVssaPw3KVLZik59DBVGTSm2dGvYT9eoXt5DQ36Yz", - "name": "go-ipfs-util", - "version": "1.2.9" - }, - { - "author": "whyrusleeping", - "hash": "QmabLh8TrJ3emfAoQk5AbqbLTbMyj7XqumMFmAFxa9epo8", - "name": "go-multistream", - "version": "0.3.9" - }, - { - "author": "multiformats", - "hash": "QmTZBfrPJmjWsCvHEtX5FE6KimVJhsJg5sBbqEFYf4UZtL", - "name": "go-multiaddr", - "version": "1.4.1" - }, - { - "author": "whyrusleeping", - "hash": "QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN", - "name": "go-libp2p-protocol", - "version": "1.0.0" - }, - { - "author": "mr-tron", - "hash": "QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY", - "name": "go-base58-fast", - "version": "0.1.1" - }, - { - "author": "whyrusleeping", - "hash": "QmQVoMEL1CxrVusTSUdYsiJXVBnvSqNUpBsGybkwSfksEF", - "name": "go-libp2p-swarm", - "version": "3.0.35" - }, - { - "author": "magik6k", - "hash": "QmPVkJMTeRC6iBByPWdrRkD3BE5UXsj5HPzb4kPqL186mS", - "name": "testify", - "version": "1.0.0" - }, - { - "author": "anacrolix", - "hash": "QmW1UQYrsBotoorzgBcQ3HVj5RzZUzB6g1vQwnNfUuCVdN", - "name": "xerrors", - "version": "0.0.2" - } - ], - "gxVersion": "0.4.0", - "language": "go", - "license": "MIT", - "name": "go-libp2p-kad-dht", - "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "4.4.33" -} diff --git a/pb/dht.pb.go b/pb/dht.pb.go index eb59b73c8..98604ca2d 100644 --- a/pb/dht.pb.go +++ b/pb/dht.pb.go @@ -259,44 +259,106 @@ func (m *Message_Peer) GetConnection() Message_ConnectionType { return Message_NOT_CONNECTED } +// Encapsulates a routing table snapshot for persistence. +type RoutingTableSnapshot struct { + // The peers that were members of the routing table. + Peers [][]byte `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"` + // The timestamp when this snapshot was taken. + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RoutingTableSnapshot) Reset() { *m = RoutingTableSnapshot{} } +func (m *RoutingTableSnapshot) String() string { return proto.CompactTextString(m) } +func (*RoutingTableSnapshot) ProtoMessage() {} +func (*RoutingTableSnapshot) Descriptor() ([]byte, []int) { + return fileDescriptor_616a434b24c97ff4, []int{1} +} +func (m *RoutingTableSnapshot) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RoutingTableSnapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RoutingTableSnapshot.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RoutingTableSnapshot) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutingTableSnapshot.Merge(m, src) +} +func (m *RoutingTableSnapshot) XXX_Size() int { + return m.Size() +} +func (m *RoutingTableSnapshot) XXX_DiscardUnknown() { + xxx_messageInfo_RoutingTableSnapshot.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutingTableSnapshot proto.InternalMessageInfo + +func (m *RoutingTableSnapshot) GetPeers() [][]byte { + if m != nil { + return m.Peers + } + return nil +} + +func (m *RoutingTableSnapshot) GetTimestamp() int64 { + if m != nil { + return m.Timestamp + } + return 0 +} + func init() { proto.RegisterEnum("dht.pb.Message_MessageType", Message_MessageType_name, Message_MessageType_value) proto.RegisterEnum("dht.pb.Message_ConnectionType", Message_ConnectionType_name, Message_ConnectionType_value) proto.RegisterType((*Message)(nil), "dht.pb.Message") proto.RegisterType((*Message_Peer)(nil), "dht.pb.Message.Peer") + proto.RegisterType((*RoutingTableSnapshot)(nil), "dht.pb.RoutingTableSnapshot") } func init() { proto.RegisterFile("dht.proto", fileDescriptor_616a434b24c97ff4) } var fileDescriptor_616a434b24c97ff4 = []byte{ - // 428 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0xc1, 0x6e, 0x9b, 0x40, - 0x10, 0xed, 0x02, 0x76, 0xe3, 0x01, 0x93, 0xcd, 0x28, 0x07, 0x94, 0x4a, 0x16, 0xf2, 0x89, 0x1e, - 0x02, 0x12, 0x95, 0x7a, 0xe8, 0xa1, 0x92, 0x0b, 0x34, 0xb2, 0x94, 0x62, 0x6b, 0xeb, 0xa4, 0x47, - 0xcb, 0xc0, 0xca, 0x41, 0xa5, 0x5e, 0x04, 0x24, 0x95, 0xbf, 0xb0, 0x3d, 0xf6, 0x13, 0x2a, 0x7f, - 0x49, 0x05, 0x84, 0x16, 0xfb, 0xd0, 0xd3, 0xbe, 0x37, 0xf3, 0xde, 0xce, 0xdb, 0xd1, 0xc2, 0x28, - 0x79, 0xa8, 0xec, 0xbc, 0x10, 0x95, 0xc0, 0x61, 0x03, 0xa3, 0x2b, 0x77, 0x9b, 0x56, 0x0f, 0x8f, - 0x91, 0x1d, 0x8b, 0x6f, 0x4e, 0x96, 0x46, 0xb9, 0x9b, 0x3b, 0x5b, 0x71, 0xdd, 0xa2, 0xeb, 0x82, - 0xc7, 0xa2, 0x48, 0x9c, 0x3c, 0x72, 0x5a, 0xd4, 0x7a, 0xa7, 0x3f, 0x14, 0x78, 0xf9, 0x89, 0x97, - 0xe5, 0x66, 0xcb, 0xd1, 0x01, 0xa5, 0xda, 0xe7, 0xdc, 0x20, 0x26, 0xb1, 0x74, 0xf7, 0x95, 0xdd, - 0x5e, 0x6b, 0x3f, 0xb7, 0xbb, 0x73, 0xb5, 0xcf, 0x39, 0x6b, 0x84, 0x68, 0xc1, 0x79, 0x9c, 0x3d, - 0x96, 0x15, 0x2f, 0x6e, 0xf9, 0x13, 0xcf, 0xd8, 0xe6, 0xbb, 0x01, 0x26, 0xb1, 0x06, 0xec, 0xb4, - 0x8c, 0x14, 0xe4, 0xaf, 0x7c, 0x6f, 0x48, 0x26, 0xb1, 0x34, 0x56, 0x43, 0x7c, 0x0d, 0xc3, 0x36, - 0x88, 0x21, 0x9b, 0xc4, 0x52, 0xdd, 0x0b, 0xbb, 0xcb, 0x15, 0xd9, 0xac, 0x41, 0xec, 0x59, 0x80, - 0x6f, 0x41, 0x8d, 0x33, 0x51, 0xf2, 0x62, 0xc9, 0x79, 0x51, 0x1a, 0x67, 0xa6, 0x6c, 0xa9, 0xee, - 0xe5, 0x69, 0xbc, 0xba, 0xc9, 0xfa, 0x42, 0x7c, 0x07, 0xe3, 0xbc, 0x10, 0x4f, 0x69, 0xd2, 0x39, - 0x47, 0xff, 0x71, 0x1e, 0x4b, 0xaf, 0x32, 0x50, 0x6a, 0x80, 0x3a, 0x48, 0x69, 0xd2, 0x6c, 0x44, - 0x63, 0x52, 0x9a, 0xe0, 0x25, 0x0c, 0x36, 0x49, 0x52, 0x94, 0x86, 0x64, 0xca, 0x96, 0xc6, 0x5a, - 0x82, 0xef, 0x01, 0x62, 0xb1, 0xdb, 0xf1, 0xb8, 0x4a, 0xc5, 0xae, 0x79, 0x90, 0xee, 0x4e, 0x4e, - 0xc7, 0x78, 0x7f, 0x15, 0xcd, 0x0a, 0x7b, 0x8e, 0x69, 0x0a, 0x6a, 0x6f, 0xbb, 0x38, 0x86, 0xd1, - 0xf2, 0x6e, 0xb5, 0xbe, 0x9f, 0xdd, 0xde, 0x05, 0xf4, 0x45, 0x4d, 0x6f, 0x82, 0x8e, 0x12, 0xa4, - 0xa0, 0xcd, 0x7c, 0x7f, 0xbd, 0x64, 0x8b, 0xfb, 0xb9, 0x1f, 0x30, 0x2a, 0xe1, 0x05, 0x8c, 0x6b, - 0x41, 0x57, 0xf9, 0x4c, 0xe5, 0xda, 0xf3, 0x71, 0x1e, 0xfa, 0xeb, 0x70, 0xe1, 0x07, 0x54, 0xc1, - 0x33, 0x50, 0x96, 0xf3, 0xf0, 0x86, 0x0e, 0xa6, 0x5f, 0x40, 0x3f, 0x0e, 0x52, 0xbb, 0xc3, 0xc5, - 0x6a, 0xed, 0x2d, 0xc2, 0x30, 0xf0, 0x56, 0x81, 0xdf, 0x4e, 0xfc, 0x47, 0x09, 0x9e, 0x83, 0xea, - 0xcd, 0xc2, 0x4e, 0x41, 0x25, 0x44, 0xd0, 0xbd, 0x59, 0xd8, 0x73, 0x51, 0xf9, 0x83, 0xf6, 0xf3, - 0x30, 0x21, 0xbf, 0x0e, 0x13, 0xf2, 0xfb, 0x30, 0x21, 0xd1, 0xb0, 0xf9, 0x5e, 0x6f, 0xfe, 0x04, - 0x00, 0x00, 0xff, 0xff, 0xf4, 0x3c, 0x3f, 0x3f, 0xa7, 0x02, 0x00, 0x00, + // 472 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0xcd, 0x6e, 0x9b, 0x40, + 0x18, 0xec, 0x82, 0xed, 0xc6, 0x9f, 0x7f, 0x42, 0x56, 0x3e, 0xa0, 0xb4, 0xb2, 0x90, 0x4f, 0xf4, + 0x10, 0x2c, 0x51, 0xa9, 0x87, 0x1e, 0x2a, 0xb9, 0x40, 0x23, 0x57, 0x29, 0xb6, 0x36, 0x24, 0x3d, + 0x5a, 0xfc, 0xac, 0x6c, 0x54, 0xcc, 0xae, 0x60, 0x9d, 0xca, 0x4f, 0xd8, 0x1e, 0xfb, 0x08, 0x95, + 0x9f, 0xa4, 0x62, 0x09, 0x8d, 0xe3, 0x43, 0x4e, 0xcc, 0x7c, 0x3b, 0xc3, 0xce, 0x8e, 0x3e, 0xe8, + 0x26, 0x1b, 0x61, 0xf1, 0x82, 0x09, 0x86, 0x3b, 0x12, 0x46, 0x97, 0xf6, 0x3a, 0x15, 0x9b, 0x5d, + 0x64, 0xc5, 0x6c, 0x3b, 0xcd, 0xd2, 0x88, 0xdb, 0x7c, 0xba, 0x66, 0x57, 0x35, 0xba, 0x2a, 0x68, + 0xcc, 0x8a, 0x64, 0xca, 0xa3, 0x69, 0x8d, 0x6a, 0xef, 0xe4, 0x57, 0x0b, 0x5e, 0x7f, 0xa3, 0x65, + 0x19, 0xae, 0x29, 0x9e, 0x42, 0x4b, 0xec, 0x39, 0xd5, 0x91, 0x81, 0xcc, 0xa1, 0xfd, 0xc6, 0xaa, + 0x7f, 0x6b, 0x3d, 0x1e, 0x37, 0xdf, 0x60, 0xcf, 0x29, 0x91, 0x42, 0x6c, 0xc2, 0x79, 0x9c, 0xed, + 0x4a, 0x41, 0x8b, 0x1b, 0xfa, 0x40, 0x33, 0x12, 0xfe, 0xd4, 0xc1, 0x40, 0x66, 0x9b, 0x9c, 0x8e, + 0xb1, 0x06, 0xea, 0x0f, 0xba, 0xd7, 0x15, 0x03, 0x99, 0x7d, 0x52, 0x41, 0xfc, 0x0e, 0x3a, 0x75, + 0x10, 0x5d, 0x35, 0x90, 0xd9, 0xb3, 0x2f, 0xac, 0x26, 0x57, 0x64, 0x11, 0x89, 0xc8, 0xa3, 0x00, + 0x7f, 0x80, 0x5e, 0x9c, 0xb1, 0x92, 0x16, 0x4b, 0x4a, 0x8b, 0x52, 0x3f, 0x33, 0x54, 0xb3, 0x67, + 0x8f, 0x4e, 0xe3, 0x55, 0x87, 0xe4, 0x58, 0x88, 0x3f, 0xc2, 0x80, 0x17, 0xec, 0x21, 0x4d, 0x1a, + 0x67, 0xf7, 0x05, 0xe7, 0x73, 0xe9, 0x65, 0x06, 0xad, 0x0a, 0xe0, 0x21, 0x28, 0x69, 0x22, 0x1b, + 0xe9, 0x13, 0x25, 0x4d, 0xf0, 0x08, 0xda, 0x61, 0x92, 0x14, 0xa5, 0xae, 0x18, 0xaa, 0xd9, 0x27, + 0x35, 0xc1, 0x9f, 0x00, 0x62, 0x96, 0xe7, 0x34, 0x16, 0x29, 0xcb, 0xe5, 0x83, 0x86, 0xf6, 0xf8, + 0xf4, 0x1a, 0xe7, 0xbf, 0x42, 0x56, 0x78, 0xe4, 0x98, 0xa4, 0xd0, 0x3b, 0x6a, 0x17, 0x0f, 0xa0, + 0xbb, 0xbc, 0x0b, 0x56, 0xf7, 0xb3, 0x9b, 0x3b, 0x4f, 0x7b, 0x55, 0xd1, 0x6b, 0xaf, 0xa1, 0x08, + 0x6b, 0xd0, 0x9f, 0xb9, 0xee, 0x6a, 0x49, 0x16, 0xf7, 0x73, 0xd7, 0x23, 0x9a, 0x82, 0x2f, 0x60, + 0x50, 0x09, 0x9a, 0xc9, 0xad, 0xa6, 0x56, 0x9e, 0x2f, 0x73, 0xdf, 0x5d, 0xf9, 0x0b, 0xd7, 0xd3, + 0x5a, 0xf8, 0x0c, 0x5a, 0xcb, 0xb9, 0x7f, 0xad, 0xb5, 0x27, 0xdf, 0x61, 0xf8, 0x3c, 0x48, 0xe5, + 0xf6, 0x17, 0xc1, 0xca, 0x59, 0xf8, 0xbe, 0xe7, 0x04, 0x9e, 0x5b, 0xdf, 0xf8, 0x44, 0x11, 0x3e, + 0x87, 0x9e, 0x33, 0xf3, 0x1b, 0x85, 0xa6, 0x60, 0x0c, 0x43, 0x67, 0xe6, 0x1f, 0xb9, 0x34, 0x75, + 0xf2, 0x15, 0x46, 0x84, 0xed, 0x44, 0x9a, 0xaf, 0x83, 0x30, 0xca, 0xe8, 0x6d, 0x1e, 0xf2, 0x72, + 0xc3, 0x44, 0xd5, 0x18, 0x97, 0xed, 0xa3, 0xba, 0x31, 0x49, 0xf0, 0x5b, 0xe8, 0x8a, 0x74, 0x4b, + 0x4b, 0x11, 0x6e, 0xb9, 0x5c, 0x0b, 0x95, 0x3c, 0x0d, 0x3e, 0xf7, 0x7f, 0x1f, 0xc6, 0xe8, 0xcf, + 0x61, 0x8c, 0xfe, 0x1e, 0xc6, 0x28, 0xea, 0xc8, 0x55, 0x7d, 0xff, 0x2f, 0x00, 0x00, 0xff, 0xff, + 0x53, 0xb2, 0x24, 0x7a, 0xf3, 0x02, 0x00, 0x00, } func (m *Message) Marshal() (dAtA []byte, err error) { @@ -410,6 +472,40 @@ func (m *Message_Peer) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *RoutingTableSnapshot) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoutingTableSnapshot) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Peers) > 0 { + for _, b := range m.Peers { + dAtA[i] = 0xa + i++ + i = encodeVarintDht(dAtA, i, uint64(len(b))) + i += copy(dAtA[i:], b) + } + } + if m.Timestamp != 0 { + dAtA[i] = 0x10 + i++ + i = encodeVarintDht(dAtA, i, uint64(m.Timestamp)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + func encodeVarintDht(dAtA []byte, offset int, v uint64) int { for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -482,6 +578,27 @@ func (m *Message_Peer) Size() (n int) { return n } +func (m *RoutingTableSnapshot) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Peers) > 0 { + for _, b := range m.Peers { + l = len(b) + n += 1 + l + sovDht(uint64(l)) + } + } + if m.Timestamp != 0 { + n += 1 + sovDht(uint64(m.Timestamp)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovDht(x uint64) (n int) { for { n++ @@ -864,6 +981,111 @@ func (m *Message_Peer) Unmarshal(dAtA []byte) error { } return nil } +func (m *RoutingTableSnapshot) 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 ErrIntOverflowDht + } + 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: RoutingTableSnapshot: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RoutingTableSnapshot: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Peers", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDht + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDht + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDht + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Peers = append(m.Peers, make([]byte, postIndex-iNdEx)) + copy(m.Peers[len(m.Peers)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDht + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipDht(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthDht + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthDht + } + 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 skipDht(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/pb/dht.proto b/pb/dht.proto index 4d2d1fd2e..f1e2dba3f 100644 --- a/pb/dht.proto +++ b/pb/dht.proto @@ -69,3 +69,12 @@ message Message { // GET_VALUE, ADD_PROVIDER, GET_PROVIDERS repeated Peer providerPeers = 9; } + +// Encapsulates a routing table snapshot for persistence. +message RoutingTableSnapshot { + // The peers that were members of the routing table. + repeated bytes peers = 1; + + // The timestamp when this snapshot was taken. + int64 timestamp = 2; +} \ No newline at end of file diff --git a/pb/message.go b/pb/message.go index a2a41254c..d8fd27270 100644 --- a/pb/message.go +++ b/pb/message.go @@ -1,10 +1,10 @@ package dht_pb import ( + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + logging "github.com/ipfs/go-log" - inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" - pstore "github.com/libp2p/go-libp2p-peerstore" b58 "github.com/mr-tron/base58/base58" ma "github.com/multiformats/go-multiaddr" ) @@ -12,8 +12,8 @@ import ( var log = logging.Logger("dht.pb") type PeerRoutingInfo struct { - pstore.PeerInfo - inet.Connectedness + peer.AddrInfo + network.Connectedness } // NewMessage constructs a new dht message with given type, key, and level @@ -40,7 +40,7 @@ func peerRoutingInfoToPBPeer(p PeerRoutingInfo) *Message_Peer { return pbp } -func peerInfoToPBPeer(p pstore.PeerInfo) *Message_Peer { +func peerInfoToPBPeer(p peer.AddrInfo) *Message_Peer { pbp := new(Message_Peer) pbp.Addrs = make([][]byte, len(p.Addrs)) @@ -51,9 +51,9 @@ func peerInfoToPBPeer(p pstore.PeerInfo) *Message_Peer { return pbp } -// PBPeerToPeer turns a *Message_Peer into its pstore.PeerInfo counterpart -func PBPeerToPeerInfo(pbp *Message_Peer) *pstore.PeerInfo { - return &pstore.PeerInfo{ +// PBPeerToPeer turns a *Message_Peer into its peer.AddrInfo counterpart +func PBPeerToPeerInfo(pbp *Message_Peer) *peer.AddrInfo { + return &peer.AddrInfo{ ID: peer.ID(pbp.GetId()), Addrs: pbp.Addresses(), } @@ -61,7 +61,7 @@ func PBPeerToPeerInfo(pbp *Message_Peer) *pstore.PeerInfo { // RawPeerInfosToPBPeers converts a slice of Peers into a slice of *Message_Peers, // ready to go out on the wire. -func RawPeerInfosToPBPeers(peers []pstore.PeerInfo) []*Message_Peer { +func RawPeerInfosToPBPeers(peers []peer.AddrInfo) []*Message_Peer { pbpeers := make([]*Message_Peer, len(peers)) for i, p := range peers { pbpeers[i] = peerInfoToPBPeer(p) @@ -72,8 +72,8 @@ func RawPeerInfosToPBPeers(peers []pstore.PeerInfo) []*Message_Peer { // PeersToPBPeers converts given []peer.Peer into a set of []*Message_Peer, // which can be written to a message and sent out. the key thing this function // does (in addition to PeersToPBPeers) is set the ConnectionType with -// information from the given inet.Network. -func PeerInfosToPBPeers(n inet.Network, peers []pstore.PeerInfo) []*Message_Peer { +// information from the given network.Network. +func PeerInfosToPBPeers(n network.Network, peers []peer.AddrInfo) []*Message_Peer { pbps := RawPeerInfosToPBPeers(peers) for i, pbp := range pbps { c := ConnectionType(n.Connectedness(peers[i].ID)) @@ -90,10 +90,10 @@ func PeerRoutingInfosToPBPeers(peers []PeerRoutingInfo) []*Message_Peer { return pbpeers } -// PBPeersToPeerInfos converts given []*Message_Peer into []pstore.PeerInfo +// PBPeersToPeerInfos converts given []*Message_Peer into []peer.AddrInfo // Invalid addresses will be silently omitted. -func PBPeersToPeerInfos(pbps []*Message_Peer) []*pstore.PeerInfo { - peers := make([]*pstore.PeerInfo, 0, len(pbps)) +func PBPeersToPeerInfos(pbps []*Message_Peer) []*peer.AddrInfo { + peers := make([]*peer.AddrInfo, 0, len(pbps)) for _, pbp := range pbps { peers = append(peers, PBPeerToPeerInfo(pbp)) } @@ -149,35 +149,35 @@ func (m *Message) Loggable() map[string]interface{} { } // ConnectionType returns a Message_ConnectionType associated with the -// inet.Connectedness. -func ConnectionType(c inet.Connectedness) Message_ConnectionType { +// network.Connectedness. +func ConnectionType(c network.Connectedness) Message_ConnectionType { switch c { default: return Message_NOT_CONNECTED - case inet.NotConnected: + case network.NotConnected: return Message_NOT_CONNECTED - case inet.Connected: + case network.Connected: return Message_CONNECTED - case inet.CanConnect: + case network.CanConnect: return Message_CAN_CONNECT - case inet.CannotConnect: + case network.CannotConnect: return Message_CANNOT_CONNECT } } -// Connectedness returns an inet.Connectedness associated with the +// Connectedness returns an network.Connectedness associated with the // Message_ConnectionType. -func Connectedness(c Message_ConnectionType) inet.Connectedness { +func Connectedness(c Message_ConnectionType) network.Connectedness { switch c { default: - return inet.NotConnected + return network.NotConnected case Message_NOT_CONNECTED: - return inet.NotConnected + return network.NotConnected case Message_CONNECTED: - return inet.Connected + return network.Connected case Message_CAN_CONNECT: - return inet.CanConnect + return network.CanConnect case Message_CANNOT_CONNECT: - return inet.CannotConnect + return network.CannotConnect } } diff --git a/persist/interfaces.go b/persist/interfaces.go new file mode 100644 index 000000000..23505b63d --- /dev/null +++ b/persist/interfaces.go @@ -0,0 +1,26 @@ +package persist + +import ( + kbucket "github.com/libp2p/go-libp2p-kbucket" + peer "github.com/libp2p/go-libp2p-peer" + + log "github.com/ipfs/go-log" +) + +var logSeed = log.Logger("dht/seeder") +var logSnapshot = log.Logger("dht/snapshot") + +type Seeder interface { + // Seed takes an optional set of candidates from a snapshot (or nil if none could be loaded), + // and a set of fallback peers, and it seeds a routing table instance with working peers. + Seed(into *kbucket.RoutingTable, candidates []peer.ID, fallback []peer.ID) error +} + +// A Snapshotter provides the ability to save and restore a routing table from a persistent medium. +type Snapshotter interface { + // Load recovers a snapshot from storage, and returns candidates to integrate in a fresh routing table. + Load() ([]peer.ID, error) + + // Store persists the current state of the routing table. + Store(rt *kbucket.RoutingTable) error +} \ No newline at end of file diff --git a/persist/seeder.go b/persist/seeder.go new file mode 100644 index 000000000..7009c046b --- /dev/null +++ b/persist/seeder.go @@ -0,0 +1,135 @@ +package persist + +import ( + "context" + "errors" + "math/rand" + "time" + + todocounter "github.com/ipfs/go-todocounter" + + host "github.com/libp2p/go-libp2p-host" + kbucket "github.com/libp2p/go-libp2p-kbucket" + inet "github.com/libp2p/go-libp2p-net" + peer "github.com/libp2p/go-libp2p-peer" +) + +var SeedDialGracePeriod = 5 * time.Second +var ErrPartialSeed = errors.New("routing table seeded partially") + +type randomSeeder struct { + host host.Host + target int +} + +var _ Seeder = (*randomSeeder)(nil) + +// NewRandomSeeder returns a Seeder that seeds a routing table with `target` random peers from +// the supplied candidate set, resorting to fallback peers if the candidates are unworkable. +// +// The fallback peers are guaranteed to exist in the peerstore. +func NewRandomSeeder(host host.Host, target int) Seeder { + return &randomSeeder{host, target} +} + +func (rs *randomSeeder) Seed(into *kbucket.RoutingTable, candidates []peer.ID, fallback []peer.ID) error { + cpy := make([]peer.ID, len(candidates)) + copy(cpy, candidates) + rand.Shuffle(len(cpy), func(i, j int) { + cpy[i], cpy[j] = cpy[j], cpy[i] + }) + + left := rs.target + addPeer := func(p peer.ID) { // adds a peer to the routing table and decrements the left counter if successful. + evicted, err := into.Update(p) + if err == nil && evicted == "" { + left-- // if we evict a peer, do not decrement the counter. + } else if err != nil { + logSeed.Warningf("error while adding candidate to routing table: %s", err) + } + } + + var todial []peer.ID + for _, p := range cpy { + if left == 0 { + return nil // lucky case: we were already connected to all our candidates. + } + if rs.host.Network().Connectedness(p) == inet.Connected { + addPeer(p) + continue + } + if addrs := rs.host.Peerstore().Addrs(p); len(addrs) == 0 { + logSeed.Infof("discarding routing table candidate as we no longer have addresses: %s", p) + continue + } + todial = append(todial, p) + } + + type result struct { + p peer.ID + err error + } + + todo := todocounter.NewSyncCounter() + todo.Increment(uint32(len(todial))) + + ctx, cancel := context.WithTimeout(context.Background(), SeedDialGracePeriod) + defer cancel() + + dialFn := func(p peer.ID, res chan<- result) { + _, err := rs.host.Network().DialPeer(ctx, p) + if err == context.Canceled { + return + } + select { + case res <- result{p, err}: + case <-time.After(5 * time.Second): + // discard this result, no one needs it. a default branch could be racy, so this is better. + } + } + + var fallingBack bool // are we falling back? + resCh := make(chan result) // dial results. + +DialCandidates: + for _, p := range todial { + go dialFn(p, resCh) + } + + for left > 0 { + select { + case res := <-resCh: + todo.Decrement(1) + if res.err == nil { + addPeer(res.p) + } + logSeed.Infof("discarded routing table candidate due to dial error; peer ID: %s, err: %s, "+ + "falling back: %s", res.p, res.err, fallingBack) + case <-todo.Done(): + if fallingBack { + logSeed.Warningf("unable to seed routing table to target due to failed dials, still missing: %d", left) + return ErrPartialSeed + } + logSeed.Warningf("resorting to fallback peers to fill %d routing table members", left) + goto AddFallbackPeers + case <-ctx.Done(): + if fallingBack { + logSeed.Warningf("unable to seed routing table to target due to slow dials, still missing: %d", left) + return ErrPartialSeed + } + logSeed.Warningf("resorting to fallback peers to fill %d routing table members", left) + goto AddFallbackPeers + } + + AddFallbackPeers: + fallingBack = true + todial = append(todial, fallback...) + todo = todocounter.NewSyncCounter() + todo.Increment(uint32(len(fallback))) + ctx, cancel = context.WithTimeout(context.Background(), SeedDialGracePeriod) + defer cancel() + goto DialCandidates + } + + return nil +} diff --git a/persist/snapshot.go b/persist/snapshot.go new file mode 100644 index 000000000..cb67c711d --- /dev/null +++ b/persist/snapshot.go @@ -0,0 +1,85 @@ +package persist + +import ( + "errors" + "time" + + ds "github.com/ipfs/go-datastore" + nsds "github.com/ipfs/go-datastore/namespace" + dht_pb "github.com/libp2p/go-libp2p-kad-dht/pb" + kb "github.com/libp2p/go-libp2p-kbucket" + peer "github.com/libp2p/go-libp2p-peer" +) + +var ( + dsSnapshotKey = ds.NewKey("routing_table") +) + + +type dsSnapshotter struct { + ds.Datastore +} + +var _ Snapshotter = (*dsSnapshotter)(nil) + +// NewDatastoreSnapshotter returns a Snapshotter backed by a datastore, under the specified non-optional namespace. +func NewDatastoreSnapshotter(dstore ds.Datastore, namespace string) (Snapshotter, error) { + if dstore == nil { + return nil, errors.New("datastore is nil when creating a datastore snapshotter") + } + if namespace == "" { + return nil, errors.New("blank namespace when creating a datastore snapshotter") + } + dstore = nsds.Wrap(dstore, ds.NewKey(namespace)) + return &dsSnapshotter{dstore}, nil +} + +func (dsp *dsSnapshotter) Load() (result []peer.ID, err error) { + val, err := dsp.Get(dsSnapshotKey) + switch err { + case nil: + case ds.ErrNotFound: + return nil, nil + default: + return nil, err + } + + var s dht_pb.RoutingTableSnapshot + if err := s.Unmarshal(val); err != nil { + return nil, err + } + + var pid peer.ID + for _, id := range s.Peers { + if err := pid.Unmarshal(id); err != nil { + logSnapshot.Warningf("encountered invalid peer ID while restoring routing table snapshot; err: %s", err) + continue + } + result = append(result, pid) + } + return result, nil +} + +func (dsp *dsSnapshotter) Store(rt *kb.RoutingTable) error { + var data [][]byte + for _, p := range rt.ListPeers() { + id, err := p.MarshalBinary() + if err != nil { + logSnapshot.Warningf("encountered error with adding peer to routing table snapshot; skipping; err: %s", p, err) + continue + } + data = append(data, id) + } + + snap := dht_pb.RoutingTableSnapshot{ + Peers: data, + Timestamp: time.Now().Unix(), + } + + bytes, err := snap.Marshal() + if err != nil { + return err + } + + return dsp.Put(dsSnapshotKey, bytes) +} diff --git a/providers/providers.go b/providers/providers.go index 78302ca50..ec44cc511 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -7,7 +7,9 @@ import ( "strings" "time" - lru "github.com/hashicorp/golang-lru" + "github.com/libp2p/go-libp2p-core/peer" + + lru "github.com/hashicorp/golang-lru/simplelru" cid "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" autobatch "github.com/ipfs/go-datastore/autobatch" @@ -15,7 +17,6 @@ import ( logging "github.com/ipfs/go-log" goprocess "github.com/jbenet/goprocess" goprocessctx "github.com/jbenet/goprocess/context" - peer "github.com/libp2p/go-libp2p-peer" base32 "github.com/whyrusleeping/base32" ) @@ -30,8 +31,8 @@ var defaultCleanupInterval = time.Hour type ProviderManager struct { // all non channel fields are meant to be accessed only within // the run method - providers *lru.Cache - dstore ds.Datastore + providers *lru.LRU + dstore *autobatch.Datastore newprovs chan *addProv getprovs chan *getProv @@ -60,7 +61,7 @@ func NewProviderManager(ctx context.Context, local peer.ID, dstore ds.Batching) pm.getprovs = make(chan *getProv) pm.newprovs = make(chan *addProv) pm.dstore = autobatch.NewAutoBatching(dstore, batchBufferSize) - cache, err := lru.New(lruCacheSize) + cache, err := lru.NewLRU(lruCacheSize, nil) if err != nil { panic(err) //only happens if negative value is passed to lru constructor } @@ -68,7 +69,7 @@ func NewProviderManager(ctx context.Context, local peer.ID, dstore ds.Batching) pm.proc = goprocessctx.WithContext(ctx) pm.cleanupInterval = defaultCleanupInterval - pm.proc.Go(func(p goprocess.Process) { pm.run() }) + pm.proc.Go(pm.run) return pm } @@ -92,7 +93,7 @@ func (pm *ProviderManager) providersForKey(k cid.Cid) ([]peer.ID, error) { } func (pm *ProviderManager) getProvSet(k cid.Cid) (*providerSet, error) { - cached, ok := pm.providers.Get(k.KeyString()) + cached, ok := pm.providers.Get(k) if ok { return cached.(*providerSet), nil } @@ -103,7 +104,7 @@ func (pm *ProviderManager) getProvSet(k cid.Cid) (*providerSet, error) { } if len(pset.providers) > 0 { - pm.providers.Add(k.KeyString(), pset) + pm.providers.Add(k, pset) } return pset, nil @@ -114,7 +115,9 @@ func loadProvSet(dstore ds.Datastore, k cid.Cid) (*providerSet, error) { if err != nil { return nil, err } + defer res.Close() + now := time.Now() out := newProviderSet() for { e, ok := res.NextSync() @@ -126,58 +129,66 @@ func loadProvSet(dstore ds.Datastore, k cid.Cid) (*providerSet, error) { continue } + // check expiration time + t, err := readTimeValue(e.Value) + switch { + case err != nil: + // couldn't parse the time + log.Warning("parsing providers record from disk: ", err) + fallthrough + case now.Sub(t) > ProvideValidity: + // or just expired + err = dstore.Delete(ds.RawKey(e.Key)) + if err != nil && err != ds.ErrNotFound { + log.Warning("failed to remove provider record from disk: ", err) + } + continue + } + lix := strings.LastIndex(e.Key, "/") decstr, err := base32.RawStdEncoding.DecodeString(e.Key[lix+1:]) if err != nil { log.Error("base32 decoding error: ", err) + err = dstore.Delete(ds.RawKey(e.Key)) + if err != nil && err != ds.ErrNotFound { + log.Warning("failed to remove provider record from disk: ", err) + } continue } pid := peer.ID(decstr) - t, err := readTimeValue(e.Value) - if err != nil { - log.Warning("parsing providers record from disk: ", err) - continue - } - out.setVal(pid, t) } return out, nil } -func readTimeValue(i interface{}) (time.Time, error) { - data, ok := i.([]byte) - if !ok { - return time.Time{}, fmt.Errorf("data was not a []byte") +func readTimeValue(data []byte) (time.Time, error) { + nsec, n := binary.Varint(data) + if n <= 0 { + return time.Time{}, fmt.Errorf("failed to parse time") } - nsec, _ := binary.Varint(data) - return time.Unix(0, nsec), nil } func (pm *ProviderManager) addProv(k cid.Cid, p peer.ID) error { - iprovs, ok := pm.providers.Get(k.KeyString()) - if !ok { - stored, err := loadProvSet(pm.dstore, k) - if err != nil { - return err - } - iprovs = stored - pm.providers.Add(k.KeyString(), iprovs) - } - provs := iprovs.(*providerSet) now := time.Now() - provs.setVal(p, now) + if provs, ok := pm.providers.Get(k); ok { + provs.(*providerSet).setVal(p, now) + } // else not cached, just write through return writeProviderEntry(pm.dstore, k, p, now) } +func mkProvKeyFor(k cid.Cid, p peer.ID) string { + return mkProvKey(k) + "/" + base32.RawStdEncoding.EncodeToString([]byte(p)) +} + func writeProviderEntry(dstore ds.Datastore, k cid.Cid, p peer.ID, t time.Time) error { - dsk := mkProvKey(k) + "/" + base32.RawStdEncoding.EncodeToString([]byte(p)) + dsk := mkProvKeyFor(k, p) buf := make([]byte, 16) n := binary.PutVarint(buf, t.UnixNano()) @@ -185,75 +196,38 @@ func writeProviderEntry(dstore ds.Datastore, k cid.Cid, p peer.ID, t time.Time) return dstore.Put(ds.NewKey(dsk), buf[:n]) } -func (pm *ProviderManager) deleteProvSet(k cid.Cid) error { - pm.providers.Remove(k.KeyString()) - - res, err := pm.dstore.Query(dsq.Query{ - KeysOnly: true, - Prefix: mkProvKey(k), - }) - if err != nil { - return err - } - - entries, err := res.Rest() - if err != nil { - return err - } - - for _, e := range entries { - err := pm.dstore.Delete(ds.NewKey(e.Key)) - if err != nil { - log.Error("deleting provider set: ", err) +func (pm *ProviderManager) run(proc goprocess.Process) { + var ( + gcQuery dsq.Results + gcQueryRes <-chan dsq.Result + gcSkip map[string]struct{} + gcTime time.Time + gcTimer = time.NewTimer(pm.cleanupInterval) + ) + + defer func() { + gcTimer.Stop() + if gcQuery != nil { + // don't really care if this fails. + _ = gcQuery.Close() } - } - return nil -} - -func (pm *ProviderManager) getProvKeys() (func() (cid.Cid, bool), error) { - res, err := pm.dstore.Query(dsq.Query{ - KeysOnly: true, - Prefix: providersKeyPrefix, - }) - if err != nil { - return nil, err - } - - iter := func() (cid.Cid, bool) { - for e := range res.Next() { - parts := strings.Split(e.Key, "/") - if len(parts) != 4 { - log.Warningf("incorrectly formatted provider entry in datastore: %s", e.Key) - continue - } - decoded, err := base32.RawStdEncoding.DecodeString(parts[2]) - if err != nil { - log.Warning("error decoding base32 provider key: %s: %s", parts[2], err) - continue - } - - c, err := cid.Cast(decoded) - if err != nil { - log.Warning("error casting key to cid from datastore key: %s", err) - continue - } - - return c, true + if err := pm.dstore.Flush(); err != nil { + log.Error("failed to flush datastore: ", err) } - return cid.Cid{}, false - } - - return iter, nil -} + }() -func (pm *ProviderManager) run() { - tick := time.NewTicker(pm.cleanupInterval) for { select { case np := <-pm.newprovs: err := pm.addProv(np.k, np.val) if err != nil { log.Error("error adding new providers: ", err) + continue + } + if gcSkip != nil { + // we have an gc, tell it to skip this provider + // as we've updated it since the GC started. + gcSkip[mkProvKeyFor(np.k, np.val)] = struct{}{} } case gp := <-pm.getprovs: provs, err := pm.providersForKey(gp.k) @@ -261,52 +235,71 @@ func (pm *ProviderManager) run() { log.Error("error reading providers: ", err) } - gp.resp <- provs - case <-tick.C: - keys, err := pm.getProvKeys() - if err != nil { - log.Error("Error loading provider keys: ", err) + // set the cap so the user can't append to this. + gp.resp <- provs[0:len(provs):len(provs)] + case res, ok := <-gcQueryRes: + if !ok { + if err := gcQuery.Close(); err != nil { + log.Error("failed to close provider GC query: ", err) + } + gcTimer.Reset(pm.cleanupInterval) + + // cleanup GC round + gcQueryRes = nil + gcSkip = nil + gcQuery = nil + continue + } + if res.Error != nil { + log.Error("got error from GC query: ", res.Error) + continue + } + if _, ok := gcSkip[res.Key]; ok { + // We've updated this record since starting the + // GC round, skip it. continue } - now := time.Now() - for { - k, ok := keys() - if !ok { - break - } - provs, err := pm.getProvSet(k) - if err != nil { - log.Error("error loading known provset: ", err) - continue - } - for p, t := range provs.set { - if now.Sub(t) > ProvideValidity { - delete(provs.set, p) - } - } - // have we run out of providers? - if len(provs.set) == 0 { - provs.providers = nil - err := pm.deleteProvSet(k) - if err != nil { - log.Error("error deleting provider set: ", err) - } - } else if len(provs.set) < len(provs.providers) { - // We must have modified the providers set, recompute. - provs.providers = make([]peer.ID, 0, len(provs.set)) - for p := range provs.set { - provs.providers = append(provs.providers, p) - } + // check expiration time + t, err := readTimeValue(res.Value) + switch { + case err != nil: + // couldn't parse the time + log.Warning("parsing providers record from disk: ", err) + fallthrough + case gcTime.Sub(t) > ProvideValidity: + // or expired + err = pm.dstore.Delete(ds.RawKey(res.Key)) + if err != nil && err != ds.ErrNotFound { + log.Warning("failed to remove provider record from disk: ", err) } } - case <-pm.proc.Closing(): - tick.Stop() + + case gcTime = <-gcTimer.C: + // You know the wonderful thing about caches? You can + // drop them. + // + // Much faster than GCing. + pm.providers.Purge() + + // Now, kick off a GC of the datastore. + q, err := pm.dstore.Query(dsq.Query{ + Prefix: providersKeyPrefix, + }) + if err != nil { + log.Error("provider record GC query failed: ", err) + continue + } + gcQuery = q + gcQueryRes = q.Next() + gcSkip = make(map[string]struct{}) + case <-proc.Closing(): return } } } +// AddProvider adds a provider. func (pm *ProviderManager) AddProvider(ctx context.Context, k cid.Cid, val peer.ID) { prov := &addProv{ k: k, @@ -318,6 +311,8 @@ func (pm *ProviderManager) AddProvider(ctx context.Context, k cid.Cid, val peer. } } +// GetProviders returns the set of providers for the given key. +// This method _does not_ copy the set. Do not modify it. func (pm *ProviderManager) GetProviders(ctx context.Context, k cid.Cid) []peer.ID { gp := &getProv{ k: k, diff --git a/providers/providers_test.go b/providers/providers_test.go index c29b1cf8b..58756c55c 100644 --- a/providers/providers_test.go +++ b/providers/providers_test.go @@ -8,10 +8,13 @@ import ( "testing" "time" + "github.com/libp2p/go-libp2p-core/peer" + cid "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" + dsq "github.com/ipfs/go-datastore/query" + dssync "github.com/ipfs/go-datastore/sync" u "github.com/ipfs/go-ipfs-util" - peer "github.com/libp2p/go-libp2p-peer" // // used by TestLargeProvidersSet: do not remove // lds "github.com/ipfs/go-ds-leveldb" @@ -22,13 +25,21 @@ func TestProviderManager(t *testing.T) { defer cancel() mid := peer.ID("testing") - p := NewProviderManager(ctx, mid, ds.NewMapDatastore()) + p := NewProviderManager(ctx, mid, dssync.MutexWrap(ds.NewMapDatastore())) a := cid.NewCidV0(u.Hash([]byte("test"))) p.AddProvider(ctx, a, peer.ID("testingprovider")) + + // Not cached resp := p.GetProviders(ctx, a) if len(resp) != 1 { t.Fatal("Could not retrieve provider.") } + + // Cached + resp = p.GetProviders(ctx, a) + if len(resp) != 1 { + t.Fatal("Could not retrieve provider.") + } p.proc.Close() } @@ -41,7 +52,7 @@ func TestProvidersDatastore(t *testing.T) { defer cancel() mid := peer.ID("testing") - p := NewProviderManager(ctx, mid, ds.NewMapDatastore()) + p := NewProviderManager(ctx, mid, dssync.MutexWrap(ds.NewMapDatastore())) defer p.proc.Close() friend := peer.ID("friend") @@ -64,7 +75,7 @@ func TestProvidersDatastore(t *testing.T) { } func TestProvidersSerialization(t *testing.T) { - dstore := ds.NewMapDatastore() + dstore := dssync.MutexWrap(ds.NewMapDatastore()) k := cid.NewCidV0(u.Hash(([]byte("my key!")))) p1 := peer.ID("peer one") @@ -119,44 +130,70 @@ func TestProvidesExpire(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + ds := dssync.MutexWrap(ds.NewMapDatastore()) mid := peer.ID("testing") - p := NewProviderManager(ctx, mid, ds.NewMapDatastore()) + p := NewProviderManager(ctx, mid, ds) peers := []peer.ID{"a", "b"} var cids []cid.Cid for i := 0; i < 10; i++ { c := cid.NewCidV0(u.Hash([]byte(fmt.Sprint(i)))) cids = append(cids, c) + } + + for _, c := range cids[:5] { p.AddProvider(ctx, c, peers[0]) p.AddProvider(ctx, c, peers[1]) } - for i := 0; i < 10; i++ { - out := p.GetProviders(ctx, cids[i]) + time.Sleep(time.Second / 4) + + for _, c := range cids[5:] { + p.AddProvider(ctx, c, peers[0]) + p.AddProvider(ctx, c, peers[1]) + } + + for _, c := range cids { + out := p.GetProviders(ctx, c) if len(out) != 2 { t.Fatal("expected providers to still be there") } } - time.Sleep(time.Second) - for i := 0; i < 10; i++ { - out := p.GetProviders(ctx, cids[i]) + time.Sleep(3 * time.Second / 8) + + for _, c := range cids[:5] { + out := p.GetProviders(ctx, c) if len(out) > 0 { t.Fatal("expected providers to be cleaned up, got: ", out) } } + for _, c := range cids[5:] { + out := p.GetProviders(ctx, c) + if len(out) != 2 { + t.Fatal("expected providers to still be there") + } + } + + time.Sleep(time.Second / 2) + + // Stop to prevent data races + p.Process().Close() + if p.providers.Len() != 0 { t.Fatal("providers map not cleaned up") } - proviter, err := p.getProvKeys() + res, err := ds.Query(dsq.Query{Prefix: providersKeyPrefix}) if err != nil { t.Fatal(err) } - - _, ok := proviter() - if ok { + rest, err := res.Rest() + if err != nil { + t.Fatal(err) + } + if len(rest) > 0 { t.Fatal("expected everything to be cleaned out of the datastore") } } @@ -229,8 +266,9 @@ func TestUponCacheMissProvidersAreReadFromDatastore(t *testing.T) { p1, p2 := peer.ID("a"), peer.ID("b") c1 := cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("1"))) c2 := cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("2"))) - pm := NewProviderManager(ctx, p1, ds.NewMapDatastore()) + pm := NewProviderManager(ctx, p1, dssync.MutexWrap(ds.NewMapDatastore())) + // add provider pm.AddProvider(ctx, c1, p1) // make the cached provider for c1 go to datastore pm.AddProvider(ctx, c2, p1) @@ -242,3 +280,24 @@ func TestUponCacheMissProvidersAreReadFromDatastore(t *testing.T) { t.Fatalf("expected c1 to be provided by 2 peers, is by %d", len(c1Provs)) } } + +func TestWriteUpdatesCache(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + p1, p2 := peer.ID("a"), peer.ID("b") + c1 := cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("1"))) + pm := NewProviderManager(ctx, p1, dssync.MutexWrap(ds.NewMapDatastore())) + + // add provider + pm.AddProvider(ctx, c1, p1) + // force into the cache + pm.GetProviders(ctx, c1) + // add a second provider + pm.AddProvider(ctx, c1, p2) + + c1Provs := pm.GetProviders(ctx, c1) + if len(c1Provs) != 2 { + t.Fatalf("expected c1 to be provided by 2 peers, is by %d", len(c1Provs)) + } +} diff --git a/query.go b/query.go index 9e9c35968..c0211a56e 100644 --- a/query.go +++ b/query.go @@ -2,22 +2,27 @@ package dht import ( "context" + "errors" "sync" - u "github.com/ipfs/go-ipfs-util" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + logging "github.com/ipfs/go-log" todoctr "github.com/ipfs/go-todocounter" process "github.com/jbenet/goprocess" ctxproc "github.com/jbenet/goprocess/context" - inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" - pset "github.com/libp2p/go-libp2p-peer/peerset" - pstore "github.com/libp2p/go-libp2p-peerstore" + kb "github.com/libp2p/go-libp2p-kbucket" + + pstore "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/routing" queue "github.com/libp2p/go-libp2p-peerstore/queue" - routing "github.com/libp2p/go-libp2p-routing" notif "github.com/libp2p/go-libp2p-routing/notifications" ) +// ErrNoPeersQueried is returned when we failed to connect to any peers. +var ErrNoPeersQueried = errors.New("failed to query any peers") + var maxQueryConcurrency = AlphaValue type dhtQuery struct { @@ -28,12 +33,12 @@ type dhtQuery struct { } type dhtQueryResult struct { - peer *pstore.PeerInfo // FindPeer - closerPeers []*pstore.PeerInfo // * + peer *peer.AddrInfo // FindPeer + closerPeers []*peer.AddrInfo // * success bool - finalSet *pset.PeerSet - queriedSet *pset.PeerSet + finalSet *peer.Set + queriedSet *peer.Set } // constructs query @@ -55,6 +60,11 @@ type queryFunc func(context.Context, peer.ID) (*dhtQueryResult, error) // Run runs the query at hand. pass in a list of peers to use first. func (q *dhtQuery) Run(ctx context.Context, peers []peer.ID) (*dhtQueryResult, error) { + if len(peers) == 0 { + logger.Warning("Running query with no peers!") + return nil, kb.ErrLookupFailure + } + select { case <-ctx.Done(): return nil, ctx.Err() @@ -70,14 +80,13 @@ func (q *dhtQuery) Run(ctx context.Context, peers []peer.ID) (*dhtQueryResult, e type dhtQueryRunner struct { query *dhtQuery // query to run - peersSeen *pset.PeerSet // all peers queried. prevent querying same peer 2x - peersQueried *pset.PeerSet // peers successfully connected to and queried + peersSeen *peer.Set // all peers queried. prevent querying same peer 2x + peersQueried *peer.Set // peers successfully connected to and queried peersDialed *dialQueue // peers we have dialed to peersToQuery *queue.ChanQueue // peers remaining to be queried peersRemaining todoctr.Counter // peersToQuery + currently processing result *dhtQueryResult // query result - errs u.MultiErr // result errors. maybe should be a map[peer.ID]error rateLimit chan struct{} // processing semaphore log logging.EventLogger @@ -95,8 +104,8 @@ func newQueryRunner(q *dhtQuery) *dhtQueryRunner { r := &dhtQueryRunner{ query: q, peersRemaining: todoctr.NewSyncCounter(), - peersSeen: pset.New(), - peersQueried: pset.New(), + peersSeen: peer.NewSet(), + peersQueried: peer.NewSet(), rateLimit: make(chan struct{}, q.concurrency), peersToQuery: peersToQuery, proc: proc, @@ -119,11 +128,6 @@ func (r *dhtQueryRunner) Run(ctx context.Context, peers []peer.ID) (*dhtQueryRes r.log = logger r.runCtx = ctx - if len(peers) == 0 { - logger.Warning("Running query with no peers!") - return nil, nil - } - // setup concurrency rate limiting for i := 0; i < r.query.concurrency; i++ { r.rateLimit <- struct{}{} @@ -155,23 +159,19 @@ func (r *dhtQueryRunner) Run(ctx context.Context, peers []peer.ID) (*dhtQueryRes select { case <-r.peersRemaining.Done(): r.proc.Close() - r.RLock() - defer r.RUnlock() - - err = routing.ErrNotFound - - // if every query to every peer failed, something must be very wrong. - if len(r.errs) > 0 && len(r.errs) == r.peersSeen.Size() { - logger.Debugf("query errs: %s", r.errs) - err = r.errs[0] + if r.peersQueried.Size() == 0 { + err = ErrNoPeersQueried + } else { + err = routing.ErrNotFound } case <-r.proc.Closed(): - r.RLock() - defer r.RUnlock() err = r.runCtx.Err() } + r.RLock() + defer r.RUnlock() + if r.result != nil && r.result.success { return r.result, nil } @@ -238,7 +238,7 @@ func (r *dhtQueryRunner) spawnWorkers(proc process.Process) { func (r *dhtQueryRunner) dialPeer(ctx context.Context, p peer.ID) error { // short-circuit if we're already connected. - if r.query.dht.host.Network().Connectedness(p) == inet.Connected { + if r.query.dht.host.Network().Connectedness(p) == network.Connected { return nil } @@ -248,7 +248,7 @@ func (r *dhtQueryRunner) dialPeer(ctx context.Context, p peer.ID) error { ID: p, }) - pi := pstore.PeerInfo{ID: p} + pi := peer.AddrInfo{ID: p} if err := r.query.dht.host.Connect(ctx, pi); err != nil { logger.Debugf("error connecting: %s", err) notif.PublishQueryEvent(r.runCtx, ¬if.QueryEvent{ @@ -257,10 +257,6 @@ func (r *dhtQueryRunner) dialPeer(ctx context.Context, p peer.ID) error { ID: p, }) - r.Lock() - r.errs = append(r.errs, err) - r.Unlock() - // This peer is dropping out of the race. r.peersRemaining.Decrement(1) return err @@ -289,10 +285,6 @@ func (r *dhtQueryRunner) queryPeer(proc process.Process, p peer.ID) { if err != nil { logger.Debugf("ERROR worker for: %v %v", p, err) - r.Lock() - r.errs = append(r.errs, err) - r.Unlock() - } else if res.success { logger.Debugf("SUCCESS worker for: %v %s", p, res) r.Lock() diff --git a/records.go b/records.go index 5e508dbaf..5f641b056 100644 --- a/records.go +++ b/records.go @@ -5,9 +5,10 @@ import ( "fmt" "time" - ci "github.com/libp2p/go-libp2p-crypto" - peer "github.com/libp2p/go-libp2p-peer" - routing "github.com/libp2p/go-libp2p-routing" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/routing" + + ci "github.com/libp2p/go-libp2p-core/crypto" ) // MaxRecordAge specifies the maximum time that any node will hold onto a record diff --git a/records_test.go b/records_test.go index efe773920..cf0dee969 100644 --- a/records_test.go +++ b/records_test.go @@ -6,11 +6,12 @@ import ( "testing" "time" + ci "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/routing" + u "github.com/ipfs/go-ipfs-util" - ci "github.com/libp2p/go-libp2p-crypto" - peer "github.com/libp2p/go-libp2p-peer" record "github.com/libp2p/go-libp2p-record" - routing "github.com/libp2p/go-libp2p-routing" ) // Check that GetPublicKey() correctly extracts a public key diff --git a/routing.go b/routing.go index 585196c11..bf3ec4d49 100644 --- a/routing.go +++ b/routing.go @@ -8,19 +8,17 @@ import ( "sync" "time" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/routing" + cid "github.com/ipfs/go-cid" u "github.com/ipfs/go-ipfs-util" logging "github.com/ipfs/go-log" pb "github.com/libp2p/go-libp2p-kad-dht/pb" kb "github.com/libp2p/go-libp2p-kbucket" - inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" - pset "github.com/libp2p/go-libp2p-peer/peerset" - pstore "github.com/libp2p/go-libp2p-peerstore" record "github.com/libp2p/go-libp2p-record" - routing "github.com/libp2p/go-libp2p-routing" - notif "github.com/libp2p/go-libp2p-routing/notifications" - ropts "github.com/libp2p/go-libp2p-routing/options" ) // asyncQueryBuffer is the size of buffered channels in async queries. This @@ -35,7 +33,7 @@ var asyncQueryBuffer = 10 // PutValue adds value corresponding to given Key. // This is the top level "Store" operation of the DHT -func (dht *IpfsDHT) PutValue(ctx context.Context, key string, value []byte, opts ...ropts.Option) (err error) { +func (dht *IpfsDHT) PutValue(ctx context.Context, key string, value []byte, opts ...routing.Option) (err error) { eip := logger.EventBegin(ctx, "PutValue") defer func() { eip.Append(loggableKey(key)) @@ -88,8 +86,8 @@ func (dht *IpfsDHT) PutValue(ctx context.Context, key string, value []byte, opts ctx, cancel := context.WithCancel(ctx) defer cancel() defer wg.Done() - notif.PublishQueryEvent(ctx, ¬if.QueryEvent{ - Type: notif.Value, + routing.PublishQueryEvent(ctx, &routing.QueryEvent{ + Type: routing.Value, ID: p, }) @@ -110,7 +108,7 @@ type RecvdVal struct { } // GetValue searches for the value corresponding to given Key. -func (dht *IpfsDHT) GetValue(ctx context.Context, key string, opts ...ropts.Option) (_ []byte, err error) { +func (dht *IpfsDHT) GetValue(ctx context.Context, key string, opts ...routing.Option) (_ []byte, err error) { eip := logger.EventBegin(ctx, "GetValue") defer func() { eip.Append(loggableKey(key)) @@ -121,7 +119,7 @@ func (dht *IpfsDHT) GetValue(ctx context.Context, key string, opts ...ropts.Opti }() // apply defaultQuorum if relevant - var cfg ropts.Options + var cfg routing.Options if err := cfg.Apply(opts...); err != nil { return nil, err } @@ -148,8 +146,8 @@ func (dht *IpfsDHT) GetValue(ctx context.Context, key string, opts ...ropts.Opti return best, nil } -func (dht *IpfsDHT) SearchValue(ctx context.Context, key string, opts ...ropts.Option) (<-chan []byte, error) { - var cfg ropts.Options +func (dht *IpfsDHT) SearchValue(ctx context.Context, key string, opts ...routing.Option) (<-chan []byte, error) { + var cfg routing.Options if err := cfg.Apply(opts...); err != nil { return nil, err } @@ -316,8 +314,8 @@ func (dht *IpfsDHT) getValues(ctx context.Context, key string, nvals int) (<-cha // setup the Query parent := ctx query := dht.newQuery(key, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) { - notif.PublishQueryEvent(parent, ¬if.QueryEvent{ - Type: notif.SendingQuery, + routing.PublishQueryEvent(parent, &routing.QueryEvent{ + Type: routing.SendingQuery, ID: p, }) @@ -327,8 +325,8 @@ func (dht *IpfsDHT) getValues(ctx context.Context, key string, nvals int) (<-cha // in this case, they responded with nothing, // still send a notification so listeners can know the // request has completed 'successfully' - notif.PublishQueryEvent(parent, ¬if.QueryEvent{ - Type: notif.PeerResponse, + routing.PublishQueryEvent(parent, &routing.QueryEvent{ + Type: routing.PeerResponse, ID: p, }) return nil, err @@ -362,8 +360,8 @@ func (dht *IpfsDHT) getValues(ctx context.Context, key string, nvals int) (<-cha valslock.Unlock() } - notif.PublishQueryEvent(parent, ¬if.QueryEvent{ - Type: notif.PeerResponse, + routing.PublishQueryEvent(parent, &routing.QueryEvent{ + Type: routing.PeerResponse, ID: p, Responses: peers, }) @@ -410,7 +408,28 @@ func (dht *IpfsDHT) Provide(ctx context.Context, key cid.Cid, brdcst bool) (err return nil } - peers, err := dht.GetClosestPeers(ctx, key.KeyString()) + closerCtx := ctx + if deadline, ok := ctx.Deadline(); ok { + now := time.Now() + timeout := deadline.Sub(now) + + if timeout < 0 { + // timed out + return context.DeadlineExceeded + } else if timeout < 10*time.Second { + // Reserve 10% for the final put. + deadline = deadline.Add(timeout / 10) + } else { + // Otherwise, reserve a second (we'll already be + // connected so this should be fast). + deadline = deadline.Add(-time.Second) + } + var cancel context.CancelFunc + closerCtx, cancel = context.WithDeadline(ctx, deadline) + defer cancel() + } + + peers, err := dht.GetClosestPeers(closerCtx, key.KeyString()) if err != nil { return err } @@ -436,7 +455,7 @@ func (dht *IpfsDHT) Provide(ctx context.Context, key cid.Cid, brdcst bool) (err return nil } func (dht *IpfsDHT) makeProvRecord(skey cid.Cid) (*pb.Message, error) { - pi := pstore.PeerInfo{ + pi := peer.AddrInfo{ ID: dht.self, Addrs: dht.host.Addrs(), } @@ -448,13 +467,13 @@ func (dht *IpfsDHT) makeProvRecord(skey cid.Cid) (*pb.Message, error) { } pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, skey.Bytes(), 0) - pmes.ProviderPeers = pb.RawPeerInfosToPBPeers([]pstore.PeerInfo{pi}) + pmes.ProviderPeers = pb.RawPeerInfosToPBPeers([]peer.AddrInfo{pi}) return pmes, nil } // FindProviders searches until the context expires. -func (dht *IpfsDHT) FindProviders(ctx context.Context, c cid.Cid) ([]pstore.PeerInfo, error) { - var providers []pstore.PeerInfo +func (dht *IpfsDHT) FindProviders(ctx context.Context, c cid.Cid) ([]peer.AddrInfo, error) { + var providers []peer.AddrInfo for p := range dht.FindProvidersAsync(ctx, c, KValue) { providers = append(providers, p) } @@ -464,18 +483,18 @@ func (dht *IpfsDHT) FindProviders(ctx context.Context, c cid.Cid) ([]pstore.Peer // FindProvidersAsync is the same thing as FindProviders, but returns a channel. // Peers will be returned on the channel as soon as they are found, even before // the search query completes. -func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key cid.Cid, count int) <-chan pstore.PeerInfo { +func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key cid.Cid, count int) <-chan peer.AddrInfo { logger.Event(ctx, "findProviders", key) - peerOut := make(chan pstore.PeerInfo, count) + peerOut := make(chan peer.AddrInfo, count) go dht.findProvidersAsyncRoutine(ctx, key, count, peerOut) return peerOut } -func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key cid.Cid, count int, peerOut chan pstore.PeerInfo) { +func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key cid.Cid, count int, peerOut chan peer.AddrInfo) { defer logger.EventBegin(ctx, "findProvidersAsync", key).Done() defer close(peerOut) - ps := pset.NewLimited(count) + ps := peer.NewLimitedSet(count) provs := dht.providers.GetProviders(ctx, key) for _, p := range provs { // NOTE: Assuming that this list of peers is unique @@ -495,11 +514,20 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key cid.Cid, } } + peers := dht.routingTable.NearestPeers(kb.ConvertKey(key.KeyString()), AlphaValue) + if len(peers) == 0 { + routing.PublishQueryEvent(ctx, &routing.QueryEvent{ + Type: routing.QueryError, + Extra: kb.ErrLookupFailure.Error(), + }) + return + } + // setup the Query parent := ctx query := dht.newQuery(key.KeyString(), func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) { - notif.PublishQueryEvent(parent, ¬if.QueryEvent{ - Type: notif.SendingQuery, + routing.PublishQueryEvent(parent, &routing.QueryEvent{ + Type: routing.SendingQuery, ID: p, }) pmes, err := dht.findProvidersSingle(ctx, p, key) @@ -514,7 +542,7 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key cid.Cid, // Add unique providers from request, up to 'count' for _, prov := range provs { if prov.ID != dht.self { - dht.peerstore.AddAddrs(prov.ID, prov.Addrs, pstore.TempAddrTTL) + dht.peerstore.AddAddrs(prov.ID, prov.Addrs, peerstore.TempAddrTTL) } logger.Debugf("got provider: %s", prov) if ps.TryAdd(prov.ID) { @@ -537,15 +565,14 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key cid.Cid, clpeers := pb.PBPeersToPeerInfos(closer) logger.Debugf("got closer peers: %d %s", len(clpeers), clpeers) - notif.PublishQueryEvent(parent, ¬if.QueryEvent{ - Type: notif.PeerResponse, + routing.PublishQueryEvent(parent, &routing.QueryEvent{ + Type: routing.PeerResponse, ID: p, Responses: clpeers, }) return &dhtQueryResult{closerPeers: clpeers}, nil }) - peers := dht.routingTable.NearestPeers(kb.ConvertKey(key.KeyString()), AlphaValue) _, err := query.Run(ctx, peers) if err != nil { logger.Debugf("Query error: %s", err) @@ -559,15 +586,15 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key cid.Cid, // replace problematic error with something that won't crash the daemon err = fmt.Errorf("") } - notif.PublishQueryEvent(ctx, ¬if.QueryEvent{ - Type: notif.QueryError, + routing.PublishQueryEvent(ctx, &routing.QueryEvent{ + Type: routing.QueryError, Extra: err.Error(), }) } } // FindPeer searches for a peer with given ID. -func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (_ pstore.PeerInfo, err error) { +func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (_ peer.AddrInfo, err error) { eip := logger.EventBegin(ctx, "FindPeer", id) defer func() { if err != nil { @@ -583,7 +610,7 @@ func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (_ pstore.PeerInfo peers := dht.routingTable.NearestPeers(kb.ConvertPeerID(id), AlphaValue) if len(peers) == 0 { - return pstore.PeerInfo{}, kb.ErrLookupFailure + return peer.AddrInfo{}, kb.ErrLookupFailure } // Sanity... @@ -597,8 +624,8 @@ func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (_ pstore.PeerInfo // setup the Query parent := ctx query := dht.newQuery(string(id), func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) { - notif.PublishQueryEvent(parent, ¬if.QueryEvent{ - Type: notif.SendingQuery, + routing.PublishQueryEvent(parent, &routing.QueryEvent{ + Type: routing.SendingQuery, ID: p, }) @@ -620,8 +647,8 @@ func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (_ pstore.PeerInfo } } - notif.PublishQueryEvent(parent, ¬if.QueryEvent{ - Type: notif.PeerResponse, + routing.PublishQueryEvent(parent, &routing.QueryEvent{ + Type: routing.PeerResponse, ID: p, Responses: clpeerInfos, }) @@ -632,21 +659,21 @@ func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (_ pstore.PeerInfo // run it! result, err := query.Run(ctx, peers) if err != nil { - return pstore.PeerInfo{}, err + return peer.AddrInfo{}, err } logger.Debugf("FindPeer %v %v", id, result.success) if result.peer.ID == "" { - return pstore.PeerInfo{}, routing.ErrNotFound + return peer.AddrInfo{}, routing.ErrNotFound } return *result.peer, nil } // FindPeersConnectedToPeer searches for peers directly connected to a given peer. -func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (<-chan *pstore.PeerInfo, error) { +func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (<-chan *peer.AddrInfo, error) { - peerchan := make(chan *pstore.PeerInfo, asyncQueryBuffer) + peerchan := make(chan *peer.AddrInfo, asyncQueryBuffer) peersSeen := make(map[peer.ID]struct{}) var peersSeenMx sync.Mutex @@ -663,7 +690,7 @@ func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (< return nil, err } - var clpeers []*pstore.PeerInfo + var clpeers []*peer.AddrInfo closer := pmes.GetCloserPeers() for _, pbp := range closer { pi := pb.PBPeerToPeerInfo(pbp) @@ -678,7 +705,7 @@ func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (< peersSeenMx.Unlock() // if peer is connected, send it to our client. - if pb.Connectedness(pbp.Connection) == inet.Connected { + if pb.Connectedness(pbp.Connection) == network.Connected { select { case <-ctx.Done(): return nil, ctx.Err() @@ -688,7 +715,7 @@ func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (< // if peer is the peer we're looking for, don't bother querying it. // TODO maybe query it? - if pb.Connectedness(pbp.Connection) != inet.Connected { + if pb.Connectedness(pbp.Connection) != network.Connected { clpeers = append(clpeers, pi) } } diff --git a/routing_options.go b/routing_options.go index 46083ea56..591ce54c4 100644 --- a/routing_options.go +++ b/routing_options.go @@ -1,8 +1,6 @@ package dht -import ( - ropts "github.com/libp2p/go-libp2p-routing/options" -) +import "github.com/libp2p/go-libp2p-core/routing" type quorumOptionKey struct{} @@ -12,8 +10,8 @@ const defaultQuorum = 16 // values from before returning the best one. // // Default: 16 -func Quorum(n int) ropts.Option { - return func(opts *ropts.Options) error { +func Quorum(n int) routing.Option { + return func(opts *routing.Options) error { if opts.Other == nil { opts.Other = make(map[interface{}]interface{}, 1) } @@ -22,7 +20,7 @@ func Quorum(n int) ropts.Option { } } -func getQuorum(opts *ropts.Options, ndefault int) int { +func getQuorum(opts *routing.Options, ndefault int) int { responsesNeeded, ok := opts.Other[quorumOptionKey{}].(int) if !ok { responsesNeeded = ndefault