Browse Source

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
```
pull/1250/head
Ethan Buchman 7 years ago
committed by Anton Kaliaev
parent
commit
9293ae76bf
30 changed files with 298 additions and 247 deletions
  1. +6
    -0
      CHANGELOG.md
  2. +25
    -0
      cmd/tendermint/commands/show_node_id.go
  3. +1
    -0
      cmd/tendermint/main.go
  4. +4
    -0
      config/config.go
  5. +3
    -0
      config/toml.go
  6. +3
    -0
      docs/specification/configuration.rst
  7. +2
    -2
      node/node.go
  8. +3
    -8
      p2p/node_info.go
  9. +85
    -75
      p2p/peer.go
  10. +2
    -1
      p2p/peer_set_test.go
  11. +13
    -9
      p2p/peer_test.go
  12. +6
    -7
      p2p/pex/pex_reactor.go
  13. +2
    -2
      p2p/pex/pex_reactor_test.go
  14. +68
    -62
      p2p/switch.go
  15. +21
    -11
      p2p/switch_test.go
  16. +7
    -6
      p2p/test_util.go
  17. +1
    -1
      test/docker/Dockerfile
  18. +0
    -20
      test/p2p/data/core/init.sh
  19. +1
    -0
      test/p2p/data/mach1/core/config/node_key.json
  20. +1
    -0
      test/p2p/data/mach2/core/config/node_key.json
  21. +1
    -0
      test/p2p/data/mach3/core/config/node_key.json
  22. +1
    -0
      test/p2p/data/mach4/core/config/node_key.json
  23. +16
    -16
      test/p2p/fast_sync/test_peer.sh
  24. +0
    -2
      test/p2p/ip.sh
  25. +7
    -0
      test/p2p/ip_plus_id.sh
  26. +3
    -2
      test/p2p/persistent_peers.sh
  27. +7
    -16
      test/p2p/pex/dial_peers.sh
  28. +7
    -4
      test/p2p/pex/test_dial_peers.sh
  29. +1
    -1
      test/p2p/test.sh
  30. +1
    -2
      types/priv_validator.go

+ 6
- 0
CHANGELOG.md View File

@ -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:


+ 25
- 0
cmd/tendermint/commands/show_node_id.go View File

@ -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
}

+ 1
- 0
cmd/tendermint/main.go View File

@ -24,6 +24,7 @@ func main() {
cmd.ResetPrivValidatorCmd,
cmd.ShowValidatorCmd,
cmd.TestnetFilesCmd,
cmd.ShowNodeIDCmd,
cmd.VersionCmd)
// NOTE:


+ 4
- 0
config/config.go View File

@ -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,
}
}


+ 3
- 0
config/toml.go View File

@ -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]


+ 3
- 0
docs/specification/configuration.rst View File

@ -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]


+ 2
- 2
node/node.go View File

@ -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
}


+ 3
- 8
p2p/node_info.go View File

@ -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)
}


+ 85
- 75
p2p/peer.go View File

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


+ 2
- 1
p2p/peer_set_test.go View File

@ -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,
},
}
}


+ 13
- 9
p2p/peer_test.go View File

@ -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",


+ 6
- 7
p2p/pex/pex_reactor.go View File

@ -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


+ 2
- 2
p2p/pex/pex_reactor_test.go View File

@ -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)


+ 68
- 62
p2p/switch.go View File

@ -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)


+ 21
- 11
p2p/switch_test.go View File

@ -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()


+ 7
- 6
p2p/test_util.go View File

@ -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
}


+ 1
- 1
test/docker/Dockerfile View File

@ -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


+ 0
- 20
test/p2p/data/core/init.sh View File

@ -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

+ 1
- 0
test/p2p/data/mach1/core/config/node_key.json View File

@ -0,0 +1 @@
{"priv_key":{"type":"ed25519","data":"06962D169F314ABB9D05AE5A04B46E48F0FBD8F1830149B47493910CBDCA7796096E5B94CD179F545AE3C281D9BF5C9E0E3D8FF719048B62F7849094CFFA8591"}}

+ 1
- 0
test/p2p/data/mach2/core/config/node_key.json View File

@ -0,0 +1 @@
{"priv_key":{"type":"ed25519","data":"B8CE8B0D5138C10208526ABDADCE91C735FCCC4186E06E0972EC35E64973428A45EBC61F24CE1B91B3D26AFBAB11C2789EF04CBAC28183619C01116B66A9C528"}}

+ 1
- 0
test/p2p/data/mach3/core/config/node_key.json View File

@ -0,0 +1 @@
{"priv_key":{"type":"ed25519","data":"913DE8AC6D18922A53F6B0196EF023B4693FECFBB565E084F0B4941768F3DAE892B35ADD954562FE071C465BC244B2AFAED4A270EC849269341473CE192DE682"}}

+ 1
- 0
test/p2p/data/mach4/core/config/node_key.json View File

@ -0,0 +1 @@
{"priv_key":{"type":"ed25519","data":"408226F3F40411AC22262DD9A33BFE27D6FED42B9F084906B3797118C951CB82F81552170A85C94F0608AE8B59B70A0CA8B604A9057585B28A266140DC615E97"}}

+ 16
- 16
test/p2p/fast_sync/test_peer.sh View File

@ -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 ""

+ 0
- 2
test/p2p/ip.sh View File

@ -3,5 +3,3 @@ set -eu
ID=$1
echo "172.57.0.$((100+$ID))"

+ 7
- 0
test/p2p/ip_plus_id.sh View File

@ -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))"

+ 3
- 2
test/p2p/persistent_peers.sh View File

@ -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"

+ 7
- 16
test/p2p/pex/dial_peers.sh View File

@ -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\\]"

+ 7
- 4
test/p2p/pex/test_dial_peers.sh View File

@ -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


+ 1
- 1
test/p2p/test.sh View File

@ -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


+ 1
- 2
types/priv_validator.go View File

@ -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)


Loading…
Cancel
Save