Browse Source

update spec and addrbook.go

pull/1519/head
Ethan Buchman 6 years ago
parent
commit
3498b676a6
5 changed files with 24 additions and 44 deletions
  1. +1
    -1
      docs/specification/new-spec/p2p/node.md
  2. +11
    -10
      docs/specification/new-spec/p2p/peer.md
  3. +3
    -2
      docs/specification/new-spec/reactors/pex/pex.md
  4. +9
    -22
      p2p/pex/addrbook.go
  5. +0
    -9
      p2p/pex/errors.go

+ 1
- 1
docs/specification/new-spec/p2p/node.md View File

@ -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. that continuously explores to validate the availability of peers.
Seeds should only respond with some top percentile of the best peers it knows about. 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 ## New Full Node


+ 11
- 10
docs/specification/new-spec/p2p/peer.md View File

@ -2,24 +2,23 @@
This document explains how Tendermint Peers are identified and how they connect to one another. 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 ## Peer Identity
Tendermint peers are expected to maintain long-term persistent identities in the form of a public key. 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. 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: `<ID>@<IP>:<PORT>`. When attempting to connect to a peer, we use the PeerURL: `<ID>@<IP>:<PORT>`.
We will attempt to connect to the peer at IP:PORT, and verify, 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 via authenticated encryption, that it is in possession of the private key
corresponding to `<ID>`. This prevents man-in-the-middle attacks on the peer layer. corresponding to `<ID>`. This prevents man-in-the-middle attacks on the peer layer.
Peers can also be connected to without specifying an ID, ie. just `<IP>:<PORT>`.
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 ## Connections
@ -84,12 +83,13 @@ The Tendermint Version Handshake allows the peers to exchange their NodeInfo:
```golang ```golang
type NodeInfo struct { type NodeInfo struct {
ID p2p.ID ID p2p.ID
Moniker string
Network string
RemoteAddr string
ListenAddr string ListenAddr string
Network string
Version string Version string
Channels []int8 Channels []int8
Moniker string
Other []string Other []string
} }
``` ```
@ -98,9 +98,10 @@ The connection is disconnected if:
- `peer.NodeInfo.ID` is not equal `peerConn.ID` - `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` 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` 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.NodeInfo.Network` is not the same as ours
- `peer.Channels` does not intersect with our known Channels. - `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. At this point, if we have not disconnected, the peer is valid.


+ 3
- 2
docs/specification/new-spec/reactors/pex/pex.md View File

@ -31,8 +31,9 @@ we try the seeds again.
## Listening ## 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 ## Address Book


+ 9
- 22
p2p/pex/addrbook.go View File

@ -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. // Adds ka to new bucket. Returns false if it couldn't do it cuz buckets full.
// NOTE: currently it always returns true. // 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 // Sanity check
if ka.isOld() { 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() addrStr := ka.Addr.String()
@ -505,7 +505,7 @@ func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) bool {
// Already exists? // Already exists?
if _, ok := bucket[addrStr]; ok { if _, ok := bucket[addrStr]; ok {
return true
return
} }
// Enforce max addresses. // Enforce max addresses.
@ -523,8 +523,6 @@ func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) bool {
// Add it to addrLookup // Add it to addrLookup
a.addrLookup[ka.ID()] = ka a.addrLookup[ka.ID()] = ka
return true
} }
// Adds ka to old bucket. Returns false if it couldn't do it cuz buckets full. // 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] ka := a.addrLookup[addr.ID]
if ka != nil { if ka != nil {
// Already old. // Already old.
if ka.isOld() { if ka.isOld() {
@ -647,10 +644,7 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error {
} }
bucket := a.calcNewBucket(addr, src) bucket := a.calcNewBucket(addr, src)
added := a.addToNewBucket(ka, bucket)
if !added {
return ErrAddrBookFull{addr, a.size()}
}
a.addToNewBucket(ka, bucket)
return nil return nil
} }
@ -696,20 +690,13 @@ func (a *addrBook) moveToOld(ka *knownAddress) {
oldBucketIdx := a.calcOldBucket(ka.Addr) oldBucketIdx := a.calcOldBucket(ka.Addr)
added := a.addToOldBucket(ka, oldBucketIdx) added := a.addToOldBucket(ka, oldBucketIdx)
if !added { if !added {
// No room, must evict something
// No room; move the oldest to a new bucket
oldest := a.pickOldest(bucketTypeOld, oldBucketIdx) oldest := a.pickOldest(bucketTypeOld, oldBucketIdx)
a.removeFromBucket(oldest, bucketTypeOld, oldBucketIdx) a.removeFromBucket(oldest, bucketTypeOld, oldBucketIdx)
// Find new bucket to put oldest in
newBucketIdx := a.calcNewBucket(oldest.Addr, oldest.Src) 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) added = a.addToOldBucket(ka, oldBucketIdx)
if !added { if !added {
a.Logger.Error(cmn.Fmt("Could not re-add ka %v to oldBucketIdx %v", ka, oldBucketIdx)) a.Logger.Error(cmn.Fmt("Could not re-add ka %v to oldBucketIdx %v", ka, oldBucketIdx))


+ 0
- 9
p2p/pex/errors.go View File

@ -30,12 +30,3 @@ type ErrAddrBookNilAddr struct {
func (err ErrAddrBookNilAddr) Error() string { func (err ErrAddrBookNilAddr) Error() string {
return fmt.Sprintf("Cannot add a nil address. Got (addr, src) = (%v, %v)", err.Addr, err.Src) 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)
}

Loading…
Cancel
Save