From 3498b676a6cd26f1b7011bec3b168a6e6062c75e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 28 Apr 2018 17:14:58 -0400 Subject: [PATCH] update spec and addrbook.go --- docs/specification/new-spec/p2p/node.md | 2 +- docs/specification/new-spec/p2p/peer.md | 21 +++++++------ .../new-spec/reactors/pex/pex.md | 5 +-- p2p/pex/addrbook.go | 31 ++++++------------- p2p/pex/errors.go | 9 ------ 5 files changed, 24 insertions(+), 44 deletions(-) diff --git a/docs/specification/new-spec/p2p/node.md b/docs/specification/new-spec/p2p/node.md index 589e3b436..c54cfeb32 100644 --- a/docs/specification/new-spec/p2p/node.md +++ b/docs/specification/new-spec/p2p/node.md @@ -12,7 +12,7 @@ Seeds should operate full nodes with the PEX reactor in a "crawler" mode that continuously explores to validate the availability of peers. Seeds should only respond with some top percentile of the best peers it knows about. -See [reputation](TODO) for details on peer quality. +See [the peer-exchange docs](/docs/specification/new-spec/reactors/pex/pex.md)for details on peer quality. ## New Full Node diff --git a/docs/specification/new-spec/p2p/peer.md b/docs/specification/new-spec/p2p/peer.md index 6aa36af79..b2808a60b 100644 --- a/docs/specification/new-spec/p2p/peer.md +++ b/docs/specification/new-spec/p2p/peer.md @@ -2,24 +2,23 @@ This document explains how Tendermint Peers are identified and how they connect to one another. -For details on peer discovery, see the [peer exchange (PEX) reactor doc](pex.md). +For details on peer discovery, see the [peer exchange (PEX) reactor doc](/docs/specification/new-spec/reactors/pex/pex.md). ## Peer Identity Tendermint peers are expected to maintain long-term persistent identities in the form of a public key. Each peer has an ID defined as `peer.ID == peer.PubKey.Address()`, where `Address` uses the scheme defined in go-crypto. -A single peer ID can have multiple IP addresses associated with it. -TODO: define how to deal with this. +A single peer ID can have multiple IP addresses associated with it, but a node +will only ever connect to one at a time. When attempting to connect to a peer, we use the PeerURL: `@:`. We will attempt to connect to the peer at IP:PORT, and verify, via authenticated encryption, that it is in possession of the private key corresponding to ``. This prevents man-in-the-middle attacks on the peer layer. -Peers can also be connected to without specifying an ID, ie. just `:`. -In this case, the peer must be authenticated out-of-band of Tendermint, -for instance via VPN. +If `auth_enc = false`, peers can use an arbitrary ID, but they must always use +one. Authentication can then happen out-of-band of Tendermint, for instance via VPN. ## Connections @@ -84,12 +83,13 @@ The Tendermint Version Handshake allows the peers to exchange their NodeInfo: ```golang type NodeInfo struct { ID p2p.ID - Moniker string - Network string - RemoteAddr string ListenAddr string + + Network string Version string Channels []int8 + + Moniker string Other []string } ``` @@ -98,9 +98,10 @@ The connection is disconnected if: - `peer.NodeInfo.ID` is not equal `peerConn.ID` - `peer.NodeInfo.Version` is not formatted as `X.X.X` where X are integers known as Major, Minor, and Revision - `peer.NodeInfo.Version` Major is not the same as ours -- `peer.NodeInfo.Version` Minor is not the same as ours - `peer.NodeInfo.Network` is not the same as ours - `peer.Channels` does not intersect with our known Channels. +- `peer.NodeInfo.ListenAddr` is malformed or is a DNS host that cannot be + resolved At this point, if we have not disconnected, the peer is valid. diff --git a/docs/specification/new-spec/reactors/pex/pex.md b/docs/specification/new-spec/reactors/pex/pex.md index d24271ebf..1c0ba1c3d 100644 --- a/docs/specification/new-spec/reactors/pex/pex.md +++ b/docs/specification/new-spec/reactors/pex/pex.md @@ -31,8 +31,9 @@ we try the seeds again. ## Listening -Peers listen on a configurable ListenAddr that they self-report during -handshakes with other peers. +Peers listen on a configurable ListenAddr that they self-report in their +NodeInfo during handshakes with other peers. Peers accept up to (MaxNumPeers - +MinNumOutboundPeers) incoming peers. ## Address Book diff --git a/p2p/pex/addrbook.go b/p2p/pex/addrbook.go index a93773472..e34bd5ab9 100644 --- a/p2p/pex/addrbook.go +++ b/p2p/pex/addrbook.go @@ -493,11 +493,11 @@ func (a *addrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAd // Adds ka to new bucket. Returns false if it couldn't do it cuz buckets full. // NOTE: currently it always returns true. -func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) bool { +func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) { // Sanity check if ka.isOld() { - a.Logger.Error(cmn.Fmt("Cannot add address already in old bucket to a new bucket: %v", ka)) - return false + a.Logger.Error("Failed Sanity Check! Cant add old address to new bucket", "ka", knownAddress, "bucket", bucketIdx) + return } addrStr := ka.Addr.String() @@ -505,7 +505,7 @@ func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) bool { // Already exists? if _, ok := bucket[addrStr]; ok { - return true + return } // Enforce max addresses. @@ -523,8 +523,6 @@ func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) bool { // Add it to addrLookup a.addrLookup[ka.ID()] = ka - - return true } // Adds ka to old bucket. Returns false if it couldn't do it cuz buckets full. @@ -627,7 +625,6 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error { } ka := a.addrLookup[addr.ID] - if ka != nil { // Already old. if ka.isOld() { @@ -647,10 +644,7 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error { } bucket := a.calcNewBucket(addr, src) - added := a.addToNewBucket(ka, bucket) - if !added { - return ErrAddrBookFull{addr, a.size()} - } + a.addToNewBucket(ka, bucket) return nil } @@ -696,20 +690,13 @@ func (a *addrBook) moveToOld(ka *knownAddress) { oldBucketIdx := a.calcOldBucket(ka.Addr) added := a.addToOldBucket(ka, oldBucketIdx) if !added { - // No room, must evict something + // No room; move the oldest to a new bucket oldest := a.pickOldest(bucketTypeOld, oldBucketIdx) a.removeFromBucket(oldest, bucketTypeOld, oldBucketIdx) - // Find new bucket to put oldest in newBucketIdx := a.calcNewBucket(oldest.Addr, oldest.Src) - added := a.addToNewBucket(oldest, newBucketIdx) - // No space in newBucket either, just put it in freedBucket from above. - if !added { - added := a.addToNewBucket(oldest, freedBucket) - if !added { - a.Logger.Error(cmn.Fmt("Could not migrate oldest %v to freedBucket %v", oldest, freedBucket)) - } - } - // Finally, add to bucket again. + a.addToNewBucket(oldest, newBucketIdx) + + // Finally, add our ka to old bucket again. added = a.addToOldBucket(ka, oldBucketIdx) if !added { a.Logger.Error(cmn.Fmt("Could not re-add ka %v to oldBucketIdx %v", ka, oldBucketIdx)) diff --git a/p2p/pex/errors.go b/p2p/pex/errors.go index 6d5451e3f..0b8bf4715 100644 --- a/p2p/pex/errors.go +++ b/p2p/pex/errors.go @@ -30,12 +30,3 @@ type ErrAddrBookNilAddr struct { func (err ErrAddrBookNilAddr) Error() string { return fmt.Sprintf("Cannot add a nil address. Got (addr, src) = (%v, %v)", err.Addr, err.Src) } - -type ErrAddrBookFull struct { - Addr *p2p.NetAddress - Size int -} - -func (err ErrAddrBookFull) Error() string { - return fmt.Sprintf("Can't add new address (%v), addr book is full (%d)", err.Addr, err.Size) -}