You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4.2 KiB

Tendermint Peers

This document explains how Tendermint Peers are identified, how they connect to one another, 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.

A single peer ID can have multiple IP addresses associated with - for simplicity, we only keep track of the latest one.

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, 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.

Peers can also be connected to without specifying an ID, ie. <IP>:<PORT>. In this case, the peer cannot be authenticated and other means, such as a VPN, must be used.

Connections

All p2p connections use TCP. Upon establishing a successful TCP connection with a peer, two handhsakes are performed: one for authenticated encryption, and one for Tendermint versioning. Both handshakes have configurable timeouts (they should complete quickly).

Authenticated Encryption Handshake

Tendermint implements the Station-to-Station protocol using ED25519 keys for Diffie-Helman key-exchange and NACL SecretBox for encryption. It goes as follows:

  • generate an emphemeral ED25519 keypair
  • send the ephemeral public key to the peer
  • wait to receive the peer's ephemeral public key
  • compute the Diffie-Hellman shared secret using the peers ephemeral public key and our ephemeral private key
  • generate nonces to use for encryption
    • TODO
  • all communications from now on are encrypted using the shared secret
  • generate a common challenge to sign
  • sign the common challenge with our persistent private key
  • send the signed challenge and persistent public key to the peer
  • wait to receive the signed challenge and persistent public key from the peer
  • verify the signature in the signed challenge using the peers persistent public key

If this is an outgoing connection (we dialed the peer) and we used a peer ID, then finally verify that the peer.PubKey corresponds to the peer ID we dialed, ie. peer.PubKey.Address() == <ID>.

The connection has now been authenticated. All traffic is encrypted.

Note that only the dialer can authenticate the identity of the peer, but this is what we care about since when we join the network we wish to ensure we have reached the intended peer (and are not being MITMd).

Peer Filter

Before continuing, we check if the new peer has the same ID has ourselves or 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 is not on it, the connection is terminated.

Tendermint Version Handshake

The Tendermint Version Handshake allows the peers to exchange their NodeInfo, which contains:

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
}

The connection is disconnected if:

  • peer.NodeInfo.PubKey != peer.PubKey
  • 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

At this point, if we have not disconnected, the peer is valid and added to the switch, so it is added to all reactors.

Connection Activity