diff --git a/config/config.go b/config/config.go index 645b9e10a..f93b79241 100644 --- a/config/config.go +++ b/config/config.go @@ -95,7 +95,7 @@ type BaseConfig struct { PrivValidator string `mapstructure:"priv_validator_file"` // A JSON file containing the private key to use for p2p authenticated encryption - NodeKey string `mapstructure:"node_key"` + NodeKey string `mapstructure:"node_key_file"` // A custom human readable name for this node Moniker string `mapstructure:"moniker"` diff --git a/config/toml.go b/config/toml.go index f979af955..e7bd26103 100644 --- a/config/toml.go +++ b/config/toml.go @@ -87,6 +87,9 @@ genesis_file = "{{ .BaseConfig.Genesis }}" # Path to the JSON file containing the private key to use as a validator in the consensus protocol priv_validator_file = "{{ .BaseConfig.PrivValidator }}" +# Path to the JSON file containing the private key to use for node authentication in the p2p protocol +node_key_file = "{{ .BaseConfig.NodeKey}}" + # Mechanism to connect to the ABCI application: socket | grpc abci = "{{ .BaseConfig.ABCI }}" diff --git a/node/node.go b/node/node.go index bd3bd1ca8..5535b1e16 100644 --- a/node/node.go +++ b/node/node.go @@ -368,7 +368,7 @@ func (n *Node) OnStart() error { n.sw.AddListener(l) // Generate node PrivKey - // TODO: the loading function will need to be configurable + // TODO: pass in like priv_val nodeKey, err := p2p.LoadOrGenNodeKey(n.config.NodeKeyFile()) if err != nil { return err diff --git a/p2p/addrbook.go b/p2p/addrbook.go index 6ccec61f7..8826ff1e0 100644 --- a/p2p/addrbook.go +++ b/p2p/addrbook.go @@ -283,7 +283,7 @@ func (a *AddrBook) RemoveAddress(addr *NetAddress) { if ka == nil { return } - a.Logger.Info("Remove address from book", "addr", ka.Addr) + a.Logger.Info("Remove address from book", "addr", ka.Addr, "ID", ka.ID) a.removeFromAllBuckets(ka) } diff --git a/p2p/addrbook_test.go b/p2p/addrbook_test.go index bcef569df..00051ae1f 100644 --- a/p2p/addrbook_test.go +++ b/p2p/addrbook_test.go @@ -189,8 +189,9 @@ func randIPv4Address(t *testing.T) *NetAddress { rand.Intn(255), ) port := rand.Intn(65535-1) + 1 - addr, err := NewNetAddressString(fmt.Sprintf("%v:%v", ip, port)) - addr.ID = ID(hex.EncodeToString(cmn.RandBytes(20))) + id := ID(hex.EncodeToString(cmn.RandBytes(IDByteLength))) + idAddr := IDAddressString(id, fmt.Sprintf("%v:%v", ip, port)) + addr, err := NewNetAddressString(idAddr) assert.Nil(t, err, "error generating rand network address") if addr.Routable() { return addr diff --git a/p2p/key.go b/p2p/key.go index 5a4ab48f7..ea0f0b071 100644 --- a/p2p/key.go +++ b/p2p/key.go @@ -30,11 +30,7 @@ type NodeKey struct { // ID returns the peer's canonical ID - the hash of its public key. func (nodeKey *NodeKey) ID() ID { - return ID(hex.EncodeToString(nodeKey.id())) -} - -func (nodeKey *NodeKey) id() []byte { - return nodeKey.PrivKey.PubKey().Address() + return PubKeyToID(nodeKey.PubKey()) } // PubKey returns the peer's PubKey @@ -42,8 +38,10 @@ func (nodeKey *NodeKey) PubKey() crypto.PubKey { return nodeKey.PrivKey.PubKey() } -func (nodeKey *NodeKey) SatisfiesTarget(target []byte) bool { - return bytes.Compare(nodeKey.id(), target) < 0 +// PubKeyToID returns the ID corresponding to the given PubKey. +// It's the hex-encoding of the pubKey.Address(). +func PubKeyToID(pubKey crypto.PubKey) ID { + return ID(hex.EncodeToString(pubKey.Address())) } // LoadOrGenNodeKey attempts to load the NodeKey from the given filePath. diff --git a/p2p/netaddress.go b/p2p/netaddress.go index c11d1442e..fed5e59d4 100644 --- a/p2p/netaddress.go +++ b/p2p/netaddress.go @@ -26,6 +26,11 @@ type NetAddress struct { str string } +// IDAddressString returns id@hostPort. +func IDAddressString(id ID, hostPort string) string { + return fmt.Sprintf("%s@%s", id, hostPort) +} + // NewNetAddress returns a new NetAddress using the provided TCP // address. When testing, other net.Addr (except TCP) will result in // using 0.0.0.0:0. When normal run, other net.Addr (except TCP) will @@ -136,7 +141,7 @@ func (na *NetAddress) String() string { if na.str == "" { addrStr := na.DialString() if na.ID != "" { - addrStr = fmt.Sprintf("%s@%s", na.ID, addrStr) + addrStr = IDAddressString(na.ID, addrStr) } na.str = addrStr } diff --git a/p2p/peer.go b/p2p/peer.go index ecf2efce5..ff8d8d0ed 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -304,7 +304,7 @@ func (p *peer) Set(key string, data interface{}) { p.Data.Set(key, data) } -// Key returns the peer's ID - the hex encoded hash of its pubkey. +// ID returns the peer's ID - the hex encoded hash of its pubkey. func (p *peer) ID() ID { return ID(hex.EncodeToString(p.PubKey().Address())) } diff --git a/p2p/pex_reactor.go b/p2p/pex_reactor.go index fc1cbdd98..0816a6e98 100644 --- a/p2p/pex_reactor.go +++ b/p2p/pex_reactor.go @@ -115,14 +115,8 @@ func (r *PEXReactor) AddPeer(p Peer) { r.RequestPEX(p) } } else { - addrStr := fmt.Sprintf("%s@%s", p.ID(), p.NodeInfo().ListenAddr) - addr, err := NewNetAddressString(addrStr) - if err != nil { - // peer gave us a bad ListenAddr. TODO: punish - r.Logger.Error("Error in AddPeer: invalid peer address", "addr", p.NodeInfo().ListenAddr, "err", err) - return - } // For inbound connections, the peer is its own source + addr := p.NodeInfo().NetAddress() r.book.AddAddress(addr, addr) } } @@ -261,7 +255,7 @@ func (r *PEXReactor) ensurePeers() { // NOTE: range here is [10, 90]. Too high ? newBias := cmn.MinInt(numOutPeers, 8)*10 + 10 - toDial := make(map[string]*NetAddress) + toDial := make(map[ID]*NetAddress) // Try maxAttempts times to pick numToDial addresses to dial maxAttempts := numToDial * 3 for i := 0; i < maxAttempts && len(toDial) < numToDial; i++ { @@ -269,19 +263,17 @@ func (r *PEXReactor) ensurePeers() { if try == nil { continue } - if _, selected := toDial[string(try.ID)]; selected { + if _, selected := toDial[try.ID]; selected { continue } if dialling := r.Switch.IsDialing(try.ID); dialling { continue } - // XXX: Should probably use pubkey as peer key ... - // TODO: use the ID correctly if connected := r.Switch.Peers().Has(try.ID); connected { continue } r.Logger.Info("Will dial address", "addr", try) - toDial[string(try.ID)] = try + toDial[try.ID] = try } // Dial picked addresses diff --git a/p2p/switch.go b/p2p/switch.go index eca52e982..da1aa552f 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -84,7 +84,6 @@ type Switch struct { dialing *cmn.CMap nodeInfo *NodeInfo // our node info nodeKey *NodeKey // our node privkey - peerIDTarget []byte filterConnByAddr func(net.Addr) error filterConnByPubKey func(crypto.PubKey) error @@ -194,12 +193,6 @@ func (sw *Switch) SetNodeKey(nodeKey *NodeKey) { } } -// SetPeerIDTarget sets the target for incoming peer ID's - -// the ID must be less than the target -func (sw *Switch) SetPeerIDTarget(target []byte) { - sw.peerIDTarget = target -} - // OnStart implements BaseService. It starts all the reactors, peers, and listeners. func (sw *Switch) OnStart() error { // Start reactors @@ -460,8 +453,7 @@ func (sw *Switch) StopPeerForError(peer Peer, reason interface{}) { // If no success after all that, it stops trying, and leaves it // to the PEX/Addrbook to find the peer again func (sw *Switch) reconnectToPeer(peer Peer) { - netAddr, _ := NewNetAddressString(peer.NodeInfo().RemoteAddr) - netAddr.ID = peer.ID() // TODO: handle above + netAddr := peer.NodeInfo().NetAddress() start := time.Now() sw.Logger.Info("Reconnecting to peer", "peer", peer) for i := 0; i < reconnectAttempts; i++ { diff --git a/p2p/types.go b/p2p/types.go index 860132902..287c88b01 100644 --- a/p2p/types.go +++ b/p2p/types.go @@ -11,6 +11,8 @@ import ( const maxNodeInfoSize = 10240 // 10Kb +// NodeInfo is the basic node information exchanged +// between two peers during the Tendermint P2P handshake type NodeInfo struct { PubKey crypto.PubKey `json:"pub_key"` // authenticated pubkey Moniker string `json:"moniker"` // arbitrary moniker @@ -54,6 +56,16 @@ func (info *NodeInfo) CompatibleWith(other *NodeInfo) error { return nil } +func (info *NodeInfo) NetAddress() *NetAddress { + id := PubKeyToID(info.PubKey) + addr := info.ListenAddr + netAddr, err := NewNetAddressString(IDAddressString(id, addr)) + if err != nil { + panic(err) // everything should be well formed by now + } + return netAddr +} + func (info *NodeInfo) ListenHost() string { host, _, _ := net.SplitHostPort(info.ListenAddr) // nolint: errcheck, gas return host