mirror of
https://github.com/tendermint/tendermint.git
synced 2026-04-29 03:46:57 +00:00
Merge pull request #1030 from tendermint/864-distinguish-between-seeds-and-manual-peers
Distinguish between seeds and manual peers
This commit is contained in:
@@ -26,6 +26,15 @@ 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.0 (TBD)
|
||||
|
||||
BREAKING CHANGES:
|
||||
- [p2p] old `seeds` is now `persistent_peers` (persistent peers to which TM will always connect to)
|
||||
- [p2p] now `seeds` only used for getting addresses (if addrbook is empty; not persistent)
|
||||
|
||||
FEATURES:
|
||||
- [p2p] added new `/dial_persistent_peers` **unsafe** endpoint
|
||||
|
||||
## 0.15.0 (December 29, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
||||
@@ -51,7 +51,7 @@ tendermint node \
|
||||
--proxy_app dummy \
|
||||
--p2p.laddr tcp://127.0.0.1:56666 \
|
||||
--rpc.laddr tcp://127.0.0.1:56667 \
|
||||
--p2p.seeds 127.0.0.1:56656 \
|
||||
--p2p.persistent_peers 127.0.0.1:56656 \
|
||||
--log_level error &
|
||||
|
||||
# wait for node to start up so we only count time where we are actually syncing
|
||||
|
||||
@@ -29,6 +29,7 @@ func AddNodeFlags(cmd *cobra.Command) {
|
||||
// p2p flags
|
||||
cmd.Flags().String("p2p.laddr", config.P2P.ListenAddress, "Node listen address. (0.0.0.0:0 means any interface, any port)")
|
||||
cmd.Flags().String("p2p.seeds", config.P2P.Seeds, "Comma delimited host:port seed nodes")
|
||||
cmd.Flags().String("p2p.persistent_peers", config.P2P.PersistentPeers, "Comma delimited host:port persistent peers")
|
||||
cmd.Flags().Bool("p2p.skip_upnp", config.P2P.SkipUPNP, "Skip UPNP configuration")
|
||||
cmd.Flags().Bool("p2p.pex", config.P2P.PexReactor, "Enable/disable Peer-Exchange")
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ type RPCConfig struct {
|
||||
// NOTE: This server only supports /broadcast_tx_commit
|
||||
GRPCListenAddress string `mapstructure:"grpc_laddr"`
|
||||
|
||||
// Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
|
||||
// Activate unsafe RPC commands like /dial_persistent_peers and /unsafe_flush_mempool
|
||||
Unsafe bool `mapstructure:"unsafe"`
|
||||
}
|
||||
|
||||
@@ -227,8 +227,13 @@ type P2PConfig struct {
|
||||
ListenAddress string `mapstructure:"laddr"`
|
||||
|
||||
// Comma separated list of seed nodes to connect to
|
||||
// We only use these if we can’t connect to peers in the addrbook
|
||||
Seeds string `mapstructure:"seeds"`
|
||||
|
||||
// Comma separated list of persistent peers to connect to
|
||||
// We always connect to these
|
||||
PersistentPeers string `mapstructure:"persistent_peers"`
|
||||
|
||||
// Skip UPNP port forwarding
|
||||
SkipUPNP bool `mapstructure:"skip_upnp"`
|
||||
|
||||
|
||||
@@ -121,6 +121,9 @@ laddr = "{{ .P2P.ListenAddress }}"
|
||||
# Comma separated list of seed nodes to connect to
|
||||
seeds = ""
|
||||
|
||||
# Comma separated list of nodes to keep persistent connections to
|
||||
persistent_peers = ""
|
||||
|
||||
# Path to address book
|
||||
addr_book_file = "{{ .P2P.AddrBook }}"
|
||||
|
||||
|
||||
@@ -24,13 +24,13 @@ Here are the steps to setting up a testnet manually:
|
||||
``tendermint gen_validator``
|
||||
4) Compile a list of public keys for each validator into a
|
||||
``genesis.json`` file.
|
||||
5) Run ``tendermint node --p2p.seeds=< seed addresses >`` on each node,
|
||||
where ``< seed addresses >`` is a comma separated list of the IP:PORT
|
||||
5) Run ``tendermint node --p2p.persistent_peers=< peer addresses >`` on each node,
|
||||
where ``< peer addresses >`` is a comma separated list of the IP:PORT
|
||||
combination for each node. The default port for Tendermint is
|
||||
``46656``. Thus, if the IP addresses of your nodes were
|
||||
``192.168.0.1, 192.168.0.2, 192.168.0.3, 192.168.0.4``, the command
|
||||
would look like:
|
||||
``tendermint node --p2p.seeds=192.168.0.1:46656,192.168.0.2:46656,192.168.0.3:46656,192.168.0.4:46656``.
|
||||
``tendermint node --p2p.persistent_peers=192.168.0.1:46656,192.168.0.2:46656,192.168.0.3:46656,192.168.0.4:46656``.
|
||||
|
||||
After a few seconds, all the nodes should connect to eachother and start
|
||||
making blocks! For more information, see the Tendermint Networks section
|
||||
|
||||
@@ -88,6 +88,9 @@ like the file below, however, double check by inspecting the
|
||||
# Comma separated list of seed nodes to connect to
|
||||
seeds = ""
|
||||
|
||||
# Comma separated list of nodes to keep persistent connections to
|
||||
persistent_peers = ""
|
||||
|
||||
# Path to address book
|
||||
addr_book_file = "addrbook.json"
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ An HTTP Get request to the root RPC endpoint (e.g.
|
||||
http://localhost:46657/broadcast_tx_sync?tx=_
|
||||
http://localhost:46657/commit?height=_
|
||||
http://localhost:46657/dial_seeds?seeds=_
|
||||
http://localhost:46657/dial_peers?peers=_&persistent=_
|
||||
http://localhost:46657/subscribe?event=_
|
||||
http://localhost:46657/tx?hash=_&prove=_
|
||||
http://localhost:46657/unsafe_start_cpu_profiler?filename=_
|
||||
|
||||
@@ -272,7 +272,9 @@ Peers
|
||||
~~~~~
|
||||
|
||||
To connect to peers on start-up, specify them in the ``$TMHOME/config/config.toml`` or
|
||||
on the command line.
|
||||
on the command line. Use `seeds` to specify seed nodes from which you can get many other
|
||||
peer addresses, and ``persistent_peers`` to specify peers that your node will maintain
|
||||
persistent connections with.
|
||||
|
||||
For instance,
|
||||
|
||||
@@ -281,26 +283,35 @@ For instance,
|
||||
tendermint node --p2p.seeds "1.2.3.4:46656,5.6.7.8:46656"
|
||||
|
||||
Alternatively, you can use the ``/dial_seeds`` endpoint of the RPC to
|
||||
specify peers for a running node to connect to:
|
||||
specify seeds for a running node to connect to:
|
||||
|
||||
::
|
||||
|
||||
curl --data-urlencode "seeds=[\"1.2.3.4:46656\",\"5.6.7.8:46656\"]" localhost:46657/dial_seeds
|
||||
curl 'localhost:46657/dial_seeds?seeds=\["1.2.3.4:46656","5.6.7.8:46656"\]'
|
||||
|
||||
Additionally, the peer-exchange protocol can be enabled using the
|
||||
``--pex`` flag, though this feature is `still under
|
||||
development <https://github.com/tendermint/tendermint/issues/598>`__. If
|
||||
``--pex`` is enabled, peers will gossip about known peers and form a
|
||||
more resilient network.
|
||||
Note, if the peer-exchange protocol (PEX) is enabled (default), you should not
|
||||
normally need seeds after the first start. Peers will be gossipping about known
|
||||
peers and forming a network, storing peer addresses in the addrbook.
|
||||
|
||||
If you want Tendermint to connect to specific set of addresses and maintain a
|
||||
persistent connection with each, you can use the ``--p2p.persistent_peers``
|
||||
flag or the corresponding setting in the ``config.toml`` or the
|
||||
``/dial_peers`` RPC endpoint to do it without stopping Tendermint
|
||||
core instance.
|
||||
|
||||
::
|
||||
|
||||
tendermint node --p2p.persistent_peers "10.11.12.13:46656,10.11.12.14:46656"
|
||||
curl 'localhost:46657/dial_peers?persistent=true&peers=\["1.2.3.4:46656","5.6.7.8:46656"\]'
|
||||
|
||||
Adding a Non-Validator
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Adding a non-validator is simple. Just copy the original
|
||||
``genesis.json`` to ``~/.tendermint/config`` on the new machine and start the
|
||||
node, specifying seeds as necessary. If no seeds are specified, the node
|
||||
won't make any blocks, because it's not a validator, and it won't hear
|
||||
about any blocks, because it's not connected to the other peer.
|
||||
node, specifying seeds or persistent peers as necessary. If no seeds or persistent
|
||||
peers are specified, the node won't make any blocks, because it's not a validator,
|
||||
and it won't hear about any blocks, because it's not connected to the other peer.
|
||||
|
||||
Adding a Validator
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
@@ -371,7 +382,7 @@ and the new ``priv_validator.json`` to the ``~/.tendermint/config`` on a new
|
||||
machine.
|
||||
|
||||
Now run ``tendermint node`` on both machines, and use either
|
||||
``--p2p.seeds`` or the ``/dial_seeds`` to get them to peer up. They
|
||||
``--p2p.persistent_peers`` or the ``/dial_peers`` to get them to peer up. They
|
||||
should start making blocks, and will only continue to do so as long as
|
||||
both of them are online.
|
||||
|
||||
|
||||
17
node/node.go
17
node/node.go
@@ -255,7 +255,8 @@ func NewNode(config *cfg.Config,
|
||||
trustMetricStore = trust.NewTrustMetricStore(trustHistoryDB, trust.DefaultConfig())
|
||||
trustMetricStore.SetLogger(p2pLogger)
|
||||
|
||||
pexReactor := p2p.NewPEXReactor(addrBook)
|
||||
pexReactor := p2p.NewPEXReactor(addrBook,
|
||||
&p2p.PEXReactorConfig{Seeds: strings.Split(config.P2P.Seeds, ",")})
|
||||
pexReactor.SetLogger(p2pLogger)
|
||||
sw.AddReactor("PEX", pexReactor)
|
||||
}
|
||||
@@ -379,11 +380,10 @@ func (n *Node) OnStart() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// If seeds exist, add them to the address book and dial out
|
||||
if n.config.P2P.Seeds != "" {
|
||||
// dial out
|
||||
seeds := strings.Split(n.config.P2P.Seeds, ",")
|
||||
if err := n.DialSeeds(seeds); err != nil {
|
||||
// Always connect to persistent peers
|
||||
if n.config.P2P.PersistentPeers != "" {
|
||||
err = n.sw.DialPeersAsync(n.addrBook, strings.Split(n.config.P2P.PersistentPeers, ","), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -575,11 +575,6 @@ func (n *Node) NodeInfo() *p2p.NodeInfo {
|
||||
return n.sw.NodeInfo()
|
||||
}
|
||||
|
||||
// DialSeeds dials the given seeds on the Switch.
|
||||
func (n *Node) DialSeeds(seeds []string) error {
|
||||
return n.sw.DialSeeds(n.addrBook, seeds)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var (
|
||||
|
||||
@@ -45,6 +45,7 @@ type PEXReactor struct {
|
||||
BaseReactor
|
||||
|
||||
book *AddrBook
|
||||
config *PEXReactorConfig
|
||||
ensurePeersPeriod time.Duration
|
||||
|
||||
// tracks message count by peer, so we can prevent abuse
|
||||
@@ -52,10 +53,18 @@ type PEXReactor struct {
|
||||
maxMsgCountByPeer uint16
|
||||
}
|
||||
|
||||
// PEXReactorConfig holds reactor specific configuration data.
|
||||
type PEXReactorConfig struct {
|
||||
// Seeds is a list of addresses reactor may use if it can't connect to peers
|
||||
// in the addrbook.
|
||||
Seeds []string
|
||||
}
|
||||
|
||||
// NewPEXReactor creates new PEX reactor.
|
||||
func NewPEXReactor(b *AddrBook) *PEXReactor {
|
||||
func NewPEXReactor(b *AddrBook, config *PEXReactorConfig) *PEXReactor {
|
||||
r := &PEXReactor{
|
||||
book: b,
|
||||
config: config,
|
||||
ensurePeersPeriod: defaultEnsurePeersPeriod,
|
||||
msgCountByPeer: cmn.NewCMap(),
|
||||
maxMsgCountByPeer: defaultMaxMsgCountByPeer,
|
||||
@@ -100,7 +109,7 @@ func (r *PEXReactor) GetChannels() []*ChannelDescriptor {
|
||||
func (r *PEXReactor) AddPeer(p Peer) {
|
||||
if p.IsOutbound() {
|
||||
// For outbound peers, the address is already in the books.
|
||||
// Either it was added in DialSeeds or when we
|
||||
// Either it was added in DialPersistentPeers or when we
|
||||
// received the peer's address in r.Receive
|
||||
if r.book.NeedMoreAddrs() {
|
||||
r.RequestPEX(p)
|
||||
@@ -238,7 +247,7 @@ func (r *PEXReactor) ensurePeersRoutine() {
|
||||
// placeholder. It should not be the case that an address becomes old/vetted
|
||||
// upon a single successful connection.
|
||||
func (r *PEXReactor) ensurePeers() {
|
||||
numOutPeers, _, numDialing := r.Switch.NumPeers()
|
||||
numOutPeers, numInPeers, numDialing := r.Switch.NumPeers()
|
||||
numToDial := minNumOutboundPeers - (numOutPeers + numDialing)
|
||||
r.Logger.Info("Ensure peers", "numOutPeers", numOutPeers, "numDialing", numDialing, "numToDial", numToDial)
|
||||
if numToDial <= 0 {
|
||||
@@ -284,13 +293,20 @@ func (r *PEXReactor) ensurePeers() {
|
||||
|
||||
// If we need more addresses, pick a random peer and ask for more.
|
||||
if r.book.NeedMoreAddrs() {
|
||||
if peers := r.Switch.Peers().List(); len(peers) > 0 {
|
||||
i := rand.Int() % len(peers) // nolint: gas
|
||||
peer := peers[i]
|
||||
r.Logger.Info("No addresses to dial. Sending pexRequest to random peer", "peer", peer)
|
||||
peers := r.Switch.Peers().List()
|
||||
peersCount := len(peers)
|
||||
if peersCount > 0 {
|
||||
peer := peers[rand.Int()%peersCount] // nolint: gas
|
||||
r.Logger.Info("We need more addresses. Sending pexRequest to random peer", "peer", peer)
|
||||
r.RequestPEX(peer)
|
||||
}
|
||||
}
|
||||
|
||||
// If we are not connected to nor dialing anybody, fallback to dialing seeds.
|
||||
if numOutPeers+numInPeers+numDialing+len(toDial) == 0 {
|
||||
r.Logger.Info("No addresses to dial nor connected peers. Will dial seeds", "seeds", r.config.Seeds)
|
||||
r.Switch.DialPeersAsync(r.book, r.config.Seeds, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *PEXReactor) flushMsgCountByPeer() {
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestPEXReactorBasic(t *testing.T) {
|
||||
book := NewAddrBook(dir+"addrbook.json", true)
|
||||
book.SetLogger(log.TestingLogger())
|
||||
|
||||
r := NewPEXReactor(book)
|
||||
r := NewPEXReactor(book, &PEXReactorConfig{})
|
||||
r.SetLogger(log.TestingLogger())
|
||||
|
||||
assert.NotNil(r)
|
||||
@@ -40,7 +40,7 @@ func TestPEXReactorAddRemovePeer(t *testing.T) {
|
||||
book := NewAddrBook(dir+"addrbook.json", true)
|
||||
book.SetLogger(log.TestingLogger())
|
||||
|
||||
r := NewPEXReactor(book)
|
||||
r := NewPEXReactor(book, &PEXReactorConfig{})
|
||||
r.SetLogger(log.TestingLogger())
|
||||
|
||||
size := book.Size()
|
||||
@@ -76,7 +76,7 @@ func TestPEXReactorRunning(t *testing.T) {
|
||||
switches[i] = makeSwitch(config, i, "127.0.0.1", "123.123.123", func(i int, sw *Switch) *Switch {
|
||||
sw.SetLogger(log.TestingLogger().With("switch", i))
|
||||
|
||||
r := NewPEXReactor(book)
|
||||
r := NewPEXReactor(book, &PEXReactorConfig{})
|
||||
r.SetLogger(log.TestingLogger())
|
||||
r.SetEnsurePeersPeriod(250 * time.Millisecond)
|
||||
sw.AddReactor("pex", r)
|
||||
@@ -107,6 +107,7 @@ func TestPEXReactorRunning(t *testing.T) {
|
||||
|
||||
func assertSomePeersWithTimeout(t *testing.T, switches []*Switch, checkPeriod, timeout time.Duration) {
|
||||
ticker := time.NewTicker(checkPeriod)
|
||||
remaining := timeout
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
@@ -118,16 +119,21 @@ func assertSomePeersWithTimeout(t *testing.T, switches []*Switch, checkPeriod, t
|
||||
allGood = false
|
||||
}
|
||||
}
|
||||
remaining -= checkPeriod
|
||||
if remaining < 0 {
|
||||
remaining = 0
|
||||
}
|
||||
if allGood {
|
||||
return
|
||||
}
|
||||
case <-time.After(timeout):
|
||||
case <-time.After(remaining):
|
||||
numPeersStr := ""
|
||||
for i, s := range switches {
|
||||
outbound, inbound, _ := s.NumPeers()
|
||||
numPeersStr += fmt.Sprintf("%d => {outbound: %d, inbound: %d}, ", i, outbound, inbound)
|
||||
}
|
||||
t.Errorf("expected all switches to be connected to at least one peer (switches: %s)", numPeersStr)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +147,7 @@ func TestPEXReactorReceive(t *testing.T) {
|
||||
book := NewAddrBook(dir+"addrbook.json", false)
|
||||
book.SetLogger(log.TestingLogger())
|
||||
|
||||
r := NewPEXReactor(book)
|
||||
r := NewPEXReactor(book, &PEXReactorConfig{})
|
||||
r.SetLogger(log.TestingLogger())
|
||||
|
||||
peer := createRandomPeer(false)
|
||||
@@ -166,7 +172,7 @@ func TestPEXReactorAbuseFromPeer(t *testing.T) {
|
||||
book := NewAddrBook(dir+"addrbook.json", true)
|
||||
book.SetLogger(log.TestingLogger())
|
||||
|
||||
r := NewPEXReactor(book)
|
||||
r := NewPEXReactor(book, &PEXReactorConfig{})
|
||||
r.SetLogger(log.TestingLogger())
|
||||
r.SetMaxMsgCountByPeer(5)
|
||||
|
||||
@@ -180,6 +186,47 @@ func TestPEXReactorAbuseFromPeer(t *testing.T) {
|
||||
assert.True(r.ReachedMaxMsgCountForPeer(peer.NodeInfo().ListenAddr))
|
||||
}
|
||||
|
||||
func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "pex_reactor")
|
||||
require.Nil(t, err)
|
||||
defer os.RemoveAll(dir) // nolint: errcheck
|
||||
|
||||
book := NewAddrBook(dir+"addrbook.json", false)
|
||||
book.SetLogger(log.TestingLogger())
|
||||
|
||||
// 1. create seed
|
||||
seed := makeSwitch(config, 0, "127.0.0.1", "123.123.123", func(i int, sw *Switch) *Switch {
|
||||
sw.SetLogger(log.TestingLogger())
|
||||
|
||||
r := NewPEXReactor(book, &PEXReactorConfig{})
|
||||
r.SetLogger(log.TestingLogger())
|
||||
r.SetEnsurePeersPeriod(250 * time.Millisecond)
|
||||
sw.AddReactor("pex", r)
|
||||
return sw
|
||||
})
|
||||
seed.AddListener(NewDefaultListener("tcp", seed.NodeInfo().ListenAddr, true, log.TestingLogger()))
|
||||
err = seed.Start()
|
||||
require.Nil(t, err)
|
||||
defer seed.Stop()
|
||||
|
||||
// 2. create usual peer
|
||||
sw := makeSwitch(config, 1, "127.0.0.1", "123.123.123", func(i int, sw *Switch) *Switch {
|
||||
sw.SetLogger(log.TestingLogger())
|
||||
|
||||
r := NewPEXReactor(book, &PEXReactorConfig{Seeds: []string{seed.NodeInfo().ListenAddr}})
|
||||
r.SetLogger(log.TestingLogger())
|
||||
r.SetEnsurePeersPeriod(250 * time.Millisecond)
|
||||
sw.AddReactor("pex", r)
|
||||
return sw
|
||||
})
|
||||
err = sw.Start()
|
||||
require.Nil(t, err)
|
||||
defer sw.Stop()
|
||||
|
||||
// 3. check that peer at least connects to seed
|
||||
assertSomePeersWithTimeout(t, []*Switch{sw}, 10*time.Millisecond, 10*time.Second)
|
||||
}
|
||||
|
||||
func createRoutableAddr() (addr string, netAddr *NetAddress) {
|
||||
for {
|
||||
addr = cmn.Fmt("%v.%v.%v.%v:46656", rand.Int()%256, rand.Int()%256, rand.Int()%256, rand.Int()%256)
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
|
||||
const (
|
||||
// wait a random amount of time from this interval
|
||||
// before dialing seeds or reconnecting to help prevent DoS
|
||||
// before dialing peers or reconnecting to help prevent DoS
|
||||
dialRandomizerIntervalMilliseconds = 3000
|
||||
|
||||
// repeatedly try to reconnect for a few minutes
|
||||
@@ -315,15 +315,15 @@ func (sw *Switch) startInitPeer(peer *peer) {
|
||||
}
|
||||
}
|
||||
|
||||
// DialSeeds dials a list of seeds asynchronously in random order.
|
||||
func (sw *Switch) DialSeeds(addrBook *AddrBook, seeds []string) error {
|
||||
netAddrs, errs := NewNetAddressStrings(seeds)
|
||||
// DialPeersAsync dials a list of peers asynchronously in random order (optionally, making them persistent).
|
||||
func (sw *Switch) DialPeersAsync(addrBook *AddrBook, peers []string, persistent bool) error {
|
||||
netAddrs, errs := NewNetAddressStrings(peers)
|
||||
for _, err := range errs {
|
||||
sw.Logger.Error("Error in seed's address", "err", err)
|
||||
sw.Logger.Error("Error in peer's address", "err", err)
|
||||
}
|
||||
|
||||
if addrBook != nil {
|
||||
// add seeds to `addrBook`
|
||||
// add peers to `addrBook`
|
||||
ourAddrS := sw.nodeInfo.ListenAddr
|
||||
ourAddr, _ := NewNetAddressString(ourAddrS)
|
||||
for _, netAddr := range netAddrs {
|
||||
@@ -342,7 +342,12 @@ func (sw *Switch) DialSeeds(addrBook *AddrBook, seeds []string) error {
|
||||
go func(i int) {
|
||||
sw.randomSleep(0)
|
||||
j := perm[i]
|
||||
sw.dialSeed(netAddrs[j])
|
||||
peer, 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)
|
||||
}
|
||||
return nil
|
||||
@@ -354,15 +359,6 @@ func (sw *Switch) randomSleep(interval time.Duration) {
|
||||
time.Sleep(r + interval)
|
||||
}
|
||||
|
||||
func (sw *Switch) dialSeed(addr *NetAddress) {
|
||||
peer, err := sw.DialPeerWithAddress(addr, true)
|
||||
if err != nil {
|
||||
sw.Logger.Error("Error dialing seed", "err", err)
|
||||
} else {
|
||||
sw.Logger.Info("Connected to seed", "peer", peer)
|
||||
}
|
||||
}
|
||||
|
||||
// DialPeerWithAddress dials the given peer and runs sw.addPeer if it connects 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) {
|
||||
|
||||
@@ -68,7 +68,9 @@ func TestTrustMetricStopPause(t *testing.T) {
|
||||
tt.NextTick()
|
||||
tm.Pause()
|
||||
|
||||
// could be 1 or 2 because Pause and NextTick race
|
||||
first := tm.Copy().numIntervals
|
||||
|
||||
// Allow more time to pass and check the intervals are unchanged
|
||||
tt.NextTick()
|
||||
tt.NextTick()
|
||||
|
||||
@@ -24,7 +24,7 @@ type TestTicker struct {
|
||||
|
||||
// NewTestTicker returns our ticker used within test routines
|
||||
func NewTestTicker() *TestTicker {
|
||||
c := make(chan time.Time, 1)
|
||||
c := make(chan time.Time)
|
||||
return &TestTicker{
|
||||
C: c,
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@ func (Local) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
|
||||
return core.UnsafeDialSeeds(seeds)
|
||||
}
|
||||
|
||||
func (Local) DialPeers(peers []string, persistent bool) (*ctypes.ResultDialPeers, error) {
|
||||
return core.UnsafeDialPeers(peers, persistent)
|
||||
}
|
||||
|
||||
func (Local) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
|
||||
return core.BlockchainInfo(minHeight, maxHeight)
|
||||
}
|
||||
|
||||
@@ -111,6 +111,10 @@ func (c Client) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
|
||||
return core.UnsafeDialSeeds(seeds)
|
||||
}
|
||||
|
||||
func (c Client) DialPeers(peers []string, persistent bool) (*ctypes.ResultDialPeers, error) {
|
||||
return core.UnsafeDialPeers(peers, persistent)
|
||||
}
|
||||
|
||||
func (c Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
|
||||
return core.BlockchainInfo(minHeight, maxHeight)
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ Endpoints that require arguments:
|
||||
/broadcast_tx_sync?tx=_
|
||||
/commit?height=_
|
||||
/dial_seeds?seeds=_
|
||||
/dial_persistent_peers?persistent_peers=_
|
||||
/subscribe?event=_
|
||||
/tx?hash=_&prove=_
|
||||
/unsafe_start_cpu_profiler?filename=_
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
)
|
||||
|
||||
@@ -55,19 +54,31 @@ func NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
}
|
||||
|
||||
func UnsafeDialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
|
||||
|
||||
if len(seeds) == 0 {
|
||||
return &ctypes.ResultDialSeeds{}, fmt.Errorf("No seeds provided")
|
||||
return &ctypes.ResultDialSeeds{}, errors.New("No seeds provided")
|
||||
}
|
||||
// starts go routines to dial each seed after random delays
|
||||
// starts go routines to dial each peer after random delays
|
||||
logger.Info("DialSeeds", "addrBook", addrBook, "seeds", seeds)
|
||||
err := p2pSwitch.DialSeeds(addrBook, seeds)
|
||||
err := p2pSwitch.DialPeersAsync(addrBook, seeds, false)
|
||||
if err != nil {
|
||||
return &ctypes.ResultDialSeeds{}, err
|
||||
}
|
||||
return &ctypes.ResultDialSeeds{"Dialing seeds in progress. See /net_info for details"}, nil
|
||||
}
|
||||
|
||||
func UnsafeDialPeers(peers []string, persistent bool) (*ctypes.ResultDialPeers, error) {
|
||||
if len(peers) == 0 {
|
||||
return &ctypes.ResultDialPeers{}, errors.New("No peers provided")
|
||||
}
|
||||
// starts go routines to dial each peer after random delays
|
||||
logger.Info("DialPeers", "addrBook", addrBook, "peers", peers, "persistent", persistent)
|
||||
err := p2pSwitch.DialPeersAsync(addrBook, peers, persistent)
|
||||
if err != nil {
|
||||
return &ctypes.ResultDialPeers{}, err
|
||||
}
|
||||
return &ctypes.ResultDialPeers{"Dialing peers in progress. See /net_info for details"}, nil
|
||||
}
|
||||
|
||||
// Get genesis file.
|
||||
//
|
||||
// ```shell
|
||||
|
||||
@@ -32,7 +32,7 @@ type P2P interface {
|
||||
NumPeers() (outbound, inbound, dialig int)
|
||||
NodeInfo() *p2p.NodeInfo
|
||||
IsListening() bool
|
||||
DialSeeds(*p2p.AddrBook, []string) error
|
||||
DialPeersAsync(*p2p.AddrBook, []string, bool) error
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
|
||||
@@ -39,6 +39,7 @@ var Routes = map[string]*rpc.RPCFunc{
|
||||
func AddUnsafeRoutes() {
|
||||
// control API
|
||||
Routes["dial_seeds"] = rpc.NewRPCFunc(UnsafeDialSeeds, "seeds")
|
||||
Routes["dial_peers"] = rpc.NewRPCFunc(UnsafeDialPeers, "peers,persistent")
|
||||
Routes["unsafe_flush_mempool"] = rpc.NewRPCFunc(UnsafeFlushMempool, "")
|
||||
|
||||
// profiler API
|
||||
|
||||
@@ -86,6 +86,10 @@ type ResultDialSeeds struct {
|
||||
Log string `json:"log"`
|
||||
}
|
||||
|
||||
type ResultDialPeers struct {
|
||||
Log string `json:"log"`
|
||||
}
|
||||
|
||||
type Peer struct {
|
||||
p2p.NodeInfo `json:"node_info"`
|
||||
IsOutbound bool `json:"is_outbound"`
|
||||
|
||||
@@ -38,7 +38,7 @@ for i in $(seq 1 4); do
|
||||
--name local_testnet_$i \
|
||||
--entrypoint tendermint \
|
||||
-e TMHOME=/go/src/github.com/tendermint/tendermint/test/p2p/data/mach$i/core \
|
||||
tendermint_tester node --p2p.seeds 172.57.0.101:46656,172.57.0.102:46656,172.57.0.103:46656,172.57.0.104:46656 --proxy_app=dummy
|
||||
tendermint_tester node --p2p.persistent_peers 172.57.0.101:46656,172.57.0.102:46656,172.57.0.103:46656,172.57.0.104:46656 --proxy_app=dummy
|
||||
done
|
||||
```
|
||||
|
||||
|
||||
@@ -23,11 +23,11 @@ docker rm -vf local_testnet_$ID
|
||||
set -e
|
||||
|
||||
# restart peer - should have an empty blockchain
|
||||
SEEDS="$(test/p2p/ip.sh 1):46656"
|
||||
PERSISTENT_PEERS="$(test/p2p/ip.sh 1):46656"
|
||||
for j in `seq 2 $N`; do
|
||||
SEEDS="$SEEDS,$(test/p2p/ip.sh $j):46656"
|
||||
PERSISTENT_PEERS="$PERSISTENT_PEERS,$(test/p2p/ip.sh $j):46656"
|
||||
done
|
||||
bash test/p2p/peer.sh $DOCKER_IMAGE $NETWORK_NAME $ID $PROXY_APP "--p2p.seeds $SEEDS --p2p.pex --rpc.unsafe"
|
||||
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"
|
||||
|
||||
@@ -7,10 +7,10 @@ N=$3
|
||||
APP_PROXY=$4
|
||||
|
||||
set +u
|
||||
SEEDS=$5
|
||||
if [[ "$SEEDS" != "" ]]; then
|
||||
echo "Seeds: $SEEDS"
|
||||
SEEDS="--p2p.seeds $SEEDS"
|
||||
PERSISTENT_PEERS=$5
|
||||
if [[ "$PERSISTENT_PEERS" != "" ]]; then
|
||||
echo "PersistentPeers: $PERSISTENT_PEERS"
|
||||
PERSISTENT_PEERS="--p2p.persistent_peers $PERSISTENT_PEERS"
|
||||
fi
|
||||
set -u
|
||||
|
||||
@@ -20,5 +20,5 @@ cd "$GOPATH/src/github.com/tendermint/tendermint"
|
||||
docker network create --driver bridge --subnet 172.57.0.0/16 "$NETWORK_NAME"
|
||||
|
||||
for i in $(seq 1 "$N"); do
|
||||
bash test/p2p/peer.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$i" "$APP_PROXY" "$SEEDS --p2p.pex --rpc.unsafe"
|
||||
bash test/p2p/peer.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$i" "$APP_PROXY" "$PERSISTENT_PEERS --p2p.pex --rpc.unsafe"
|
||||
done
|
||||
|
||||
12
test/p2p/persistent_peers.sh
Normal file
12
test/p2p/persistent_peers.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#! /bin/bash
|
||||
set -eu
|
||||
|
||||
N=$1
|
||||
|
||||
cd "$GOPATH/src/github.com/tendermint/tendermint"
|
||||
|
||||
persistent_peers="$(test/p2p/ip.sh 1):46656"
|
||||
for i in $(seq 2 $N); do
|
||||
persistent_peers="$persistent_peers,$(test/p2p/ip.sh $i):46656"
|
||||
done
|
||||
echo "$persistent_peers"
|
||||
@@ -1,4 +1,4 @@
|
||||
#! /bin/bash
|
||||
#! /bin/bash
|
||||
set -u
|
||||
|
||||
N=$1
|
||||
@@ -11,7 +11,7 @@ for i in `seq 1 $N`; do
|
||||
curl -s $addr/status > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 1
|
||||
sleep 1
|
||||
curl -s $addr/status > /dev/null
|
||||
ERR=$?
|
||||
done
|
||||
@@ -19,13 +19,13 @@ for i in `seq 1 $N`; do
|
||||
done
|
||||
|
||||
set -e
|
||||
# seeds need quotes
|
||||
seeds="\"$(test/p2p/ip.sh 1):46656\""
|
||||
# persistent_peers need quotes
|
||||
persistent_peers="\"$(test/p2p/ip.sh 1):46656\""
|
||||
for i in `seq 2 $N`; do
|
||||
seeds="$seeds,\"$(test/p2p/ip.sh $i):46656\""
|
||||
persistent_peers="$persistent_peers,\"$(test/p2p/ip.sh $i):46656\""
|
||||
done
|
||||
echo $seeds
|
||||
echo $persistent_peers
|
||||
|
||||
echo $seeds
|
||||
echo $persistent_peers
|
||||
IP=$(test/p2p/ip.sh 1)
|
||||
curl --data-urlencode "seeds=[$seeds]" "$IP:46657/dial_seeds"
|
||||
curl --data-urlencode "persistent_peers=[$persistent_peers]" "$IP:46657/dial_persistent_peers"
|
||||
@@ -6,10 +6,10 @@ NETWORK_NAME=$2
|
||||
N=$3
|
||||
PROXY_APP=$4
|
||||
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
cd "$GOPATH/src/github.com/tendermint/tendermint"
|
||||
|
||||
echo "Test reconnecting from the address book"
|
||||
bash test/p2p/pex/test_addrbook.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP
|
||||
bash test/p2p/pex/test_addrbook.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$N" "$PROXY_APP"
|
||||
|
||||
echo "Test connecting via /dial_seeds"
|
||||
bash test/p2p/pex/test_dial_seeds.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP
|
||||
echo "Test connecting via /dial_persistent_peers"
|
||||
bash test/p2p/pex/test_dial_persistent_peers.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$N" "$PROXY_APP"
|
||||
|
||||
@@ -9,7 +9,7 @@ PROXY_APP=$4
|
||||
ID=1
|
||||
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Testing pex creates the addrbook and uses it if seeds are not provided"
|
||||
echo "Testing pex creates the addrbook and uses it if persistent_peers are not provided"
|
||||
echo "(assuming peers are started with pex enabled)"
|
||||
|
||||
CLIENT_NAME="pex_addrbook_$ID"
|
||||
@@ -22,7 +22,7 @@ set +e #CIRCLE
|
||||
docker rm -vf "local_testnet_$ID"
|
||||
set -e
|
||||
|
||||
# NOTE that we do not provide seeds
|
||||
# NOTE that we do not provide persistent_peers
|
||||
bash test/p2p/peer.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$ID" "$PROXY_APP" "--p2p.pex --rpc.unsafe"
|
||||
docker cp "/tmp/addrbook.json" "local_testnet_$ID:/go/src/github.com/tendermint/tendermint/test/p2p/data/mach1/core/addrbook.json"
|
||||
echo "with the following addrbook:"
|
||||
@@ -35,7 +35,7 @@ echo ""
|
||||
bash test/p2p/client.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$CLIENT_NAME" "test/p2p/pex/check_peer.sh $ID $N"
|
||||
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Testing other peers connect to us if we have neither seeds nor the addrbook"
|
||||
echo "Testing other peers connect to us if we have neither persistent_peers nor the addrbook"
|
||||
echo "(assuming peers are started with pex enabled)"
|
||||
|
||||
CLIENT_NAME="pex_no_addrbook_$ID"
|
||||
@@ -46,7 +46,7 @@ set +e #CIRCLE
|
||||
docker rm -vf "local_testnet_$ID"
|
||||
set -e
|
||||
|
||||
# NOTE that we do not provide seeds
|
||||
# NOTE that we do not provide persistent_peers
|
||||
bash test/p2p/peer.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$ID" "$PROXY_APP" "--p2p.pex --rpc.unsafe"
|
||||
|
||||
# if the client runs forever, it means other peers have removed us from their books (which should not happen)
|
||||
|
||||
@@ -11,7 +11,7 @@ ID=1
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Testing full network connection using one /dial_seeds call"
|
||||
echo "Testing full network connection using one /dial_persistent_peers call"
|
||||
echo "(assuming peers are started with pex enabled)"
|
||||
|
||||
# stop the existing testnet and remove local network
|
||||
@@ -21,16 +21,16 @@ set -e
|
||||
|
||||
# start the testnet on a local network
|
||||
# NOTE we re-use the same network for all tests
|
||||
SEEDS=""
|
||||
bash test/p2p/local_testnet_start.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP $SEEDS
|
||||
PERSISTENT_PEERS=""
|
||||
bash test/p2p/local_testnet_start.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP $PERSISTENT_PEERS
|
||||
|
||||
|
||||
|
||||
# dial seeds from one node
|
||||
CLIENT_NAME="dial_seeds"
|
||||
bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME $CLIENT_NAME "test/p2p/pex/dial_seeds.sh $N"
|
||||
# dial persistent_peers from one node
|
||||
CLIENT_NAME="dial_persistent_peers"
|
||||
bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME $CLIENT_NAME "test/p2p/pex/dial_persistent_peers.sh $N"
|
||||
|
||||
# test basic connectivity and consensus
|
||||
# start client container and check the num peers and height for all nodes
|
||||
CLIENT_NAME="dial_seeds_basic"
|
||||
CLIENT_NAME="dial_persistent_peers_basic"
|
||||
bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME $CLIENT_NAME "test/p2p/basic/test.sh $N"
|
||||
@@ -1,12 +0,0 @@
|
||||
#! /bin/bash
|
||||
set -eu
|
||||
|
||||
N=$1
|
||||
|
||||
cd "$GOPATH/src/github.com/tendermint/tendermint"
|
||||
|
||||
seeds="$(test/p2p/ip.sh 1):46656"
|
||||
for i in $(seq 2 $N); do
|
||||
seeds="$seeds,$(test/p2p/ip.sh $i):46656"
|
||||
done
|
||||
echo "$seeds"
|
||||
@@ -13,11 +13,11 @@ set +e
|
||||
bash test/p2p/local_testnet_stop.sh "$NETWORK_NAME" "$N"
|
||||
set -e
|
||||
|
||||
SEEDS=$(bash test/p2p/seeds.sh $N)
|
||||
PERSISTENT_PEERS=$(bash test/p2p/persistent_peers.sh $N)
|
||||
|
||||
# start the testnet on a local network
|
||||
# NOTE we re-use the same network for all tests
|
||||
bash test/p2p/local_testnet_start.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$N" "$PROXY_APP" "$SEEDS"
|
||||
bash test/p2p/local_testnet_start.sh "$DOCKER_IMAGE" "$NETWORK_NAME" "$N" "$PROXY_APP" "$PERSISTENT_PEERS"
|
||||
|
||||
# test basic connectivity and consensus
|
||||
# start client container and check the num peers and height for all nodes
|
||||
|
||||
Reference in New Issue
Block a user