Merge pull request #1676 from tendermint/xla/collapse-peerconfig

Collapse PeerConfig into P2PConfig
This commit is contained in:
Ethan Buchman 2018-06-04 18:50:41 -07:00 committed by GitHub
commit fd4db8dfdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 239 additions and 170 deletions

View File

@ -5,6 +5,15 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
tmconn "github.com/tendermint/tendermint/p2p/conn"
)
const (
// FuzzModeDrop is a mode in which we randomly drop reads/writes, connections or sleep
FuzzModeDrop = iota
// FuzzModeDelay is a mode in which we randomly sleep
FuzzModeDelay
) )
// NOTE: Most of the structs & relevant comments + the // NOTE: Most of the structs & relevant comments + the
@ -287,11 +296,24 @@ type P2PConfig struct {
// Does not work if the peer-exchange reactor is disabled. // Does not work if the peer-exchange reactor is disabled.
SeedMode bool `mapstructure:"seed_mode"` SeedMode bool `mapstructure:"seed_mode"`
// Comma separated list of peer IDs to keep private (will not be gossiped to other peers) // Comma separated list of peer IDs to keep private (will not be gossiped to
// other peers)
PrivatePeerIDs string `mapstructure:"private_peer_ids"` PrivatePeerIDs string `mapstructure:"private_peer_ids"`
// Toggle to disable guard against peers connecting from the same ip. // Toggle to disable guard against peers connecting from the same ip.
AllowDuplicateIP bool `mapstructure:"allow_duplicate_ip"` AllowDuplicateIP bool `mapstructure:"allow_duplicate_ip"`
// Peer connection configuration.
HandshakeTimeout time.Duration `mapstructure:"handshake_timeout"`
DialTimeout time.Duration `mapstructure:"dial_timeout"`
MConfig tmconn.MConnConfig `mapstructure:"connection"`
// Testing params.
// Force dial to fail
TestDialFail bool `mapstructure:"test_dial_fail"`
// FUzz connection
TestFuzz bool `mapstructure:"test_fuzz"`
TestFuzzConfig *FuzzConnConfig `mapstructure:"test_fuzz_config"`
} }
// DefaultP2PConfig returns a default configuration for the peer-to-peer layer // DefaultP2PConfig returns a default configuration for the peer-to-peer layer
@ -308,6 +330,12 @@ func DefaultP2PConfig() *P2PConfig {
PexReactor: true, PexReactor: true,
SeedMode: false, SeedMode: false,
AllowDuplicateIP: true, // so non-breaking yet AllowDuplicateIP: true, // so non-breaking yet
HandshakeTimeout: 20 * time.Second,
DialTimeout: 3 * time.Second,
MConfig: tmconn.DefaultMConnConfig(),
TestDialFail: false,
TestFuzz: false,
TestFuzzConfig: DefaultFuzzConnConfig(),
} }
} }
@ -326,6 +354,26 @@ func (cfg *P2PConfig) AddrBookFile() string {
return rootify(cfg.AddrBook, cfg.RootDir) return rootify(cfg.AddrBook, cfg.RootDir)
} }
// FuzzConnConfig is a FuzzedConnection configuration.
type FuzzConnConfig struct {
Mode int
MaxDelay time.Duration
ProbDropRW float64
ProbDropConn float64
ProbSleep float64
}
// DefaultFuzzConnConfig returns the default config.
func DefaultFuzzConnConfig() *FuzzConnConfig {
return &FuzzConnConfig{
Mode: FuzzModeDrop,
MaxDelay: 3 * time.Second,
ProbDropRW: 0.2,
ProbDropConn: 0.00,
ProbSleep: 0.00,
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// MempoolConfig // MempoolConfig

View File

@ -83,7 +83,7 @@ type MConnection struct {
onReceive receiveCbFunc onReceive receiveCbFunc
onError errorCbFunc onError errorCbFunc
errored uint32 errored uint32
config *MConnConfig config MConnConfig
quit chan struct{} quit chan struct{}
flushTimer *cmn.ThrottleTimer // flush writes as necessary but throttled. flushTimer *cmn.ThrottleTimer // flush writes as necessary but throttled.
@ -121,8 +121,8 @@ func (cfg *MConnConfig) maxPacketMsgTotalSize() int {
} }
// DefaultMConnConfig returns the default config. // DefaultMConnConfig returns the default config.
func DefaultMConnConfig() *MConnConfig { func DefaultMConnConfig() MConnConfig {
return &MConnConfig{ return MConnConfig{
SendRate: defaultSendRate, SendRate: defaultSendRate,
RecvRate: defaultRecvRate, RecvRate: defaultRecvRate,
MaxPacketMsgPayloadSize: maxPacketMsgPayloadSizeDefault, MaxPacketMsgPayloadSize: maxPacketMsgPayloadSizeDefault,
@ -143,7 +143,7 @@ func NewMConnection(conn net.Conn, chDescs []*ChannelDescriptor, onReceive recei
} }
// NewMConnectionWithConfig wraps net.Conn and creates multiplex connection with a config // NewMConnectionWithConfig wraps net.Conn and creates multiplex connection with a config
func NewMConnectionWithConfig(conn net.Conn, chDescs []*ChannelDescriptor, onReceive receiveCbFunc, onError errorCbFunc, config *MConnConfig) *MConnection { func NewMConnectionWithConfig(conn net.Conn, chDescs []*ChannelDescriptor, onReceive receiveCbFunc, onError errorCbFunc, config MConnConfig) *MConnection {
if config.PongTimeout >= config.PingInterval { if config.PongTimeout >= config.PingInterval {
panic("pongTimeout must be less than pingInterval (otherwise, next ping will reset pong timer)") panic("pongTimeout must be less than pingInterval (otherwise, next ping will reset pong timer)")
} }

View File

@ -5,16 +5,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/tendermint/tendermint/config"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
) )
const (
// FuzzModeDrop is a mode in which we randomly drop reads/writes, connections or sleep
FuzzModeDrop = iota
// FuzzModeDelay is a mode in which we randomly sleep
FuzzModeDelay
)
// FuzzedConnection wraps any net.Conn and depending on the mode either delays // FuzzedConnection wraps any net.Conn and depending on the mode either delays
// reads/writes or randomly drops reads/writes/connections. // reads/writes or randomly drops reads/writes/connections.
type FuzzedConnection struct { type FuzzedConnection struct {
@ -24,37 +18,17 @@ type FuzzedConnection struct {
start <-chan time.Time start <-chan time.Time
active bool active bool
config *FuzzConnConfig config *config.FuzzConnConfig
}
// FuzzConnConfig is a FuzzedConnection configuration.
type FuzzConnConfig struct {
Mode int
MaxDelay time.Duration
ProbDropRW float64
ProbDropConn float64
ProbSleep float64
}
// DefaultFuzzConnConfig returns the default config.
func DefaultFuzzConnConfig() *FuzzConnConfig {
return &FuzzConnConfig{
Mode: FuzzModeDrop,
MaxDelay: 3 * time.Second,
ProbDropRW: 0.2,
ProbDropConn: 0.00,
ProbSleep: 0.00,
}
} }
// FuzzConn creates a new FuzzedConnection. Fuzzing starts immediately. // FuzzConn creates a new FuzzedConnection. Fuzzing starts immediately.
func FuzzConn(conn net.Conn) net.Conn { func FuzzConn(conn net.Conn) net.Conn {
return FuzzConnFromConfig(conn, DefaultFuzzConnConfig()) return FuzzConnFromConfig(conn, config.DefaultFuzzConnConfig())
} }
// FuzzConnFromConfig creates a new FuzzedConnection from a config. Fuzzing // FuzzConnFromConfig creates a new FuzzedConnection from a config. Fuzzing
// starts immediately. // starts immediately.
func FuzzConnFromConfig(conn net.Conn, config *FuzzConnConfig) net.Conn { func FuzzConnFromConfig(conn net.Conn, config *config.FuzzConnConfig) net.Conn {
return &FuzzedConnection{ return &FuzzedConnection{
conn: conn, conn: conn,
start: make(<-chan time.Time), start: make(<-chan time.Time),
@ -66,12 +40,16 @@ func FuzzConnFromConfig(conn net.Conn, config *FuzzConnConfig) net.Conn {
// FuzzConnAfter creates a new FuzzedConnection. Fuzzing starts when the // FuzzConnAfter creates a new FuzzedConnection. Fuzzing starts when the
// duration elapses. // duration elapses.
func FuzzConnAfter(conn net.Conn, d time.Duration) net.Conn { func FuzzConnAfter(conn net.Conn, d time.Duration) net.Conn {
return FuzzConnAfterFromConfig(conn, d, DefaultFuzzConnConfig()) return FuzzConnAfterFromConfig(conn, d, config.DefaultFuzzConnConfig())
} }
// FuzzConnAfterFromConfig creates a new FuzzedConnection from a config. // FuzzConnAfterFromConfig creates a new FuzzedConnection from a config.
// Fuzzing starts when the duration elapses. // Fuzzing starts when the duration elapses.
func FuzzConnAfterFromConfig(conn net.Conn, d time.Duration, config *FuzzConnConfig) net.Conn { func FuzzConnAfterFromConfig(
conn net.Conn,
d time.Duration,
config *config.FuzzConnConfig,
) net.Conn {
return &FuzzedConnection{ return &FuzzedConnection{
conn: conn, conn: conn,
start: time.After(d), start: time.After(d),
@ -81,7 +59,7 @@ func FuzzConnAfterFromConfig(conn net.Conn, d time.Duration, config *FuzzConnCon
} }
// Config returns the connection's config. // Config returns the connection's config.
func (fc *FuzzedConnection) Config() *FuzzConnConfig { func (fc *FuzzedConnection) Config() *config.FuzzConnConfig {
return fc.config return fc.config
} }
@ -136,7 +114,7 @@ func (fc *FuzzedConnection) fuzz() bool {
} }
switch fc.config.Mode { switch fc.config.Mode {
case FuzzModeDrop: case config.FuzzModeDrop:
// randomly drop the r/w, drop the conn, or sleep // randomly drop the r/w, drop the conn, or sleep
r := cmn.RandFloat64() r := cmn.RandFloat64()
if r <= fc.config.ProbDropRW { if r <= fc.config.ProbDropRW {
@ -149,7 +127,7 @@ func (fc *FuzzedConnection) fuzz() bool {
} else if r < fc.config.ProbDropRW+fc.config.ProbDropConn+fc.config.ProbSleep { } else if r < fc.config.ProbDropRW+fc.config.ProbDropConn+fc.config.ProbSleep {
time.Sleep(fc.randomDuration()) time.Sleep(fc.randomDuration())
} }
case FuzzModeDelay: case config.FuzzModeDelay:
// sleep a bit // sleep a bit
time.Sleep(fc.randomDuration()) time.Sleep(fc.randomDuration())
} }

View File

@ -10,10 +10,11 @@ import (
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/config"
tmconn "github.com/tendermint/tendermint/p2p/conn" tmconn "github.com/tendermint/tendermint/p2p/conn"
) )
var testIPSuffix uint32 = 0 var testIPSuffix uint32
// Peer is an interface representing a peer connected on a reactor. // Peer is an interface representing a peer connected on a reactor.
type Peer interface { type Peer interface {
@ -39,7 +40,7 @@ type Peer interface {
type peerConn struct { type peerConn struct {
outbound bool outbound bool
persistent bool persistent bool
config *PeerConfig config *config.P2PConfig
conn net.Conn // source connection conn net.Conn // source connection
ip net.IP ip net.IP
} }
@ -99,94 +100,95 @@ type peer struct {
Data *cmn.CMap Data *cmn.CMap
} }
func newPeer(pc peerConn, nodeInfo NodeInfo, func newPeer(
reactorsByCh map[byte]Reactor, chDescs []*tmconn.ChannelDescriptor, pc peerConn,
onPeerError func(Peer, interface{})) *peer { nodeInfo NodeInfo,
reactorsByCh map[byte]Reactor,
chDescs []*tmconn.ChannelDescriptor,
onPeerError func(Peer, interface{}),
) *peer {
p := &peer{ p := &peer{
peerConn: pc, peerConn: pc,
nodeInfo: nodeInfo, nodeInfo: nodeInfo,
channels: nodeInfo.Channels, channels: nodeInfo.Channels,
Data: cmn.NewCMap(), Data: cmn.NewCMap(),
} }
p.mconn = createMConnection(pc.conn, p, reactorsByCh, chDescs, onPeerError, pc.config.MConfig)
p.mconn = createMConnection(
pc.conn,
p,
reactorsByCh,
chDescs,
onPeerError,
pc.config.MConfig,
)
p.BaseService = *cmn.NewBaseService(nil, "Peer", p) p.BaseService = *cmn.NewBaseService(nil, "Peer", p)
return p return p
} }
// PeerConfig is a Peer configuration. func newOutboundPeerConn(
type PeerConfig struct { addr *NetAddress,
// times are in seconds config *config.P2PConfig,
HandshakeTimeout time.Duration `mapstructure:"handshake_timeout"` persistent bool,
DialTimeout time.Duration `mapstructure:"dial_timeout"` ourNodePrivKey crypto.PrivKey,
) (peerConn, error) {
MConfig *tmconn.MConnConfig `mapstructure:"connection"`
DialFail bool `mapstructure:"dial_fail"` // for testing
Fuzz bool `mapstructure:"fuzz"` // fuzz connection (for testing)
FuzzConfig *FuzzConnConfig `mapstructure:"fuzz_config"`
}
// DefaultPeerConfig returns the default config.
func DefaultPeerConfig() *PeerConfig {
return &PeerConfig{
HandshakeTimeout: 20, // * time.Second,
DialTimeout: 3, // * time.Second,
MConfig: tmconn.DefaultMConnConfig(),
DialFail: false,
Fuzz: false,
FuzzConfig: DefaultFuzzConnConfig(),
}
}
func newOutboundPeerConn(addr *NetAddress, config *PeerConfig, persistent bool, ourNodePrivKey crypto.PrivKey) (peerConn, error) {
var pc peerConn
conn, err := dial(addr, config) conn, err := dial(addr, config)
if err != nil { if err != nil {
return pc, cmn.ErrorWrap(err, "Error creating peer") return peerConn{}, cmn.ErrorWrap(err, "Error creating peer")
} }
pc, err = newPeerConn(conn, config, true, persistent, ourNodePrivKey) pc, err := newPeerConn(conn, config, true, persistent, ourNodePrivKey)
if err != nil { if err != nil {
if err2 := conn.Close(); err2 != nil { if cerr := conn.Close(); cerr != nil {
return pc, cmn.ErrorWrap(err, err2.Error()) return peerConn{}, cmn.ErrorWrap(err, cerr.Error())
} }
return pc, err return peerConn{}, err
} }
// ensure dialed ID matches connection ID // ensure dialed ID matches connection ID
if addr.ID != pc.ID() { if addr.ID != pc.ID() {
if err2 := conn.Close(); err2 != nil { if cerr := conn.Close(); cerr != nil {
return pc, cmn.ErrorWrap(err, err2.Error()) return peerConn{}, cmn.ErrorWrap(err, cerr.Error())
} }
return pc, ErrSwitchAuthenticationFailure{addr, pc.ID()} return peerConn{}, ErrSwitchAuthenticationFailure{addr, pc.ID()}
} }
return pc, nil return pc, nil
} }
func newInboundPeerConn(conn net.Conn, config *PeerConfig, ourNodePrivKey crypto.PrivKey) (peerConn, error) { func newInboundPeerConn(
conn net.Conn,
config *config.P2PConfig,
ourNodePrivKey crypto.PrivKey,
) (peerConn, error) {
// TODO: issue PoW challenge // TODO: issue PoW challenge
return newPeerConn(conn, config, false, false, ourNodePrivKey) return newPeerConn(conn, config, false, false, ourNodePrivKey)
} }
func newPeerConn(rawConn net.Conn, func newPeerConn(
config *PeerConfig, outbound, persistent bool, rawConn net.Conn,
ourNodePrivKey crypto.PrivKey) (pc peerConn, err error) { cfg *config.P2PConfig,
outbound, persistent bool,
ourNodePrivKey crypto.PrivKey,
) (pc peerConn, err error) {
conn := rawConn conn := rawConn
// Fuzz connection // Fuzz connection
if config.Fuzz { if cfg.TestFuzz {
// so we have time to do peer handshakes and get set up // so we have time to do peer handshakes and get set up
conn = FuzzConnAfterFromConfig(conn, 10*time.Second, config.FuzzConfig) conn = FuzzConnAfterFromConfig(conn, 10*time.Second, cfg.TestFuzzConfig)
} }
// Set deadline for secret handshake // Set deadline for secret handshake
if err := conn.SetDeadline(time.Now().Add(config.HandshakeTimeout * time.Second)); err != nil { dl := time.Now().Add(cfg.HandshakeTimeout)
return pc, cmn.ErrorWrap(err, "Error setting deadline while encrypting connection") if err := conn.SetDeadline(dl); err != nil {
return pc, cmn.ErrorWrap(
err,
"Error setting deadline while encrypting connection",
)
} }
// Encrypt connection // Encrypt connection
@ -197,7 +199,7 @@ func newPeerConn(rawConn net.Conn,
// Only the information we already have // Only the information we already have
return peerConn{ return peerConn{
config: config, config: cfg,
outbound: outbound, outbound: outbound,
persistent: persistent, persistent: persistent,
conn: conn, conn: conn,
@ -300,22 +302,33 @@ func (p *peer) hasChannel(chID byte) bool {
} }
// NOTE: probably will want to remove this // NOTE: probably will want to remove this
// but could be helpful while the feature is new // but could be helpful while the feature is new
p.Logger.Debug("Unknown channel for peer", "channel", chID, "channels", p.channels) p.Logger.Debug(
"Unknown channel for peer",
"channel",
chID,
"channels",
p.channels,
)
return false return false
} }
//--------------------------------------------------- //---------------------------------------------------
// methods used by the Switch // methods used by the Switch
// CloseConn should be called by the Switch if the peer was created but never started. // CloseConn should be called by the Switch if the peer was created but never
// started.
func (pc *peerConn) CloseConn() { func (pc *peerConn) CloseConn() {
pc.conn.Close() // nolint: errcheck pc.conn.Close() // nolint: errcheck
} }
// HandshakeTimeout performs the Tendermint P2P handshake between a given node and the peer // HandshakeTimeout performs the Tendermint P2P handshake between a given node
// by exchanging their NodeInfo. It sets the received nodeInfo on the peer. // and the peer by exchanging their NodeInfo. It sets the received nodeInfo on
// the peer.
// NOTE: blocking // NOTE: blocking
func (pc *peerConn) HandshakeTimeout(ourNodeInfo NodeInfo, timeout time.Duration) (peerNodeInfo NodeInfo, err 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 // Set deadline for handshake so we don't block forever on conn.ReadFull
if err := pc.conn.SetDeadline(time.Now().Add(timeout)); err != nil { if err := pc.conn.SetDeadline(time.Now().Add(timeout)); err != nil {
return peerNodeInfo, cmn.ErrorWrap(err, "Error setting deadline") return peerNodeInfo, cmn.ErrorWrap(err, "Error setting deadline")
@ -327,7 +340,11 @@ func (pc *peerConn) HandshakeTimeout(ourNodeInfo NodeInfo, timeout time.Duration
return return
}, },
func(_ int) (val interface{}, err error, abort bool) { func(_ int) (val interface{}, err error, abort bool) {
_, err = cdc.UnmarshalBinaryReader(pc.conn, &peerNodeInfo, int64(MaxNodeInfoSize())) _, err = cdc.UnmarshalBinaryReader(
pc.conn,
&peerNodeInfo,
int64(MaxNodeInfoSize()),
)
return return
}, },
) )
@ -368,20 +385,26 @@ func (p *peer) String() string {
//------------------------------------------------------------------ //------------------------------------------------------------------
// helper funcs // helper funcs
func dial(addr *NetAddress, config *PeerConfig) (net.Conn, error) { func dial(addr *NetAddress, cfg *config.P2PConfig) (net.Conn, error) {
if config.DialFail { if cfg.TestDialFail {
return nil, fmt.Errorf("dial err (peerConfig.DialFail == true)") return nil, fmt.Errorf("dial err (peerConfig.DialFail == true)")
} }
conn, err := addr.DialTimeout(config.DialTimeout * time.Second) conn, err := addr.DialTimeout(cfg.DialTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return conn, nil return conn, nil
} }
func createMConnection(conn net.Conn, p *peer, reactorsByCh map[byte]Reactor, chDescs []*tmconn.ChannelDescriptor, func createMConnection(
onPeerError func(Peer, interface{}), config *tmconn.MConnConfig) *tmconn.MConnection { conn net.Conn,
p *peer,
reactorsByCh map[byte]Reactor,
chDescs []*tmconn.ChannelDescriptor,
onPeerError func(Peer, interface{}),
config tmconn.MConnConfig,
) *tmconn.MConnection {
onReceive := func(chID byte, msgBytes []byte) { onReceive := func(chID byte, msgBytes []byte) {
reactor := reactorsByCh[chID] reactor := reactorsByCh[chID]
@ -397,5 +420,11 @@ func createMConnection(conn net.Conn, p *peer, reactorsByCh map[byte]Reactor, ch
onPeerError(p, r) onPeerError(p, r)
} }
return tmconn.NewMConnectionWithConfig(conn, chDescs, onReceive, onError, config) return tmconn.NewMConnectionWithConfig(
conn,
chDescs,
onReceive,
onError,
config,
)
} }

View File

@ -10,9 +10,11 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
tmconn "github.com/tendermint/tendermint/p2p/conn"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/config"
tmconn "github.com/tendermint/tendermint/p2p/conn"
) )
const testCh = 0x01 const testCh = 0x01
@ -21,11 +23,11 @@ func TestPeerBasic(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
// simulate remote peer // simulate remote peer
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: DefaultPeerConfig()} rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: cfg}
rp.Start() rp.Start()
defer rp.Stop() defer rp.Stop()
p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), DefaultPeerConfig()) p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), cfg)
require.Nil(err) require.Nil(err)
err = p.Start() err = p.Start()
@ -44,7 +46,7 @@ func TestPeerBasic(t *testing.T) {
func TestPeerSend(t *testing.T) { func TestPeerSend(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
config := DefaultPeerConfig() config := cfg
// simulate remote peer // simulate remote peer
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: config} rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: config}
@ -63,7 +65,7 @@ func TestPeerSend(t *testing.T) {
assert.True(p.Send(testCh, []byte("Asylum"))) assert.True(p.Send(testCh, []byte("Asylum")))
} }
func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *PeerConfig) (*peer, error) { func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *config.P2PConfig) (*peer, error) {
chDescs := []*tmconn.ChannelDescriptor{ chDescs := []*tmconn.ChannelDescriptor{
{ID: testCh, Priority: 1}, {ID: testCh, Priority: 1},
} }
@ -91,7 +93,7 @@ func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *PeerConfig)
type remotePeer struct { type remotePeer struct {
PrivKey crypto.PrivKey PrivKey crypto.PrivKey
Config *PeerConfig Config *config.P2PConfig
addr *NetAddress addr *NetAddress
quit chan struct{} quit chan struct{}
channels cmn.HexBytes channels cmn.HexBytes

View File

@ -13,21 +13,22 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/p2p/conn"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/p2p/conn"
) )
var ( var (
config *cfg.P2PConfig cfg *config.P2PConfig
) )
func init() { func init() {
config = cfg.DefaultP2PConfig() cfg = config.DefaultP2PConfig()
config.PexReactor = true cfg.PexReactor = true
config.AllowDuplicateIP = true cfg.AllowDuplicateIP = true
} }
func TestPEXReactorBasic(t *testing.T) { func TestPEXReactorBasic(t *testing.T) {
@ -81,7 +82,7 @@ func TestPEXReactorRunning(t *testing.T) {
// create switches // create switches
for i := 0; i < N; i++ { for i := 0; i < N; i++ {
switches[i] = p2p.MakeSwitch(config, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false) books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
books[i].SetLogger(logger.With("pex", i)) books[i].SetLogger(logger.With("pex", i))
sw.SetAddrBook(books[i]) sw.SetAddrBook(books[i])
@ -209,7 +210,7 @@ func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
// 1. create seed // 1. create seed
seed := p2p.MakeSwitch( seed := p2p.MakeSwitch(
config, cfg,
0, 0,
"127.0.0.1", "127.0.0.1",
"123.123.123", "123.123.123",
@ -239,7 +240,7 @@ func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
// 2. create usual peer with only seed configured. // 2. create usual peer with only seed configured.
peer := p2p.MakeSwitch( peer := p2p.MakeSwitch(
config, cfg,
1, 1,
"127.0.0.1", "127.0.0.1",
"123.123.123", "123.123.123",
@ -425,7 +426,7 @@ func assertPeersWithTimeout(
} }
} }
func createReactor(config *PEXReactorConfig) (r *PEXReactor, book *addrBook) { func createReactor(conf *PEXReactorConfig) (r *PEXReactor, book *addrBook) {
// directory to store address book // directory to store address book
dir, err := ioutil.TempDir("", "pex_reactor") dir, err := ioutil.TempDir("", "pex_reactor")
if err != nil { if err != nil {
@ -434,7 +435,7 @@ func createReactor(config *PEXReactorConfig) (r *PEXReactor, book *addrBook) {
book = NewAddrBook(filepath.Join(dir, "addrbook.json"), true) book = NewAddrBook(filepath.Join(dir, "addrbook.json"), true)
book.SetLogger(log.TestingLogger()) book.SetLogger(log.TestingLogger())
r = NewPEXReactor(book, config) r = NewPEXReactor(book, conf)
r.SetLogger(log.TestingLogger()) r.SetLogger(log.TestingLogger())
return return
} }
@ -447,7 +448,7 @@ func teardownReactor(book *addrBook) {
} }
func createSwitchAndAddReactors(reactors ...p2p.Reactor) *p2p.Switch { func createSwitchAndAddReactors(reactors ...p2p.Reactor) *p2p.Switch {
sw := p2p.MakeSwitch(config, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw }) sw := p2p.MakeSwitch(cfg, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
sw.SetLogger(log.TestingLogger()) sw.SetLogger(log.TestingLogger())
for _, r := range reactors { for _, r := range reactors {
sw.AddReactor(r.String(), r) sw.AddReactor(r.String(), r)

View File

@ -7,7 +7,7 @@ import (
"sync" "sync"
"time" "time"
cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p/conn" "github.com/tendermint/tendermint/p2p/conn"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
) )
@ -55,8 +55,7 @@ type AddrBook interface {
type Switch struct { type Switch struct {
cmn.BaseService cmn.BaseService
config *cfg.P2PConfig config *config.P2PConfig
peerConfig *PeerConfig
listeners []Listener listeners []Listener
reactors map[string]Reactor reactors map[string]Reactor
chDescs []*conn.ChannelDescriptor chDescs []*conn.ChannelDescriptor
@ -75,10 +74,9 @@ type Switch struct {
} }
// NewSwitch creates a new Switch with the given config. // NewSwitch creates a new Switch with the given config.
func NewSwitch(config *cfg.P2PConfig) *Switch { func NewSwitch(cfg *config.P2PConfig) *Switch {
sw := &Switch{ sw := &Switch{
config: config, config: cfg,
peerConfig: DefaultPeerConfig(),
reactors: make(map[string]Reactor), reactors: make(map[string]Reactor),
chDescs: make([]*conn.ChannelDescriptor, 0), chDescs: make([]*conn.ChannelDescriptor, 0),
reactorsByCh: make(map[byte]Reactor), reactorsByCh: make(map[byte]Reactor),
@ -90,11 +88,10 @@ func NewSwitch(config *cfg.P2PConfig) *Switch {
// Ensure we have a completely undeterministic PRNG. // Ensure we have a completely undeterministic PRNG.
sw.rng = cmn.NewRand() sw.rng = cmn.NewRand()
// TODO: collapse the peerConfig into the config ? sw.config.MConfig.FlushThrottle = time.Duration(cfg.FlushThrottleTimeout) * time.Millisecond
sw.peerConfig.MConfig.FlushThrottle = time.Duration(config.FlushThrottleTimeout) * time.Millisecond sw.config.MConfig.SendRate = cfg.SendRate
sw.peerConfig.MConfig.SendRate = config.SendRate sw.config.MConfig.RecvRate = cfg.RecvRate
sw.peerConfig.MConfig.RecvRate = config.RecvRate sw.config.MConfig.MaxPacketMsgPayloadSize = cfg.MaxPacketMsgPayloadSize
sw.peerConfig.MConfig.MaxPacketMsgPayloadSize = config.MaxPacketMsgPayloadSize
sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw) sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw)
return sw return sw
@ -419,7 +416,7 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b
func (sw *Switch) DialPeerWithAddress(addr *NetAddress, persistent bool) error { func (sw *Switch) DialPeerWithAddress(addr *NetAddress, persistent bool) error {
sw.dialing.Set(string(addr.ID), addr) sw.dialing.Set(string(addr.ID), addr)
defer sw.dialing.Delete(string(addr.ID)) defer sw.dialing.Delete(string(addr.ID))
return sw.addOutboundPeerWithConfig(addr, sw.peerConfig, persistent) return sw.addOutboundPeerWithConfig(addr, sw.config, persistent)
} }
// sleep for interval plus some random amount of ms on [0, dialRandomizerIntervalMilliseconds] // sleep for interval plus some random amount of ms on [0, dialRandomizerIntervalMilliseconds]
@ -476,7 +473,7 @@ func (sw *Switch) listenerRoutine(l Listener) {
} }
// New inbound connection! // New inbound connection!
err := sw.addInboundPeerWithConfig(inConn, sw.peerConfig) err := sw.addInboundPeerWithConfig(inConn, sw.config)
if err != nil { if err != nil {
sw.Logger.Info("Ignoring inbound connection: error while adding peer", "address", inConn.RemoteAddr().String(), "err", err) sw.Logger.Info("Ignoring inbound connection: error while adding peer", "address", inConn.RemoteAddr().String(), "err", err)
continue continue
@ -486,7 +483,10 @@ func (sw *Switch) listenerRoutine(l Listener) {
// cleanup // cleanup
} }
func (sw *Switch) addInboundPeerWithConfig(conn net.Conn, config *PeerConfig) error { func (sw *Switch) addInboundPeerWithConfig(
conn net.Conn,
config *config.P2PConfig,
) error {
peerConn, err := newInboundPeerConn(conn, config, sw.nodeKey.PrivKey) peerConn, err := newInboundPeerConn(conn, config, sw.nodeKey.PrivKey)
if err != nil { if err != nil {
conn.Close() // peer is nil conn.Close() // peer is nil
@ -503,10 +503,20 @@ func (sw *Switch) addInboundPeerWithConfig(conn net.Conn, config *PeerConfig) er
// dial the peer; make secret connection; authenticate against the dialed ID; // dial the peer; make secret connection; authenticate against the dialed ID;
// add the peer. // add the peer.
// if dialing fails, start the reconnect loop. If handhsake fails, its over. // if dialing fails, start the reconnect loop. If handhsake fails, its over.
// If peer is started succesffuly, reconnectLoop will start when StopPeerForError is called // If peer is started succesffuly, reconnectLoop will start when
func (sw *Switch) addOutboundPeerWithConfig(addr *NetAddress, config *PeerConfig, persistent bool) error { // StopPeerForError is called
func (sw *Switch) addOutboundPeerWithConfig(
addr *NetAddress,
config *config.P2PConfig,
persistent bool,
) error {
sw.Logger.Info("Dialing peer", "address", addr) sw.Logger.Info("Dialing peer", "address", addr)
peerConn, err := newOutboundPeerConn(addr, config, persistent, sw.nodeKey.PrivKey) peerConn, err := newOutboundPeerConn(
addr,
config,
persistent,
sw.nodeKey.PrivKey,
)
if err != nil { if err != nil {
if persistent { if persistent {
go sw.reconnectToPeer(addr) go sw.reconnectToPeer(addr)
@ -525,7 +535,8 @@ func (sw *Switch) addOutboundPeerWithConfig(addr *NetAddress, config *PeerConfig
// that already has a SecretConnection. If all goes well, // that already has a SecretConnection. If all goes well,
// it starts the peer and adds it to the switch. // it starts the peer and adds it to the switch.
// NOTE: This performs a blocking handshake before the peer is added. // NOTE: This performs a blocking handshake before the peer is added.
// NOTE: If error is returned, caller is responsible for calling peer.CloseConn() // NOTE: If error is returned, caller is responsible for calling
// peer.CloseConn()
func (sw *Switch) addPeer(pc peerConn) error { func (sw *Switch) addPeer(pc peerConn) error {
addr := pc.conn.RemoteAddr() addr := pc.conn.RemoteAddr()
@ -534,7 +545,7 @@ func (sw *Switch) addPeer(pc peerConn) error {
} }
// Exchange NodeInfo on the conn // Exchange NodeInfo on the conn
peerNodeInfo, err := pc.HandshakeTimeout(sw.nodeInfo, time.Duration(sw.peerConfig.HandshakeTimeout*time.Second)) peerNodeInfo, err := pc.HandshakeTimeout(sw.nodeInfo, time.Duration(sw.config.HandshakeTimeout))
if err != nil { if err != nil {
return err return err
} }

View File

@ -14,18 +14,18 @@ import (
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p/conn" "github.com/tendermint/tendermint/p2p/conn"
) )
var ( var (
config *cfg.P2PConfig cfg *config.P2PConfig
) )
func init() { func init() {
config = cfg.DefaultP2PConfig() cfg = config.DefaultP2PConfig()
config.PexReactor = true cfg.PexReactor = true
config.AllowDuplicateIP = true cfg.AllowDuplicateIP = true
} }
type PeerMessage struct { type PeerMessage struct {
@ -85,7 +85,7 @@ func (tr *TestReactor) getMsgs(chID byte) []PeerMessage {
// XXX: note this uses net.Pipe and not a proper TCP conn // XXX: note this uses net.Pipe and not a proper TCP conn
func MakeSwitchPair(t testing.TB, initSwitch func(int, *Switch) *Switch) (*Switch, *Switch) { func MakeSwitchPair(t testing.TB, initSwitch func(int, *Switch) *Switch) (*Switch, *Switch) {
// Create two switches that will be interconnected. // Create two switches that will be interconnected.
switches := MakeConnectedSwitches(config, 2, initSwitch, Connect2Switches) switches := MakeConnectedSwitches(cfg, 2, initSwitch, Connect2Switches)
return switches[0], switches[1] return switches[0], switches[1]
} }
@ -152,8 +152,8 @@ func assertMsgReceivedWithTimeout(t *testing.T, msgBytes []byte, channel byte, r
} }
func TestConnAddrFilter(t *testing.T) { func TestConnAddrFilter(t *testing.T) {
s1 := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) s1 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
s2 := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) s2 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
defer s1.Stop() defer s1.Stop()
defer s2.Stop() defer s2.Stop()
@ -181,14 +181,14 @@ func TestConnAddrFilter(t *testing.T) {
} }
func TestSwitchFiltersOutItself(t *testing.T) { func TestSwitchFiltersOutItself(t *testing.T) {
s1 := MakeSwitch(config, 1, "127.0.0.1", "123.123.123", initSwitchFunc) s1 := MakeSwitch(cfg, 1, "127.0.0.1", "123.123.123", initSwitchFunc)
// addr := s1.NodeInfo().NetAddress() // addr := s1.NodeInfo().NetAddress()
// // add ourselves like we do in node.go#427 // // add ourselves like we do in node.go#427
// s1.addrBook.AddOurAddress(addr) // s1.addrBook.AddOurAddress(addr)
// simulate s1 having a public IP by creating a remote peer with the same ID // simulate s1 having a public IP by creating a remote peer with the same ID
rp := &remotePeer{PrivKey: s1.nodeKey.PrivKey, Config: DefaultPeerConfig()} rp := &remotePeer{PrivKey: s1.nodeKey.PrivKey, Config: cfg}
rp.Start() rp.Start()
// addr should be rejected in addPeer based on the same ID // addr should be rejected in addPeer based on the same ID
@ -214,8 +214,8 @@ func assertNoPeersAfterTimeout(t *testing.T, sw *Switch, timeout time.Duration)
} }
func TestConnIDFilter(t *testing.T) { func TestConnIDFilter(t *testing.T) {
s1 := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) s1 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
s2 := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) s2 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
defer s1.Stop() defer s1.Stop()
defer s2.Stop() defer s2.Stop()
@ -251,7 +251,7 @@ func TestConnIDFilter(t *testing.T) {
func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) { func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
sw := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
err := sw.Start() err := sw.Start()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -259,11 +259,11 @@ func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) {
defer sw.Stop() defer sw.Stop()
// simulate remote peer // simulate remote peer
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: DefaultPeerConfig()} rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: cfg}
rp.Start() rp.Start()
defer rp.Stop() defer rp.Stop()
pc, err := newOutboundPeerConn(rp.Addr(), DefaultPeerConfig(), false, sw.nodeKey.PrivKey) pc, err := newOutboundPeerConn(rp.Addr(), cfg, false, sw.nodeKey.PrivKey)
require.Nil(err) require.Nil(err)
err = sw.addPeer(pc) err = sw.addPeer(pc)
require.Nil(err) require.Nil(err)
@ -281,7 +281,7 @@ func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) {
func TestSwitchReconnectsToPersistentPeer(t *testing.T) { func TestSwitchReconnectsToPersistentPeer(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
sw := MakeSwitch(config, 1, "testing", "123.123.123", initSwitchFunc) sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
err := sw.Start() err := sw.Start()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -289,11 +289,11 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) {
defer sw.Stop() defer sw.Stop()
// simulate remote peer // simulate remote peer
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: DefaultPeerConfig()} rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: cfg}
rp.Start() rp.Start()
defer rp.Stop() defer rp.Stop()
pc, err := newOutboundPeerConn(rp.Addr(), DefaultPeerConfig(), true, sw.nodeKey.PrivKey) pc, err := newOutboundPeerConn(rp.Addr(), cfg, true, sw.nodeKey.PrivKey)
// sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, // sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey,
require.Nil(err) require.Nil(err)
@ -320,7 +320,7 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) {
// simulate another remote peer // simulate another remote peer
rp = &remotePeer{ rp = &remotePeer{
PrivKey: crypto.GenPrivKeyEd25519(), PrivKey: crypto.GenPrivKeyEd25519(),
Config: DefaultPeerConfig(), Config: cfg,
// Use different interface to prevent duplicate IP filter, this will break // Use different interface to prevent duplicate IP filter, this will break
// beyond two peers. // beyond two peers.
listenAddr: "127.0.0.1:0", listenAddr: "127.0.0.1:0",
@ -329,9 +329,9 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) {
defer rp.Stop() defer rp.Stop()
// simulate first time dial failure // simulate first time dial failure
peerConfig := DefaultPeerConfig() conf := config.DefaultP2PConfig()
peerConfig.DialFail = true conf.TestDialFail = true
err = sw.addOutboundPeerWithConfig(rp.Addr(), peerConfig, true) err = sw.addOutboundPeerWithConfig(rp.Addr(), conf, true)
require.NotNil(err) require.NotNil(err)
// DialPeerWithAddres - sw.peerConfig resets the dialer // DialPeerWithAddres - sw.peerConfig resets the dialer
@ -348,7 +348,7 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) {
} }
func TestSwitchFullConnectivity(t *testing.T) { func TestSwitchFullConnectivity(t *testing.T) {
switches := MakeConnectedSwitches(config, 3, initSwitchFunc, Connect2Switches) switches := MakeConnectedSwitches(cfg, 3, initSwitchFunc, Connect2Switches)
defer func() { defer func() {
for _, sw := range switches { for _, sw := range switches {
sw.Stop() sw.Stop()

View File

@ -8,7 +8,7 @@ import (
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p/conn" "github.com/tendermint/tendermint/p2p/conn"
) )
@ -56,7 +56,7 @@ const TEST_HOST = "localhost"
// If connect==Connect2Switches, the switches will be fully connected. // If connect==Connect2Switches, the switches will be fully connected.
// initSwitch defines how the i'th switch should be initialized (ie. with what reactors). // initSwitch defines how the i'th switch should be initialized (ie. with what reactors).
// NOTE: panics if any switch fails to start. // NOTE: panics if any switch fails to start.
func MakeConnectedSwitches(cfg *cfg.P2PConfig, n int, initSwitch func(int, *Switch) *Switch, connect func([]*Switch, int, int)) []*Switch { func MakeConnectedSwitches(cfg *config.P2PConfig, n int, initSwitch func(int, *Switch) *Switch, connect func([]*Switch, int, int)) []*Switch {
switches := make([]*Switch, n) switches := make([]*Switch, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
switches[i] = MakeSwitch(cfg, i, TEST_HOST, "123.123.123", initSwitch) switches[i] = MakeSwitch(cfg, i, TEST_HOST, "123.123.123", initSwitch)
@ -104,7 +104,7 @@ func Connect2Switches(switches []*Switch, i, j int) {
} }
func (sw *Switch) addPeerWithConnection(conn net.Conn) error { func (sw *Switch) addPeerWithConnection(conn net.Conn) error {
pc, err := newInboundPeerConn(conn, sw.peerConfig, sw.nodeKey.PrivKey) pc, err := newInboundPeerConn(conn, sw.config, sw.nodeKey.PrivKey)
if err != nil { if err != nil {
if err := conn.Close(); err != nil { if err := conn.Close(); err != nil {
sw.Logger.Error("Error closing connection", "err", err) sw.Logger.Error("Error closing connection", "err", err)
@ -131,7 +131,7 @@ func StartSwitches(switches []*Switch) error {
return nil return nil
} }
func MakeSwitch(cfg *cfg.P2PConfig, i int, network, version string, initSwitch func(int, *Switch) *Switch) *Switch { func MakeSwitch(cfg *config.P2PConfig, i int, network, version string, initSwitch func(int, *Switch) *Switch) *Switch {
// new switch, add reactors // new switch, add reactors
// TODO: let the config be passed in? // TODO: let the config be passed in?
nodeKey := &NodeKey{ nodeKey := &NodeKey{