From 31a1162733f22c86152ed1d2e0d8b92914c0a6a8 Mon Sep 17 00:00:00 2001
From: Ethan Buchman <ethan@coinculture.info>
Date: Sat, 5 Mar 2016 23:18:01 -0500
Subject: [PATCH] add genesis hash to p2p handshake. closes #56

---
 .../tendermint/tendermint/node/node.go        |  6 ++-
 .../tendermint/tendermint/node/node_test.go   | 49 +++++++++++++++++++
 .../tendermint/tendermint/p2p/switch.go       |  2 +-
 .../tendermint/tendermint/types/node.go       | 12 ++++-
 4 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go
index 7c50d842..7185f88a 100644
--- a/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go
+++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go
@@ -152,7 +152,8 @@ func NewNode(privValidator *types.PrivValidator) *Node {
 // Call Start() after adding the listeners.
 func (n *Node) Start() error {
 	n.book.Start()
-	n.sw.SetNodeInfo(makeNodeInfo(n.sw, n.privKey))
+	genState := sm.MakeGenesisState(dbm.NewMemDB(), n.genDoc)
+	n.sw.SetNodeInfo(makeNodeInfo(n.sw, n.privKey, genState.Hash()))
 	n.sw.SetNodePrivKey(n.privKey)
 	_, err := n.sw.Start()
 	return err
@@ -247,12 +248,13 @@ func (n *Node) EventSwitch() *events.EventSwitch {
 	return n.evsw
 }
 
-func makeNodeInfo(sw *p2p.Switch, privKey acm.PrivKeyEd25519) *types.NodeInfo {
+func makeNodeInfo(sw *p2p.Switch, privKey acm.PrivKeyEd25519, genesisRoot []byte) *types.NodeInfo {
 
 	nodeInfo := &types.NodeInfo{
 		PubKey:  privKey.PubKey().(acm.PubKeyEd25519),
 		Moniker: config.GetString("moniker"),
 		ChainID: config.GetString("chain_id"),
+		Genesis: genesisRoot,
 		Version: types.Versions{
 			Tendermint: Version,
 			P2P:        p2p.Version,
diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go
index 84eb1014..a77d4ac9 100644
--- a/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go
+++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go
@@ -1,11 +1,17 @@
 package node
 
 import (
+	"strconv"
+	"strings"
 	"testing"
 	"time"
 
 	_ "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test"
+	dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db"
 	"github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p"
+	sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state"
+	stypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state/types"
+	"github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types"
 )
 
 func TestNodeStartStop(t *testing.T) {
@@ -28,3 +34,46 @@ func TestNodeStartStop(t *testing.T) {
 		t.Fatal("timed out waiting for shutdown")
 	}
 }
+
+func TestCompatibleNodeInfo(t *testing.T) {
+	sw := p2p.NewSwitch()
+	priv1, priv2 := types.GenPrivValidator(), types.GenPrivValidator()
+	genDoc1, _, _ := stypes.RandGenesisDoc(5, true, 100, 4, true, 1000)
+	genState1 := sm.MakeGenesisState(dbm.NewMemDB(), genDoc1)
+	genDoc2, _, _ := stypes.RandGenesisDoc(5, true, 100, 4, true, 1000)
+	genState2 := sm.MakeGenesisState(dbm.NewMemDB(), genDoc2)
+
+	// incompatible genesis states
+	n1 := makeNodeInfo(sw, priv1.PrivKey, genState1.Hash())
+	n2 := makeNodeInfo(sw, priv2.PrivKey, genState2.Hash())
+	if err := n1.CompatibleWith(n2); err == nil {
+		t.Fatalf("Expected nodes to be incompatible due to genesis state")
+	}
+
+	// incompatible chain ids
+	copy(n2.Genesis, n1.Genesis)
+	n2.ChainID = "incryptowetrust"
+	if err := n1.CompatibleWith(n2); err == nil {
+		t.Fatalf("Expected nodes to be incompatible due to chain ID")
+	}
+
+	// incompatible versions
+	n2.ChainID = n1.ChainID
+	v := n1.Version.Tendermint
+	spl := strings.Split(v, ".")
+	n, err := strconv.Atoi(spl[0])
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+	spl[0] = strconv.Itoa(n + 1)
+	n2.Version.Tendermint = strings.Join(spl, ".")
+	if err := n1.CompatibleWith(n2); err == nil {
+		t.Fatalf("Expected nodes to be incompatible due to major version")
+	}
+
+	// compatible
+	n2.Version.Tendermint = n1.Version.Tendermint
+	if err := n1.CompatibleWith(n2); err != nil {
+		t.Fatalf("Expected nodes to be compatible")
+	}
+}
diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go
index 661aee12..fb03ca8e 100644
--- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go
+++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go
@@ -220,7 +220,7 @@ func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, er
 		sconn.Close()
 		return nil, fmt.Errorf("Ignoring connection from self")
 	}
-	// Check version, chain id
+	// Check version, chain id, genesis hash
 	if err := sw.nodeInfo.CompatibleWith(peerNodeInfo); err != nil {
 		sconn.Close()
 		return nil, err
diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/node.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/node.go
index 8e320cba..52a93c5c 100644
--- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/node.go
+++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/node.go
@@ -1,15 +1,18 @@
 package types
 
 import (
+	"bytes"
 	"fmt"
-	acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account"
 	"strings"
+
+	acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account"
 )
 
 type NodeInfo struct {
 	PubKey  acm.PubKeyEd25519 `json:"pub_key"`
 	Moniker string            `json:"moniker"`
 	ChainID string            `json:"chain_id"`
+	Genesis []byte            `json:"genesis"`
 	Host    string            `json:"host"`
 	P2PPort uint16            `json:"p2p_port"`
 	RPCPort uint16            `json:"rpc_port"`
@@ -25,7 +28,7 @@ type Versions struct {
 	Wire       string `json:"wire"`
 }
 
-// CONTRACT: two nodes with the same Tendermint major and minor version and with the same ChainID are compatible
+// CONTRACT: two nodes with the same Tendermint major and minor version and with the same ChainID and Genesis are compatible
 func (ni *NodeInfo) CompatibleWith(no *NodeInfo) error {
 	iM, im, _, ie := splitVersion(ni.Version.Tendermint)
 	oM, om, _, oe := splitVersion(no.Version.Tendermint)
@@ -55,6 +58,11 @@ func (ni *NodeInfo) CompatibleWith(no *NodeInfo) error {
 		return fmt.Errorf("Peer is on a different chain_id. Got %v, expected %v", no.ChainID, ni.ChainID)
 	}
 
+	// nodes must share a common genesis root
+	if !bytes.Equal(ni.Genesis, no.Genesis) {
+		return fmt.Errorf("Peer has a different genesis root. Got %v, expected %v", no.Genesis, ni.Genesis)
+	}
+
 	return nil
 }
 
-- 
GitLab