From 03a14d834284900af5184b9c7f2e261ecdbb2ae2 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 9 Jan 2018 12:44:49 -0500 Subject: [PATCH] docs/p2p: updates from review (#1076) --- docs/specification/new-spec/p2p/config.md | 8 ++-- docs/specification/new-spec/p2p/connection.md | 38 ++++++++----------- docs/specification/new-spec/p2p/node.md | 7 +++- docs/specification/new-spec/p2p/peer.md | 32 +++++++--------- 4 files changed, 38 insertions(+), 47 deletions(-) diff --git a/docs/specification/new-spec/p2p/config.md b/docs/specification/new-spec/p2p/config.md index bc3c343c..565f7800 100644 --- a/docs/specification/new-spec/p2p/config.md +++ b/docs/specification/new-spec/p2p/config.md @@ -6,14 +6,14 @@ Here we describe configuration options around the Peer Exchange. `--p2p.seed_mode` -The node operates in seed mode. It will kick incoming peers after sharing some peers. -It will continually crawl the network for peers. +The node operates in seed mode. In seed mode, a node continuously crawls the network for peers, +and upon incoming connection shares some peers and disconnects. ## Seeds `--p2p.seeds “1.2.3.4:466656,2.3.4.5:4444”` -Dials these seeds when we need more peers. They will return a list of peers and then disconnect. +Dials these seeds when we need more peers. They should return a list of peers and then disconnect. If we already have enough peers in the address book, we may never need to dial them. ## Persistent Peers @@ -27,7 +27,7 @@ anchor us in the p2p network. Note that the auto-redial uses exponential backoff and will give up after a day of trying to connect. -NOTE: If `dial_seeds` and `persistent_peers` intersect, +NOTE: If `seeds` and `persistent_peers` intersect, the user will be WARNED that seeds may auto-close connections and the node may not be able to keep the connection persistent. diff --git a/docs/specification/new-spec/p2p/connection.md b/docs/specification/new-spec/p2p/connection.md index 72847fa1..dfe0d090 100644 --- a/docs/specification/new-spec/p2p/connection.md +++ b/docs/specification/new-spec/p2p/connection.md @@ -1,12 +1,14 @@ +## P2P Multiplex Connection + +... + ## MConnection -`MConnection` is a multiplex connection: - -__multiplex__ *noun* a system or signal involving simultaneous transmission of -several messages along a single channel of communication. - -Each `MConnection` handles message transmission on multiple abstract communication -`Channel`s. Each channel has a globally unique byte id. +`MConnection` is a multiplex connection that supports multiple independent streams +with distinct quality of service guarantees atop a single TCP connection. +Each stream is known as a `Channel` and each `Channel` has a globally unique byte id. +Each `Channel` also has a relative priority that determines the quality of service +of the `Channel` in comparison to the others. The byte id and the relative priorities of each `Channel` are configured upon initialization of the connection. @@ -14,12 +16,13 @@ The `MConnection` supports three packet types: Ping, Pong, and Msg. ### Ping and Pong -The ping and pong messages consist of writing a single byte to the connection; 0x1 and 0x2, respectively +The ping and pong messages consist of writing a single byte to the connection; 0x1 and 0x2, respectively. When we haven't received any messages on an `MConnection` in a time `pingTimeout`, we send a ping message. -When a ping is received on the `MConnection`, a pong is sent in response. +When a ping is received on the `MConnection`, a pong is sent in response only if there are no other messages +to send and the peer has not sent us too many pings. -If a pong is not received in sufficient time, the peer's score should be decremented (TODO). +If a pong or message is not received in sufficient time after a ping, disconnect from the peer. ### Msg @@ -57,8 +60,8 @@ func (m MConnection) TrySend(chID byte, msg interface{}) bool {} for the channel with the given id byte `chID`. The message `msg` is serialized using the `tendermint/wire` submodule's `WriteBinary()` reflection routine. -`TrySend(chID, msg)` is a nonblocking call that returns false if the channel's -queue is full. +`TrySend(chID, msg)` is a nonblocking call that queues the message msg in the channel +with the given id byte chID if the queue is not full; otherwise it returns false immediately. `Send()` and `TrySend()` are also exposed for each `Peer`. @@ -103,14 +106,3 @@ for _, peer := range switch.Peers().List() { } } ``` - -### PexReactor/AddrBook - -A `PEXReactor` reactor implementation is provided to automate peer discovery. - -```go -book := p2p.NewAddrBook(addrBookFilePath) -pexReactor := p2p.NewPEXReactor(book) -... -switch := NewSwitch([]Reactor{pexReactor, myReactor, ...}) -``` diff --git a/docs/specification/new-spec/p2p/node.md b/docs/specification/new-spec/p2p/node.md index 9f9fc529..0ab8e508 100644 --- a/docs/specification/new-spec/p2p/node.md +++ b/docs/specification/new-spec/p2p/node.md @@ -39,8 +39,10 @@ A node checks its address book on startup and attempts to connect to peers from If it can't connect to any peers after some time, it falls back to the seeds to find more. Restarted full nodes can run the `blockchain` or `consensus` reactor protocols to sync up -to the latest state of the blockchain, assuming they aren't too far behind. -If they are too far behind, they may need to validate a recent `H` and `HASH` out-of-band again. +to the latest state of the blockchain from wherever they were last. +In a Proof-of-Stake context, if they are sufficiently far behind (greater than the length +of the unbonding period), they will need to validate a recent `H` and `HASH` out-of-band again +so they know they have synced the correct chain. ## Validator Node @@ -54,6 +56,7 @@ Validators that know and trust each other can accept incoming connections from o ## Sentry Node Sentry nodes are guardians of a validator node and provide it access to the rest of the network. +They should be well connected to other full nodes on the network. Sentry nodes may be dynamic, but should maintain persistent connections to some evolving random subset of each other. They should always expect to have direct incoming connections from the validator node and its backup/s. They do not report the validator node's address in the PEX. diff --git a/docs/specification/new-spec/p2p/peer.md b/docs/specification/new-spec/p2p/peer.md index 5281a702..a172764c 100644 --- a/docs/specification/new-spec/p2p/peer.md +++ b/docs/specification/new-spec/p2p/peer.md @@ -5,15 +5,11 @@ and how other peers are found. ## Peer Identity -Tendermint peers are expected to maintain long-term persistent identities in the form of a private key. -Each peer has an ID defined as `peer.ID == peer.PrivKey.Address()`, where `Address` uses the scheme defined in go-crypto. - -Peer ID's must come with some Proof-of-Work; that is, -they must satisfy `peer.PrivKey.Address() < target` for some difficulty target. -This ensures they are not too easy to generate. To begin, let `target == 2^240`. +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. -For simplicity, we only keep track of the latest one. +TODO: define how to deal with this. When attempting to connect to a peer, we use the PeerURL: `@:`. We will attempt to connect to the peer at IP:PORT, and verify, @@ -22,7 +18,7 @@ corresponding to ``. This prevents man-in-the-middle attacks on the peer lay 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 +for instance via VPN. ## Connections @@ -49,8 +45,8 @@ It goes as follows: - if we had the smaller ephemeral pubkey, use nonce1 for receiving, nonce2 for sending; else the opposite - all communications from now on are encrypted using the shared secret and the nonces, where each nonce -- we now have an encrypted channel, but still need to authenticate increments by 2 every time it is used +- we now have an encrypted channel, but still need to authenticate - generate a common challenge to sign: - SHA256 of the sorted (lowest first) and concatenated ephemeral pub keys - sign the common challenge with our persistent private key @@ -76,7 +72,7 @@ an existing peer. If so, we disconnect. We also check the peer's address and public key against an optional whitelist which can be managed through the ABCI app - -if the whitelist is enabled and the peer does not qualigy, the connection is +if the whitelist is enabled and the peer does not qualify, the connection is terminated. @@ -86,14 +82,14 @@ The Tendermint Version Handshake allows the peers to exchange their NodeInfo: ``` type NodeInfo struct { - PubKey crypto.PubKey `json:"pub_key"` - Moniker string `json:"moniker"` - Network string `json:"network"` - RemoteAddr string `json:"remote_addr"` - ListenAddr string `json:"listen_addr"` // accepting in - Version string `json:"version"` // major.minor.revision - Channels []int8 `json:"channels"` // active reactor channels - Other []string `json:"other"` // other application specific data + PubKey crypto.PubKey + Moniker string + Network string + RemoteAddr string + ListenAddr string + Version string + Channels []int8 + Other []string } ```