From 9293ae76bf2cc75251a5df54b478d8ccc61bb00f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 27 Feb 2018 06:54:40 -0500 Subject: [PATCH] p2p: introduce peerConn to simplify peer creation (#1226) * expose AuthEnc in the P2P config if AuthEnc is true, dialed peers must have a node ID in the address and it must match the persistent pubkey from the secret handshake. Refs #1157 * fixes after my own review * fix docs * fix build failure ``` p2p/pex/pex_reactor_test.go:288:88: cannot use seed.NodeInfo().NetAddress() (type *p2p.NetAddress) as type string in array or slice literal ``` * p2p: introduce peerConn to simplify peer creation * Introduce `peerConn` containing the known fields of `peer` * `peer` only created in `sw.addPeer` once handshake is complete and NodeInfo is checked * Eliminates some mutable variables and makes the code flow better * Simplifies the `newXxxPeer` funcs * Use ID instead of PubKey where possible. * SetPubKeyFilter -> SetIDFilter * nodeInfo.Validate takes ID * remove peer.PubKey() * persistent node ids * fixes from review * test: use ip_plus_id.sh more * fix invalid memory panic during fast_sync test ``` 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: panic: runtime error: invalid memory address or nil pointer dereference 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x98dd3e] 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: goroutine 3432 [running]: 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.newOutboundPeerConn(0xc423fd1380, 0xc420933e00, 0x1, 0x1239a60, 0 xc420128c40, 0x2, 0x42caf6, 0xc42001f300, 0xc422831d98, 0xc4227951c0, ...) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/peer.go:123 +0x31e 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).addOutboundPeerWithConfig(0xc4200ad040, 0xc423fd1380, 0 xc420933e00, 0xc423f48801, 0x28, 0x2) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:455 +0x12b 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).DialPeerWithAddress(0xc4200ad040, 0xc423fd1380, 0x1, 0x 0, 0x0) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:371 +0xdc 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).reconnectToPeer(0xc4200ad040, 0x123e000, 0xc42007bb00) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:290 +0x25f 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: created by github.com/tendermint/tendermint/p2p.(*Switch).StopPeerForError 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:256 +0x1b7 ``` --- CHANGELOG.md | 6 + cmd/tendermint/commands/show_node_id.go | 25 +++ cmd/tendermint/main.go | 1 + config/config.go | 4 + config/toml.go | 3 + docs/specification/configuration.rst | 3 + node/node.go | 4 +- p2p/node_info.go | 11 +- p2p/peer.go | 160 ++++++++++-------- p2p/peer_set_test.go | 3 +- p2p/peer_test.go | 22 ++- p2p/pex/pex_reactor.go | 13 +- p2p/pex/pex_reactor_test.go | 4 +- p2p/switch.go | 130 +++++++------- p2p/switch_test.go | 32 ++-- p2p/test_util.go | 13 +- test/docker/Dockerfile | 2 +- test/p2p/data/core/init.sh | 20 --- test/p2p/data/mach1/core/config/node_key.json | 1 + test/p2p/data/mach2/core/config/node_key.json | 1 + test/p2p/data/mach3/core/config/node_key.json | 1 + test/p2p/data/mach4/core/config/node_key.json | 1 + test/p2p/fast_sync/test_peer.sh | 32 ++-- test/p2p/ip.sh | 2 - test/p2p/ip_plus_id.sh | 7 + test/p2p/persistent_peers.sh | 5 +- test/p2p/pex/dial_peers.sh | 23 +-- test/p2p/pex/test_dial_peers.sh | 11 +- test/p2p/test.sh | 2 +- types/priv_validator.go | 3 +- 30 files changed, 298 insertions(+), 247 deletions(-) create mode 100644 cmd/tendermint/commands/show_node_id.go delete mode 100755 test/p2p/data/core/init.sh create mode 100644 test/p2p/data/mach1/core/config/node_key.json create mode 100644 test/p2p/data/mach2/core/config/node_key.json create mode 100644 test/p2p/data/mach3/core/config/node_key.json create mode 100644 test/p2p/data/mach4/core/config/node_key.json create mode 100755 test/p2p/ip_plus_id.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 3456fb58d..c98b55beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,12 @@ BUG FIXES: - Graceful handling/recovery for apps that have non-determinism or fail to halt - Graceful handling/recovery for violations of safety, or liveness +## 0.16.1 (TBD) + +IMPROVEMENTS: +- [config] exposed `auth_enc` flag to enable/disable encryption +- [p2p] when `auth_enc` is true, all dialed peers must have a node ID in their address + ## 0.16.0 (February 20th, 2017) BREAKING CHANGES: diff --git a/cmd/tendermint/commands/show_node_id.go b/cmd/tendermint/commands/show_node_id.go new file mode 100644 index 000000000..92af49417 --- /dev/null +++ b/cmd/tendermint/commands/show_node_id.go @@ -0,0 +1,25 @@ +package commands + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/tendermint/tendermint/p2p" +) + +// ShowNodeIDCmd dumps node's ID to the standard output. +var ShowNodeIDCmd = &cobra.Command{ + Use: "show_node_id", + Short: "Show this node's ID", + RunE: showNodeID, +} + +func showNodeID(cmd *cobra.Command, args []string) error { + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + if err != nil { + return err + } + fmt.Println(nodeKey.ID()) + return nil +} diff --git a/cmd/tendermint/main.go b/cmd/tendermint/main.go index 17b5a585b..fd6287115 100644 --- a/cmd/tendermint/main.go +++ b/cmd/tendermint/main.go @@ -24,6 +24,7 @@ func main() { cmd.ResetPrivValidatorCmd, cmd.ShowValidatorCmd, cmd.TestnetFilesCmd, + cmd.ShowNodeIDCmd, cmd.VersionCmd) // NOTE: diff --git a/config/config.go b/config/config.go index 621847bd0..92e1553df 100644 --- a/config/config.go +++ b/config/config.go @@ -281,6 +281,9 @@ type P2PConfig struct { // // Does not work if the peer-exchange reactor is disabled. SeedMode bool `mapstructure:"seed_mode"` + + // Authenticated encryption + AuthEnc bool `mapstructure:"auth_enc"` } // DefaultP2PConfig returns a default configuration for the peer-to-peer layer @@ -296,6 +299,7 @@ func DefaultP2PConfig() *P2PConfig { RecvRate: 512000, // 500 kB/s PexReactor: true, SeedMode: false, + AuthEnc: true, } } diff --git a/config/toml.go b/config/toml.go index e69cf37fe..35e0985f9 100644 --- a/config/toml.go +++ b/config/toml.go @@ -159,6 +159,9 @@ pex = {{ .P2P.PexReactor }} # Does not work if the peer-exchange reactor is disabled. seed_mode = {{ .P2P.SeedMode }} +# Authenticated encryption +auth_enc = {{ .P2P.AuthEnc }} + ##### mempool configuration options ##### [mempool] diff --git a/docs/specification/configuration.rst b/docs/specification/configuration.rst index d7c186007..983ac87cf 100644 --- a/docs/specification/configuration.rst +++ b/docs/specification/configuration.rst @@ -121,6 +121,9 @@ like the file below, however, double check by inspecting the # Does not work if the peer-exchange reactor is disabled. seed_mode = false + # Authenticated encryption + auth_enc = true + ##### mempool configuration options ##### [mempool] diff --git a/node/node.go b/node/node.go index cd2b4bcb5..65f8e7168 100644 --- a/node/node.go +++ b/node/node.go @@ -279,8 +279,8 @@ func NewNode(config *cfg.Config, } return nil }) - sw.SetPubKeyFilter(func(pubkey crypto.PubKey) error { - resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: cmn.Fmt("/p2p/filter/pubkey/%X", pubkey.Bytes())}) + sw.SetIDFilter(func(id p2p.ID) error { + resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: cmn.Fmt("/p2p/filter/pubkey/%s", id)}) if err != nil { return err } diff --git a/p2p/node_info.go b/p2p/node_info.go index a5bb9da53..6f44b49cd 100644 --- a/p2p/node_info.go +++ b/p2p/node_info.go @@ -34,15 +34,10 @@ type NodeInfo struct { } // Validate checks the self-reported NodeInfo is safe. -// It returns an error if the info.PubKey doesn't match the given pubKey, -// or if there are too many Channels or any duplicate Channels. +// It returns an error if there +// are too many Channels or any duplicate Channels. // TODO: constraints for Moniker/Other? Or is that for the UI ? -func (info NodeInfo) Validate(pubKey crypto.PubKey) error { - if !info.PubKey.Equals(pubKey) { - return fmt.Errorf("info.PubKey (%v) doesn't match peer.PubKey (%v)", - info.PubKey, pubKey) - } - +func (info NodeInfo) Validate() error { if len(info.Channels) > maxNumChannels { return fmt.Errorf("info.Channels is too long (%v). Max is %v", len(info.Channels), maxNumChannels) } diff --git a/p2p/peer.go b/p2p/peer.go index 67ce411cd..2e876d11b 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -34,23 +34,53 @@ type Peer interface { //---------------------------------------------------------- +// peerConn contains the raw connection and its config. +type peerConn struct { + outbound bool + persistent bool + config *PeerConfig + conn net.Conn // source connection +} + +// ID only exists for SecretConnection. +// NOTE: Will panic if conn is not *SecretConnection. +func (pc peerConn) ID() ID { + return PubKeyToID(pc.conn.(*tmconn.SecretConnection).RemotePubKey()) +} + // peer implements Peer. // // Before using a peer, you will need to perform a handshake on connection. type peer struct { cmn.BaseService - outbound bool + // raw peerConn and the multiplex connection + peerConn + mconn *tmconn.MConnection - conn net.Conn // source connection - mconn *tmconn.MConnection // multiplex connection + // peer's node info and the channel it knows about + // channels = nodeInfo.Channels + // cached to avoid copying nodeInfo in hasChannel + nodeInfo NodeInfo + channels []byte - persistent bool - config *PeerConfig + // User data + Data *cmn.CMap +} + +func newPeer(pc peerConn, nodeInfo NodeInfo, + reactorsByCh map[byte]Reactor, chDescs []*tmconn.ChannelDescriptor, + onPeerError func(Peer, interface{})) *peer { - nodeInfo NodeInfo // peer's node info - channels []byte // channels the peer knows about - Data *cmn.CMap // User data. + p := &peer{ + peerConn: pc, + nodeInfo: nodeInfo, + channels: nodeInfo.Channels, + Data: cmn.NewCMap(), + } + p.mconn = createMConnection(pc.conn, p, reactorsByCh, chDescs, onPeerError, pc.config.MConfig) + p.BaseService = *cmn.NewBaseService(nil, "Peer", p) + return p } // PeerConfig is a Peer configuration. @@ -79,36 +109,42 @@ func DefaultPeerConfig() *PeerConfig { } } -func newOutboundPeer(addr *NetAddress, reactorsByCh map[byte]Reactor, chDescs []*tmconn.ChannelDescriptor, - onPeerError func(Peer, interface{}), ourNodePrivKey crypto.PrivKey, config *PeerConfig, persistent bool) (*peer, error) { +func newOutboundPeerConn(addr *NetAddress, config *PeerConfig, persistent bool, ourNodePrivKey crypto.PrivKey) (peerConn, error) { + var pc peerConn conn, err := dial(addr, config) if err != nil { - return nil, errors.Wrap(err, "Error creating peer") + return pc, errors.Wrap(err, "Error creating peer") } - peer, err := newPeerFromConnAndConfig(conn, true, reactorsByCh, chDescs, onPeerError, ourNodePrivKey, config) + pc, err = newPeerConn(conn, config, true, persistent, ourNodePrivKey) if err != nil { - if err := conn.Close(); err != nil { - return nil, err + if err2 := conn.Close(); err2 != nil { + return pc, errors.Wrap(err, err2.Error()) } - return nil, err + return pc, err } - peer.persistent = persistent - return peer, nil + // ensure dialed ID matches connection ID + if config.AuthEnc && addr.ID != pc.ID() { + if err2 := conn.Close(); err2 != nil { + return pc, errors.Wrap(err, err2.Error()) + } + return pc, ErrSwitchAuthenticationFailure{addr, pc.ID()} + } + return pc, nil } -func newInboundPeer(conn net.Conn, reactorsByCh map[byte]Reactor, chDescs []*tmconn.ChannelDescriptor, - onPeerError func(Peer, interface{}), ourNodePrivKey crypto.PrivKey, config *PeerConfig) (*peer, error) { +func newInboundPeerConn(conn net.Conn, config *PeerConfig, ourNodePrivKey crypto.PrivKey) (peerConn, error) { // TODO: issue PoW challenge - return newPeerFromConnAndConfig(conn, false, reactorsByCh, chDescs, onPeerError, ourNodePrivKey, config) + return newPeerConn(conn, config, false, false, ourNodePrivKey) } -func newPeerFromConnAndConfig(rawConn net.Conn, outbound bool, reactorsByCh map[byte]Reactor, chDescs []*tmconn.ChannelDescriptor, - onPeerError func(Peer, interface{}), ourNodePrivKey crypto.PrivKey, config *PeerConfig) (*peer, error) { +func newPeerConn(rawConn net.Conn, + config *PeerConfig, outbound, persistent bool, + ourNodePrivKey crypto.PrivKey) (pc peerConn, err error) { conn := rawConn @@ -118,32 +154,26 @@ func newPeerFromConnAndConfig(rawConn net.Conn, outbound bool, reactorsByCh map[ conn = FuzzConnAfterFromConfig(conn, 10*time.Second, config.FuzzConfig) } - // Encrypt connection if config.AuthEnc { + // Set deadline for secret handshake if err := conn.SetDeadline(time.Now().Add(config.HandshakeTimeout * time.Second)); err != nil { - return nil, errors.Wrap(err, "Error setting deadline while encrypting connection") + return pc, errors.Wrap(err, "Error setting deadline while encrypting connection") } - var err error + // Encrypt connection conn, err = tmconn.MakeSecretConnection(conn, ourNodePrivKey) if err != nil { - return nil, errors.Wrap(err, "Error creating peer") + return pc, errors.Wrap(err, "Error creating peer") } } - // NodeInfo is set after Handshake - p := &peer{ - outbound: outbound, - conn: conn, - config: config, - Data: cmn.NewCMap(), - } - - p.mconn = createMConnection(conn, p, reactorsByCh, chDescs, onPeerError, config.MConfig) - - p.BaseService = *cmn.NewBaseService(nil, "Peer", p) - - return p, nil + // Only the information we already have + return peerConn{ + config: config, + outbound: outbound, + persistent: persistent, + conn: conn, + }, nil } //--------------------------------------------------- @@ -175,17 +205,17 @@ func (p *peer) OnStop() { // ID returns the peer's ID - the hex encoded hash of its pubkey. func (p *peer) ID() ID { - return PubKeyToID(p.PubKey()) + return p.nodeInfo.ID() } // IsOutbound returns true if the connection is outbound, false otherwise. func (p *peer) IsOutbound() bool { - return p.outbound + return p.peerConn.outbound } // IsPersistent returns true if the peer is persitent, false otherwise. func (p *peer) IsPersistent() bool { - return p.persistent + return p.peerConn.persistent } // NodeInfo returns a copy of the peer's NodeInfo. @@ -250,68 +280,48 @@ func (p *peer) hasChannel(chID byte) bool { // methods used by the Switch // CloseConn should be called by the Switch if the peer was created but never started. -func (p *peer) CloseConn() { - p.conn.Close() // nolint: errcheck +func (pc *peerConn) CloseConn() { + pc.conn.Close() // nolint: errcheck } // HandshakeTimeout performs the Tendermint P2P handshake between a given node and the peer // by exchanging their NodeInfo. It sets the received nodeInfo on the peer. // NOTE: blocking -func (p *peer) HandshakeTimeout(ourNodeInfo NodeInfo, timeout time.Duration) error { +func (pc *peerConn) HandshakeTimeout(ourNodeInfo NodeInfo, timeout time.Duration) (peerNodeInfo NodeInfo, err error) { // Set deadline for handshake so we don't block forever on conn.ReadFull - if err := p.conn.SetDeadline(time.Now().Add(timeout)); err != nil { - return errors.Wrap(err, "Error setting deadline") + if err := pc.conn.SetDeadline(time.Now().Add(timeout)); err != nil { + return peerNodeInfo, errors.Wrap(err, "Error setting deadline") } - var peerNodeInfo NodeInfo var err1 error var err2 error cmn.Parallel( func() { var n int - wire.WriteBinary(&ourNodeInfo, p.conn, &n, &err1) + wire.WriteBinary(&ourNodeInfo, pc.conn, &n, &err1) }, func() { var n int - wire.ReadBinary(&peerNodeInfo, p.conn, MaxNodeInfoSize(), &n, &err2) - p.Logger.Info("Peer handshake", "peerNodeInfo", peerNodeInfo) + wire.ReadBinary(&peerNodeInfo, pc.conn, MaxNodeInfoSize(), &n, &err2) }) if err1 != nil { - return errors.Wrap(err1, "Error during handshake/write") + return peerNodeInfo, errors.Wrap(err1, "Error during handshake/write") } if err2 != nil { - return errors.Wrap(err2, "Error during handshake/read") + return peerNodeInfo, errors.Wrap(err2, "Error during handshake/read") } // Remove deadline - if err := p.conn.SetDeadline(time.Time{}); err != nil { - return errors.Wrap(err, "Error removing deadline") + if err := pc.conn.SetDeadline(time.Time{}); err != nil { + return peerNodeInfo, errors.Wrap(err, "Error removing deadline") } - p.setNodeInfo(peerNodeInfo) - return nil -} - -func (p *peer) setNodeInfo(nodeInfo NodeInfo) { - p.nodeInfo = nodeInfo - // cache the channels so we dont copy nodeInfo - // every time we check hasChannel - p.channels = nodeInfo.Channels + return peerNodeInfo, nil } // Addr returns peer's remote network address. func (p *peer) Addr() net.Addr { - return p.conn.RemoteAddr() -} - -// PubKey returns peer's public key. -func (p *peer) PubKey() crypto.PubKey { - if !p.nodeInfo.PubKey.Empty() { - return p.nodeInfo.PubKey - } else if p.config.AuthEnc { - return p.conn.(*tmconn.SecretConnection).RemotePubKey() - } - panic("Attempt to get peer's PubKey before calling Handshake") + return p.peerConn.conn.RemoteAddr() } // CanSend returns true if the send queue is not full, false otherwise. diff --git a/p2p/peer_set_test.go b/p2p/peer_set_test.go index e906eb8e7..c25041996 100644 --- a/p2p/peer_set_test.go +++ b/p2p/peer_set_test.go @@ -13,10 +13,11 @@ import ( // Returns an empty dummy peer func randPeer() *peer { + pubKey := crypto.GenPrivKeyEd25519().Wrap().PubKey() return &peer{ nodeInfo: NodeInfo{ ListenAddr: cmn.Fmt("%v.%v.%v.%v:46656", rand.Int()%256, rand.Int()%256, rand.Int()%256, rand.Int()%256), - PubKey: crypto.GenPrivKeyEd25519().Wrap().PubKey(), + PubKey: pubKey, }, } } diff --git a/p2p/peer_test.go b/p2p/peer_test.go index a2f5ed05f..45e2b0457 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -11,6 +11,7 @@ import ( crypto "github.com/tendermint/go-crypto" tmconn "github.com/tendermint/tendermint/p2p/conn" + "github.com/tendermint/tmlibs/log" ) const testCh = 0x01 @@ -35,8 +36,8 @@ func TestPeerBasic(t *testing.T) { assert.False(p.IsPersistent()) p.persistent = true assert.True(p.IsPersistent()) - assert.Equal(rp.Addr().String(), p.Addr().String()) - assert.Equal(rp.PubKey(), p.PubKey()) + assert.Equal(rp.Addr().DialString(), p.Addr().String()) + assert.Equal(rp.ID(), p.ID()) } func TestPeerWithoutAuthEnc(t *testing.T) { @@ -89,11 +90,11 @@ func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *PeerConfig) } reactorsByCh := map[byte]Reactor{testCh: NewTestReactor(chDescs, true)} pk := crypto.GenPrivKeyEd25519().Wrap() - p, err := newOutboundPeer(addr, reactorsByCh, chDescs, func(p Peer, r interface{}) {}, pk, config, false) + pc, err := newOutboundPeerConn(addr, config, false, pk) if err != nil { return nil, err } - err = p.HandshakeTimeout(NodeInfo{ + nodeInfo, err := pc.HandshakeTimeout(NodeInfo{ PubKey: pk.PubKey(), Moniker: "host_peer", Network: "testing", @@ -103,6 +104,9 @@ func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *PeerConfig) if err != nil { return nil, err } + + p := newPeer(pc, nodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {}) + p.SetLogger(log.TestingLogger().With("peer", addr)) return p, nil } @@ -117,8 +121,8 @@ func (p *remotePeer) Addr() *NetAddress { return p.addr } -func (p *remotePeer) PubKey() crypto.PubKey { - return p.PrivKey.PubKey() +func (p *remotePeer) ID() ID { + return PubKeyToID(p.PrivKey.PubKey()) } func (p *remotePeer) Start() { @@ -126,7 +130,7 @@ func (p *remotePeer) Start() { if e != nil { golog.Fatalf("net.Listen tcp :0: %+v", e) } - p.addr = NewNetAddress("", l.Addr()) + p.addr = NewNetAddress(PubKeyToID(p.PrivKey.PubKey()), l.Addr()) p.quit = make(chan struct{}) go p.accept(l) } @@ -141,11 +145,11 @@ func (p *remotePeer) accept(l net.Listener) { if err != nil { golog.Fatalf("Failed to accept conn: %+v", err) } - peer, err := newInboundPeer(conn, make(map[byte]Reactor), make([]*tmconn.ChannelDescriptor, 0), func(p Peer, r interface{}) {}, p.PrivKey, p.Config) + pc, err := newInboundPeerConn(conn, p.Config, p.PrivKey) if err != nil { golog.Fatalf("Failed to create a peer: %+v", err) } - err = peer.HandshakeTimeout(NodeInfo{ + _, err = pc.HandshakeTimeout(NodeInfo{ PubKey: p.PrivKey.PubKey(), Moniker: "remote_peer", Network: "testing", diff --git a/p2p/pex/pex_reactor.go b/p2p/pex/pex_reactor.go index 5aeca8f76..2cee9e221 100644 --- a/p2p/pex/pex_reactor.go +++ b/p2p/pex/pex_reactor.go @@ -323,8 +323,9 @@ func (r *PEXReactor) ensurePeers() { // Dial picked addresses for _, item := range toDial { go func(picked *p2p.NetAddress) { - _, err := r.Switch.DialPeerWithAddress(picked, false) + err := r.Switch.DialPeerWithAddress(picked, false) if err != nil { + r.Logger.Error("Dialing failed", "err", err) // TODO: detect more "bad peer" scenarios if _, ok := err.(p2p.ErrSwitchAuthenticationFailure); ok { r.book.MarkBad(picked) @@ -381,13 +382,11 @@ func (r *PEXReactor) dialSeeds() { for _, i := range perm { // dial a random seed seedAddr := seedAddrs[i] - peer, err := r.Switch.DialPeerWithAddress(seedAddr, false) - if err != nil { - r.Switch.Logger.Error("Error dialing seed", "err", err, "seed", seedAddr) - } else { - r.Switch.Logger.Info("Connected to seed", "peer", peer) + err := r.Switch.DialPeerWithAddress(seedAddr, false) + if err == nil { return } + r.Switch.Logger.Error("Error dialing seed", "err", err, "seed", seedAddr) } r.Switch.Logger.Error("Couldn't connect to any seeds") } @@ -470,7 +469,7 @@ func (r *PEXReactor) crawlPeers() { continue } // Otherwise, attempt to connect with the known address - _, err := r.Switch.DialPeerWithAddress(pi.Addr, false) + err := r.Switch.DialPeerWithAddress(pi.Addr, false) if err != nil { r.book.MarkAttempt(pi.Addr) continue diff --git a/p2p/pex/pex_reactor_test.go b/p2p/pex/pex_reactor_test.go index 82dafecd4..57f02423f 100644 --- a/p2p/pex/pex_reactor_test.go +++ b/p2p/pex/pex_reactor_test.go @@ -100,7 +100,7 @@ func TestPEXReactorRunning(t *testing.T) { // fill the address book and add listeners for _, s := range switches { - addr, _ := p2p.NewNetAddressString(s.NodeInfo().ListenAddr) + addr := s.NodeInfo().NetAddress() book.AddAddress(addr, addr) s.AddListener(p2p.NewDefaultListener("tcp", s.NodeInfo().ListenAddr, true, log.TestingLogger())) } @@ -285,7 +285,7 @@ func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) { sw := p2p.MakeSwitch(config, 1, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { sw.SetLogger(log.TestingLogger()) - r := NewPEXReactor(book, &PEXReactorConfig{Seeds: []string{seed.NodeInfo().ListenAddr}}) + r := NewPEXReactor(book, &PEXReactorConfig{Seeds: []string{seed.NodeInfo().NetAddress().String()}}) r.SetLogger(log.TestingLogger()) r.SetEnsurePeersPeriod(250 * time.Millisecond) sw.AddReactor("pex", r) diff --git a/p2p/switch.go b/p2p/switch.go index f1d02dcfc..cffadf3be 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -10,7 +10,6 @@ import ( "github.com/pkg/errors" - crypto "github.com/tendermint/go-crypto" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/p2p/conn" cmn "github.com/tendermint/tmlibs/common" @@ -59,8 +58,8 @@ type Switch struct { nodeInfo NodeInfo // our node info nodeKey *NodeKey // our node privkey - filterConnByAddr func(net.Addr) error - filterConnByPubKey func(crypto.PubKey) error + filterConnByAddr func(net.Addr) error + filterConnByID func(ID) error rng *rand.Rand // seed for randomizing dial times and orders } @@ -85,6 +84,7 @@ func NewSwitch(config *cfg.P2PConfig) *Switch { sw.peerConfig.MConfig.SendRate = config.SendRate sw.peerConfig.MConfig.RecvRate = config.RecvRate sw.peerConfig.MConfig.MaxMsgPacketPayloadSize = config.MaxMsgPacketPayloadSize + sw.peerConfig.AuthEnc = config.AuthEnc sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw) return sw @@ -287,14 +287,13 @@ func (sw *Switch) reconnectToPeer(peer Peer) { return } - peer, err := sw.DialPeerWithAddress(netAddr, true) + err := sw.DialPeerWithAddress(netAddr, true) if err != nil { sw.Logger.Info("Error reconnecting to peer. Trying again", "tries", i, "err", err, "peer", peer) // sleep a set amount sw.randomSleep(reconnectInterval) continue } else { - sw.Logger.Info("Reconnected to peer", "peer", peer) return } } @@ -309,14 +308,11 @@ func (sw *Switch) reconnectToPeer(peer Peer) { // sleep an exponentially increasing amount sleepIntervalSeconds := math.Pow(reconnectBackOffBaseSeconds, float64(i)) sw.randomSleep(time.Duration(sleepIntervalSeconds) * time.Second) - peer, err := sw.DialPeerWithAddress(netAddr, true) - if err != nil { - sw.Logger.Info("Error reconnecting to peer. Trying again", "tries", i, "err", err, "peer", peer) - continue - } else { - sw.Logger.Info("Reconnected to peer", "peer", peer) - return + err := sw.DialPeerWithAddress(netAddr, true) + if err == nil { + return // success } + sw.Logger.Info("Error reconnecting to peer. Trying again", "tries", i, "err", err, "peer", peer) } sw.Logger.Error("Failed to reconnect to peer. Giving up", "peer", peer, "elapsed", time.Since(start)) } @@ -358,11 +354,9 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b go func(i int) { sw.randomSleep(0) j := perm[i] - peer, err := sw.DialPeerWithAddress(netAddrs[j], persistent) + err := sw.DialPeerWithAddress(netAddrs[j], persistent) if err != nil { sw.Logger.Error("Error dialing peer", "err", err) - } else { - sw.Logger.Info("Connected to peer", "peer", peer) } }(i) } @@ -371,7 +365,7 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b // DialPeerWithAddress dials the given peer and runs sw.addPeer if it connects and authenticates successfully. // If `persistent == true`, the switch will always try to reconnect to this peer if the connection ever fails. -func (sw *Switch) DialPeerWithAddress(addr *NetAddress, persistent bool) (Peer, error) { +func (sw *Switch) DialPeerWithAddress(addr *NetAddress, persistent bool) error { sw.dialing.Set(string(addr.ID), addr) defer sw.dialing.Delete(string(addr.ID)) return sw.addOutboundPeerWithConfig(addr, sw.peerConfig, persistent) @@ -394,10 +388,10 @@ func (sw *Switch) FilterConnByAddr(addr net.Addr) error { return nil } -// FilterConnByPubKey returns an error if connecting to the given public key is forbidden. -func (sw *Switch) FilterConnByPubKey(pubkey crypto.PubKey) error { - if sw.filterConnByPubKey != nil { - return sw.filterConnByPubKey(pubkey) +// FilterConnByID returns an error if connecting to the given peer ID is forbidden. +func (sw *Switch) FilterConnByID(id ID) error { + if sw.filterConnByID != nil { + return sw.filterConnByID(id) } return nil @@ -408,9 +402,9 @@ func (sw *Switch) SetAddrFilter(f func(net.Addr) error) { sw.filterConnByAddr = f } -// SetPubKeyFilter sets the function for filtering connections by public key. -func (sw *Switch) SetPubKeyFilter(f func(crypto.PubKey) error) { - sw.filterConnByPubKey = f +// SetIDFilter sets the function for filtering connections by peer ID. +func (sw *Switch) SetIDFilter(f func(ID) error) { + sw.filterConnByID = f } //------------------------------------------------------------------------------------ @@ -441,14 +435,13 @@ func (sw *Switch) listenerRoutine(l Listener) { } func (sw *Switch) addInboundPeerWithConfig(conn net.Conn, config *PeerConfig) error { - peer, err := newInboundPeer(conn, sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, config) + peerConn, err := newInboundPeerConn(conn, config, sw.nodeKey.PrivKey) if err != nil { conn.Close() // peer is nil return err } - peer.SetLogger(sw.Logger.With("peer", conn.RemoteAddr())) - if err = sw.addPeer(peer); err != nil { - peer.CloseConn() + if err = sw.addPeer(peerConn); err != nil { + peerConn.CloseConn() return err } @@ -457,31 +450,20 @@ func (sw *Switch) addInboundPeerWithConfig(conn net.Conn, config *PeerConfig) er // dial the peer; make secret connection; authenticate against the dialed ID; // add the peer. -func (sw *Switch) addOutboundPeerWithConfig(addr *NetAddress, config *PeerConfig, persistent bool) (Peer, error) { +func (sw *Switch) addOutboundPeerWithConfig(addr *NetAddress, config *PeerConfig, persistent bool) error { sw.Logger.Info("Dialing peer", "address", addr) - peer, err := newOutboundPeer(addr, sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, config, persistent) + peerConn, err := newOutboundPeerConn(addr, config, persistent, sw.nodeKey.PrivKey) if err != nil { sw.Logger.Error("Failed to dial peer", "address", addr, "err", err) - return nil, err - } - peer.SetLogger(sw.Logger.With("peer", addr)) - - // authenticate peer - if addr.ID == "" { - peer.Logger.Info("Dialed peer with unknown ID - unable to authenticate", "addr", addr) - } else if addr.ID != peer.ID() { - peer.CloseConn() - return nil, ErrSwitchAuthenticationFailure{addr, peer.ID()} + return err } - err = sw.addPeer(peer) - if err != nil { + if err := sw.addPeer(peerConn); err != nil { sw.Logger.Error("Failed to add peer", "address", addr, "err", err) - peer.CloseConn() - return nil, err + peerConn.CloseConn() + return err } - sw.Logger.Info("Dialed and added peer", "address", addr, "peer", peer) - return peer, nil + return nil } // addPeer performs the Tendermint P2P handshake with a peer @@ -489,41 +471,65 @@ func (sw *Switch) addOutboundPeerWithConfig(addr *NetAddress, config *PeerConfig // it starts the peer and adds it to the switch. // NOTE: This performs a blocking handshake before the peer is added. // NOTE: If error is returned, caller is responsible for calling peer.CloseConn() -func (sw *Switch) addPeer(peer *peer) error { - // Avoid self - if sw.nodeKey.ID() == peer.ID() { - return ErrSwitchConnectToSelf +func (sw *Switch) addPeer(pc peerConn) error { + + addr := pc.conn.RemoteAddr() + if err := sw.FilterConnByAddr(addr); err != nil { + return err } - // Avoid duplicate - if sw.peers.Has(peer.ID()) { - return ErrSwitchDuplicatePeer + // NOTE: if AuthEnc==false, we don't have a peerID until after the handshake. + // If AuthEnc==true then we already know the ID and could do the checks first before the handshake, + // but it's simple to just deal with both cases the same after the handshake. + // Exchange NodeInfo on the conn + peerNodeInfo, err := pc.HandshakeTimeout(sw.nodeInfo, time.Duration(sw.peerConfig.HandshakeTimeout*time.Second)) + if err != nil { + return err } - // Filter peer against white list - if err := sw.FilterConnByAddr(peer.Addr()); err != nil { - return err + peerID := peerNodeInfo.ID() + + // ensure connection key matches self reported key + if pc.config.AuthEnc { + connID := pc.ID() + + if peerID != connID { + return fmt.Errorf("nodeInfo.ID() (%v) doesn't match conn.ID() (%v)", + peerID, connID) + } } - if err := sw.FilterConnByPubKey(peer.PubKey()); err != nil { + + // Validate the peers nodeInfo + if err := peerNodeInfo.Validate(); err != nil { return err } - // Exchange NodeInfo with the peer - if err := peer.HandshakeTimeout(sw.nodeInfo, time.Duration(sw.peerConfig.HandshakeTimeout*time.Second)); err != nil { - return err + // Avoid self + if sw.nodeKey.ID() == peerID { + return ErrSwitchConnectToSelf + } + + // Avoid duplicate + if sw.peers.Has(peerID) { + return ErrSwitchDuplicatePeer } - // Validate the peers nodeInfo against the pubkey - if err := peer.NodeInfo().Validate(peer.PubKey()); err != nil { + // Filter peer against ID white list + if err := sw.FilterConnByID(peerID); err != nil { return err } // Check version, chain id - if err := sw.nodeInfo.CompatibleWith(peer.NodeInfo()); err != nil { + if err := sw.nodeInfo.CompatibleWith(peerNodeInfo); err != nil { return err } + peer := newPeer(pc, peerNodeInfo, sw.reactorsByCh, sw.chDescs, sw.StopPeerForError) + peer.SetLogger(sw.Logger.With("peer", addr)) + + peer.Logger.Info("Successful handshake with peer", "peerNodeInfo", peerNodeInfo) + // All good. Start peer if sw.IsRunning() { sw.startInitPeer(peer) diff --git a/p2p/switch_test.go b/p2p/switch_test.go index 745eb44e6..9ba9bf831 100644 --- a/p2p/switch_test.go +++ b/p2p/switch_test.go @@ -192,7 +192,7 @@ func assertNoPeersAfterTimeout(t *testing.T, sw *Switch, timeout time.Duration) } } -func TestConnPubKeyFilter(t *testing.T) { +func TestConnIDFilter(t *testing.T) { s1 := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) s2 := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) defer s1.Stop() @@ -200,15 +200,20 @@ func TestConnPubKeyFilter(t *testing.T) { c1, c2 := conn.NetPipe() - // set pubkey filter - s1.SetPubKeyFilter(func(pubkey crypto.PubKey) error { - if bytes.Equal(pubkey.Bytes(), s2.nodeInfo.PubKey.Bytes()) { + s1.SetIDFilter(func(id ID) error { + if id == PubKeyToID(s2.nodeInfo.PubKey) { + return fmt.Errorf("Error: pipe is blacklisted") + } + return nil + }) + + s2.SetIDFilter(func(id ID) error { + if id == PubKeyToID(s1.nodeInfo.PubKey) { return fmt.Errorf("Error: pipe is blacklisted") } return nil }) - // connect to good peer go func() { err := s1.addPeerWithConnection(c1) assert.NotNil(t, err, "expected error") @@ -237,13 +242,15 @@ func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) { rp.Start() defer rp.Stop() - peer, err := newOutboundPeer(rp.Addr(), sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, DefaultPeerConfig(), false) + pc, err := newOutboundPeerConn(rp.Addr(), DefaultPeerConfig(), false, sw.nodeKey.PrivKey) require.Nil(err) - err = sw.addPeer(peer) + err = sw.addPeer(pc) require.Nil(err) + peer := sw.Peers().Get(rp.ID()) + // simulate failure by closing connection - peer.CloseConn() + pc.CloseConn() assertNoPeersAfterTimeout(t, sw, 100*time.Millisecond) assert.False(peer.IsRunning()) @@ -264,13 +271,16 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) { rp.Start() defer rp.Stop() - peer, err := newOutboundPeer(rp.Addr(), sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, DefaultPeerConfig(), true) + pc, err := newOutboundPeerConn(rp.Addr(), DefaultPeerConfig(), true, sw.nodeKey.PrivKey) + // sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, require.Nil(err) - err = sw.addPeer(peer) + err = sw.addPeer(pc) require.Nil(err) + peer := sw.Peers().Get(rp.ID()) + // simulate failure by closing connection - peer.CloseConn() + pc.CloseConn() // TODO: remove sleep, detect the disconnection, wait for reconnect npeers := sw.Peers().Size() diff --git a/p2p/test_util.go b/p2p/test_util.go index dea48dfd3..0d6427f43 100644 --- a/p2p/test_util.go +++ b/p2p/test_util.go @@ -19,12 +19,14 @@ func AddPeerToSwitch(sw *Switch, peer Peer) { func CreateRandomPeer(outbound bool) *peer { addr, netAddr := CreateRoutableAddr() p := &peer{ + peerConn: peerConn{ + outbound: outbound, + }, nodeInfo: NodeInfo{ ListenAddr: netAddr.DialString(), PubKey: crypto.GenPrivKeyEd25519().Wrap().PubKey(), }, - outbound: outbound, - mconn: &conn.MConnection{}, + mconn: &conn.MConnection{}, } p.SetLogger(log.TestingLogger().With("peer", addr)) return p @@ -98,16 +100,15 @@ func Connect2Switches(switches []*Switch, i, j int) { } func (sw *Switch) addPeerWithConnection(conn net.Conn) error { - peer, err := newInboundPeer(conn, sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, sw.peerConfig) + pc, err := newInboundPeerConn(conn, sw.peerConfig, sw.nodeKey.PrivKey) if err != nil { if err := conn.Close(); err != nil { sw.Logger.Error("Error closing connection", "err", err) } return err } - peer.SetLogger(sw.Logger.With("peer", conn.RemoteAddr())) - if err = sw.addPeer(peer); err != nil { - peer.CloseConn() + if err = sw.addPeer(pc); err != nil { + pc.CloseConn() return err } diff --git a/test/docker/Dockerfile b/test/docker/Dockerfile index a168cfb1d..06dfdfd88 100644 --- a/test/docker/Dockerfile +++ b/test/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.9.2 +FROM golang:1.9.4 # Add testing deps for curl RUN echo 'deb http://httpredir.debian.org/debian testing main non-free contrib' >> /etc/apt/sources.list diff --git a/test/p2p/data/core/init.sh b/test/p2p/data/core/init.sh deleted file mode 100755 index 12a42ed40..000000000 --- a/test/p2p/data/core/init.sh +++ /dev/null @@ -1,20 +0,0 @@ -#! /bin/bash -# This is a sample bash script for tendermint core -# Edit this script before "mintnet start" to change -# the core blockchain engine. - -TMREPO="github.com/tendermint/tendermint" -BRANCH="master" - -go get -d $TMREPO/cmd/tendermint -### DEPENDENCIES (example) -# cd $GOPATH/src/github.com/tendermint/abci -# git fetch origin $BRANCH -# git checkout $BRANCH -### DEPENDENCIES END -cd $GOPATH/src/$TMREPO -git fetch origin $BRANCH -git checkout $BRANCH -make install - -tendermint node --p2p.seeds="$TMSEEDS" --moniker="$TMNAME" --proxy_app="$PROXYAPP" --rpc.unsafe diff --git a/test/p2p/data/mach1/core/config/node_key.json b/test/p2p/data/mach1/core/config/node_key.json new file mode 100644 index 000000000..7540cb5f4 --- /dev/null +++ b/test/p2p/data/mach1/core/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"ed25519","data":"06962D169F314ABB9D05AE5A04B46E48F0FBD8F1830149B47493910CBDCA7796096E5B94CD179F545AE3C281D9BF5C9E0E3D8FF719048B62F7849094CFFA8591"}} \ No newline at end of file diff --git a/test/p2p/data/mach2/core/config/node_key.json b/test/p2p/data/mach2/core/config/node_key.json new file mode 100644 index 000000000..efad2f0b3 --- /dev/null +++ b/test/p2p/data/mach2/core/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"ed25519","data":"B8CE8B0D5138C10208526ABDADCE91C735FCCC4186E06E0972EC35E64973428A45EBC61F24CE1B91B3D26AFBAB11C2789EF04CBAC28183619C01116B66A9C528"}} \ No newline at end of file diff --git a/test/p2p/data/mach3/core/config/node_key.json b/test/p2p/data/mach3/core/config/node_key.json new file mode 100644 index 000000000..58880f6f3 --- /dev/null +++ b/test/p2p/data/mach3/core/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"ed25519","data":"913DE8AC6D18922A53F6B0196EF023B4693FECFBB565E084F0B4941768F3DAE892B35ADD954562FE071C465BC244B2AFAED4A270EC849269341473CE192DE682"}} \ No newline at end of file diff --git a/test/p2p/data/mach4/core/config/node_key.json b/test/p2p/data/mach4/core/config/node_key.json new file mode 100644 index 000000000..72e7b25df --- /dev/null +++ b/test/p2p/data/mach4/core/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"ed25519","data":"408226F3F40411AC22262DD9A33BFE27D6FED42B9F084906B3797118C951CB82F81552170A85C94F0608AE8B59B70A0CA8B604A9057585B28A266140DC615E97"}} \ No newline at end of file diff --git a/test/p2p/fast_sync/test_peer.sh b/test/p2p/fast_sync/test_peer.sh index 1f341bf5d..8b24b0438 100644 --- a/test/p2p/fast_sync/test_peer.sh +++ b/test/p2p/fast_sync/test_peer.sh @@ -19,20 +19,20 @@ echo "Testing fastsync on node $ID" # kill peer set +e # circle sigh :( -docker rm -vf local_testnet_$ID -set -e - -# restart peer - should have an empty blockchain -PERSISTENT_PEERS="$(test/p2p/ip.sh 1):46656" -for j in `seq 2 $N`; do - PERSISTENT_PEERS="$PERSISTENT_PEERS,$(test/p2p/ip.sh $j):46656" -done -bash test/p2p/peer.sh $DOCKER_IMAGE $NETWORK_NAME $ID $PROXY_APP "--p2p.persistent_peers $PERSISTENT_PEERS --p2p.pex --rpc.unsafe" - -# wait for peer to sync and check the app hash -bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME fs_$ID "test/p2p/fast_sync/check_peer.sh $ID" - -echo "" -echo "PASS" -echo "" + docker rm -vf local_testnet_$ID + set -e + + # restart peer - should have an empty blockchain + PERSISTENT_PEERS="$(test/p2p/ip_plus_id.sh 1 $DOCKER_IMAGE):46656" + for j in `seq 2 $N`; do + PERSISTENT_PEERS="$PERSISTENT_PEERS,$(test/p2p/ip_plus_id.sh $j $DOCKER_IMAGE):46656" + done + bash test/p2p/peer.sh $DOCKER_IMAGE $NETWORK_NAME $ID $PROXY_APP "--p2p.persistent_peers $PERSISTENT_PEERS --p2p.pex --rpc.unsafe" + + # wait for peer to sync and check the app hash + bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME fs_$ID "test/p2p/fast_sync/check_peer.sh $ID" + + echo "" + echo "PASS" + echo "" diff --git a/test/p2p/ip.sh b/test/p2p/ip.sh index 33ea890db..77753f541 100755 --- a/test/p2p/ip.sh +++ b/test/p2p/ip.sh @@ -3,5 +3,3 @@ set -eu ID=$1 echo "172.57.0.$((100+$ID))" - - diff --git a/test/p2p/ip_plus_id.sh b/test/p2p/ip_plus_id.sh new file mode 100755 index 000000000..0d2248fe0 --- /dev/null +++ b/test/p2p/ip_plus_id.sh @@ -0,0 +1,7 @@ +#! /bin/bash +set -eu + +ID=$1 +DOCKER_IMAGE=$2 +NODEID="$(docker run --rm -e TMHOME=/go/src/github.com/tendermint/tendermint/test/p2p/data/mach$ID/core $DOCKER_IMAGE tendermint show_node_id)" +echo "$NODEID@172.57.0.$((100+$ID))" diff --git a/test/p2p/persistent_peers.sh b/test/p2p/persistent_peers.sh index 4ad55bc03..68eeebe25 100644 --- a/test/p2p/persistent_peers.sh +++ b/test/p2p/persistent_peers.sh @@ -2,11 +2,12 @@ set -eu N=$1 +DOCKER_IMAGE=$2 cd "$GOPATH/src/github.com/tendermint/tendermint" -persistent_peers="$(test/p2p/ip.sh 1):46656" +persistent_peers="$(test/p2p/ip_plus_id.sh 1 $DOCKER_IMAGE):46656" for i in $(seq 2 $N); do - persistent_peers="$persistent_peers,$(test/p2p/ip.sh $i):46656" + persistent_peers="$persistent_peers,$(test/p2p/ip_plus_id.sh $i $DOCKER_IMAGE):46656" done echo "$persistent_peers" diff --git a/test/p2p/pex/dial_peers.sh b/test/p2p/pex/dial_peers.sh index ddda7dbe7..43ebfab00 100644 --- a/test/p2p/pex/dial_peers.sh +++ b/test/p2p/pex/dial_peers.sh @@ -2,31 +2,22 @@ set -u N=$1 +PEERS=$2 -cd $GOPATH/src/github.com/tendermint/tendermint +cd "$GOPATH/src/github.com/tendermint/tendermint" echo "Waiting for nodes to come online" -for i in `seq 1 $N`; do - addr=$(test/p2p/ip.sh $i):46657 - curl -s $addr/status > /dev/null +for i in $(seq 1 "$N"); do + addr=$(test/p2p/ip.sh "$i"):46657 + curl -s "$addr/status" > /dev/null ERR=$? while [ "$ERR" != 0 ]; do sleep 1 - curl -s $addr/status > /dev/null + curl -s "$addr/status" > /dev/null ERR=$? done echo "... node $i is up" done -set -e -# peers need quotes -peers="\"$(test/p2p/ip.sh 1):46656\"" -for i in `seq 2 $N`; do - peers="$peers,\"$(test/p2p/ip.sh $i):46656\"" -done -echo $peers - -echo $peers IP=$(test/p2p/ip.sh 1) -curl "$IP:46657/dial_peers?persistent=true&peers=\[$peers\]" - +curl "$IP:46657/dial_peers?persistent=true&peers=\\[$PEERS\\]" diff --git a/test/p2p/pex/test_dial_peers.sh b/test/p2p/pex/test_dial_peers.sh index d0b042342..ec386d008 100644 --- a/test/p2p/pex/test_dial_peers.sh +++ b/test/p2p/pex/test_dial_peers.sh @@ -21,14 +21,17 @@ set -e # start the testnet on a local network # NOTE we re-use the same network for all tests -PERSISTENT_PEERS="" -bash test/p2p/local_testnet_start.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP $PERSISTENT_PEERS - +bash test/p2p/local_testnet_start.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP "" +PERSISTENT_PEERS="\"$(test/p2p/ip_plus_id.sh 1 $DOCKER_IMAGE):46656\"" +for i in $(seq 2 $N); do + PERSISTENT_PEERS="$PERSISTENT_PEERS,\"$(test/p2p/ip_plus_id.sh $i $DOCKER_IMAGE):46656\"" +done +echo "$PERSISTENT_PEERS" # dial peers from one node CLIENT_NAME="dial_peers" -bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME $CLIENT_NAME "test/p2p/pex/dial_peers.sh $N" +bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME $CLIENT_NAME "test/p2p/pex/dial_peers.sh $N $PERSISTENT_PEERS" # test basic connectivity and consensus # start client container and check the num peers and height for all nodes diff --git a/test/p2p/test.sh b/test/p2p/test.sh index c95f69733..9493058e0 100644 --- a/test/p2p/test.sh +++ b/test/p2p/test.sh @@ -13,7 +13,7 @@ set +e bash test/p2p/local_testnet_stop.sh "$NETWORK_NAME" "$N" set -e -PERSISTENT_PEERS=$(bash test/p2p/persistent_peers.sh $N) +PERSISTENT_PEERS=$(bash test/p2p/persistent_peers.sh $N $DOCKER_IMAGE) # start the testnet on a local network # NOTE we re-use the same network for all tests diff --git a/types/priv_validator.go b/types/priv_validator.go index 062fe09d2..5072dfa81 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io/ioutil" - "os" "sync" "time" @@ -130,7 +129,7 @@ func LoadPrivValidatorFS(filePath string) *PrivValidatorFS { // or else generates a new one and saves it to the filePath. func LoadOrGenPrivValidatorFS(filePath string) *PrivValidatorFS { var privVal *PrivValidatorFS - if _, err := os.Stat(filePath); err == nil { + if cmn.FileExists(filePath) { privVal = LoadPrivValidatorFS(filePath) } else { privVal = GenPrivValidatorFS(filePath)