distinguish between seeds and manual peers in the config/flags

- we only use seeds if we can’t connect to peers in the addrbook.
- we always connect to nodes given in config/flags

Refs #864
This commit is contained in:
Anton Kaliaev 2017-12-28 12:54:39 -06:00
parent 179d6062e4
commit 28fc15028a
No known key found for this signature in database
GPG Key ID: 7B6881D965918214
28 changed files with 112 additions and 107 deletions

View File

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

View File

@ -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.manual_peers", config.P2P.ManualPeers, "Comma delimited host:port manual 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")

View File

@ -170,7 +170,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_manual_peers and /unsafe_flush_mempool
Unsafe bool `mapstructure:"unsafe"`
}
@ -203,8 +203,13 @@ type P2PConfig struct {
ListenAddress string `mapstructure:"laddr"`
// Comma separated list of seed nodes to connect to
// We only use these if we cant connect to peers in the addrbook
Seeds string `mapstructure:"seeds"`
// Comma separated list of manual peers to connect to
// We always connect to these
ManualPeers string `mapstructure:"manual_peers"`
// Skip UPNP port forwarding
SkipUPNP bool `mapstructure:"skip_upnp"`

View File

@ -42,6 +42,7 @@ laddr = "tcp://0.0.0.0:46657"
[p2p]
laddr = "tcp://0.0.0.0:46656"
seeds = ""
manual_peers = ""
`
func defaultConfig(moniker string) string {
@ -106,6 +107,7 @@ laddr = "tcp://0.0.0.0:36657"
[p2p]
laddr = "tcp://0.0.0.0:36656"
seeds = ""
manual_peers = ""
`
func testConfig(moniker string) (testConfig string) {

View File

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

View File

@ -49,6 +49,8 @@ The main config parameters are defined
- ``p2p.pex``: Enable Peer-Exchange (dev feature). *Default*: ``false``
- ``p2p.seeds``: Comma delimited host:port seed nodes. *Default*:
``""``
- ``p2p.manual_peers``: Comma delimited host:port manual peers. *Default*:
``""``
- ``p2p.skip_upnp``: Skip UPNP detection. *Default*: ``false``
- ``rpc.grpc_laddr``: GRPC listen address (BroadcastTx only). Port

View File

@ -111,7 +111,7 @@ An HTTP Get request to the root RPC endpoint (e.g.
http://localhost:46657/broadcast_tx_commit?tx=_
http://localhost:46657/broadcast_tx_sync?tx=_
http://localhost:46657/commit?height=_
http://localhost:46657/dial_seeds?seeds=_
http://localhost:46657/dial_manual_peers?manual_peers=_
http://localhost:46657/subscribe?event=_
http://localhost:46657/tx?hash=_&prove=_
http://localhost:46657/unsafe_start_cpu_profiler?filename=_

View File

@ -270,14 +270,14 @@ For instance,
::
tendermint node --p2p.seeds "1.2.3.4:46656,5.6.7.8:46656"
tendermint node --p2p.manual_peers "1.2.3.4:46656,5.6.7.8:46656"
Alternatively, you can use the ``/dial_seeds`` endpoint of the RPC to
Alternatively, you can use the ``/dial_manual_peers`` endpoint of the RPC to
specify peers 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 --data-urlencode "manual_peers=[\"1.2.3.4:46656\",\"5.6.7.8:46656\"]" localhost:46657/dial_manual_peers
Additionally, the peer-exchange protocol can be enabled using the
``--pex`` flag, though this feature is `still under
@ -290,7 +290,7 @@ Adding a Non-Validator
Adding a non-validator is simple. Just copy the original
``genesis.json`` to ``~/.tendermint`` on the new machine and start the
node, specifying seeds as necessary. If no seeds are specified, the node
node, specifying manual_peers as necessary. If no manual_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.
@ -363,7 +363,7 @@ and the new ``priv_validator.json`` to the ``~/.tendermint`` 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.manual_peers`` or the ``/dial_manual_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.

View File

@ -380,40 +380,44 @@ func (n *Node) OnStart() error {
return err
}
err = n.dialSeedsIfAddrBookIsEmptyOrPEXFailedToConnect()
if err != nil {
return err
// Always connect to manual peers
if n.config.P2P.ManualPeers != "" {
err = n.sw.DialPeersAsync(n.addrBook, strings.Split(n.config.P2P.ManualPeers, ","), true)
if err != nil {
return err
}
}
if n.config.P2P.Seeds != "" {
err = n.dialSeedsIfAddrBookIsEmptyOrPEXFailedToConnect(strings.Split(n.config.P2P.Seeds, ","))
if err != nil {
return err
}
}
// start tx indexer
return n.indexerService.Start()
}
func (n *Node) dialSeedsIfAddrBookIsEmptyOrPEXFailedToConnect() error {
if n.config.P2P.Seeds == "" {
return nil
}
seeds := strings.Split(n.config.P2P.Seeds, ",")
func (n *Node) dialSeedsIfAddrBookIsEmptyOrPEXFailedToConnect(seeds []string) error {
// prefer peers from address book
if n.config.P2P.PexReactor && n.addrBook.Size() > 0 {
// give some time to PexReactor to connect us to other peers
const fallbackToSeedsAfterSec = 30 * time.Second
// give some time for PexReactor to connect us to other peers
const fallbackToSeedsAfter = 30 * time.Second
go func() {
time.Sleep(fallbackToSeedsAfterSec)
time.Sleep(fallbackToSeedsAfter)
// fallback to dialing seeds if for some reason we can't connect to any
// peers
outbound, inbound, _ := n.sw.NumPeers()
if n.IsRunning() && outbound+inbound == 0 {
n.DialSeeds(seeds)
// TODO: ignore error?
n.sw.DialPeersAsync(n.addrBook, seeds, false)
}
}()
return nil
}
// add seeds to the address book and dial out
return n.DialSeeds(seeds)
return n.sw.DialPeersAsync(n.addrBook, seeds, false)
}
// OnStop stops the Node. It implements cmn.Service.
@ -599,11 +603,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 (

View File

@ -100,7 +100,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 DialManualPeers or when we
// received the peer's address in r.Receive
if r.book.NeedMoreAddrs() {
r.RequestPEX(p)

View File

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

View File

@ -84,8 +84,8 @@ func (Local) DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
return core.DumpConsensusState()
}
func (Local) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
return core.UnsafeDialSeeds(seeds)
func (Local) DialManualPeers(manual_peers []string) (*ctypes.ResultDialManualPeers, error) {
return core.UnsafeDialManualPeers(manual_peers)
}
func (Local) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {

View File

@ -107,8 +107,8 @@ func (c Client) NetInfo() (*ctypes.ResultNetInfo, error) {
return core.NetInfo()
}
func (c Client) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
return core.UnsafeDialSeeds(seeds)
func (c Client) DialManualPeers(manual_peers []string) (*ctypes.ResultDialManualPeers, error) {
return core.UnsafeDialManualPeers(manual_peers)
}
func (c Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {

View File

@ -94,7 +94,7 @@ Endpoints that require arguments:
/broadcast_tx_commit?tx=_
/broadcast_tx_sync?tx=_
/commit?height=_
/dial_seeds?seeds=_
/dial_manual_peers?manual_peers=_
/subscribe?event=_
/tx?hash=_&prove=_
/unsafe_start_cpu_profiler?filename=_

View File

@ -54,18 +54,18 @@ func NetInfo() (*ctypes.ResultNetInfo, error) {
}, nil
}
func UnsafeDialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
func UnsafeDialManualPeers(manual_peers []string) (*ctypes.ResultDialManualPeers, error) {
if len(seeds) == 0 {
return &ctypes.ResultDialSeeds{}, fmt.Errorf("No seeds provided")
if len(manual_peers) == 0 {
return &ctypes.ResultDialManualPeers{}, fmt.Errorf("No manual peers provided")
}
// starts go routines to dial each seed after random delays
logger.Info("DialSeeds", "addrBook", addrBook, "seeds", seeds)
err := p2pSwitch.DialSeeds(addrBook, seeds)
// starts go routines to dial each peer after random delays
logger.Info("DialManualPeers", "addrBook", addrBook, "manual_peers", manual_peers)
err := p2pSwitch.DialPeersAsync(addrBook, manual_peers, true)
if err != nil {
return &ctypes.ResultDialSeeds{}, err
return &ctypes.ResultDialManualPeers{}, err
}
return &ctypes.ResultDialSeeds{"Dialing seeds in progress. See /net_info for details"}, nil
return &ctypes.ResultDialManualPeers{"Dialing manual peers in progress. See /net_info for details"}, nil
}
// Get genesis file.

View File

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

View File

@ -38,7 +38,7 @@ var Routes = map[string]*rpc.RPCFunc{
func AddUnsafeRoutes() {
// control API
Routes["dial_seeds"] = rpc.NewRPCFunc(UnsafeDialSeeds, "seeds")
Routes["dial_manual_peers"] = rpc.NewRPCFunc(UnsafeDialManualPeers, "manual_peers")
Routes["unsafe_flush_mempool"] = rpc.NewRPCFunc(UnsafeFlushMempool, "")
// profiler API

View File

@ -82,7 +82,7 @@ type ResultNetInfo struct {
Peers []Peer `json:"peers"`
}
type ResultDialSeeds struct {
type ResultDialManualPeers struct {
Log string `json:"log"`
}

View File

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

View File

@ -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"
MANUAL_PEERS="$(test/p2p/ip.sh 1):46656"
for j in `seq 2 $N`; do
SEEDS="$SEEDS,$(test/p2p/ip.sh $j):46656"
MANUAL_PEERS="$MANUAL_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.manual_peers $MANUAL_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"

View File

@ -7,10 +7,10 @@ N=$3
APP_PROXY=$4
set +u
SEEDS=$5
if [[ "$SEEDS" != "" ]]; then
echo "Seeds: $SEEDS"
SEEDS="--p2p.seeds $SEEDS"
MANUAL_PEERS=$5
if [[ "$MANUAL_PEERS" != "" ]]; then
echo "ManualPeers: $MANUAL_PEERS"
MANUAL_PEERS="--p2p.manual_peers $MANUAL_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" "$MANUAL_PEERS --p2p.pex --rpc.unsafe"
done

12
test/p2p/manual_peers.sh Normal file
View File

@ -0,0 +1,12 @@
#! /bin/bash
set -eu
N=$1
cd "$GOPATH/src/github.com/tendermint/tendermint"
manual_peers="$(test/p2p/ip.sh 1):46656"
for i in $(seq 2 $N); do
manual_peers="$manual_peers,$(test/p2p/ip.sh $i):46656"
done
echo "$manual_peers"

View File

@ -19,13 +19,13 @@ for i in `seq 1 $N`; do
done
set -e
# seeds need quotes
seeds="\"$(test/p2p/ip.sh 1):46656\""
# manual_peers need quotes
manual_peers="\"$(test/p2p/ip.sh 1):46656\""
for i in `seq 2 $N`; do
seeds="$seeds,\"$(test/p2p/ip.sh $i):46656\""
manual_peers="$manual_peers,\"$(test/p2p/ip.sh $i):46656\""
done
echo $seeds
echo $manual_peers
echo $seeds
echo $manual_peers
IP=$(test/p2p/ip.sh 1)
curl --data-urlencode "seeds=[$seeds]" "$IP:46657/dial_seeds"
curl --data-urlencode "manual_peers=[$manual_peers]" "$IP:46657/dial_manual_peers"

View File

@ -11,5 +11,5 @@ 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
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_manual_peers"
bash test/p2p/pex/test_dial_manual_peers.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP

View File

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

View File

@ -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_manual_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
MANUAL_PEERS=""
bash test/p2p/local_testnet_start.sh $DOCKER_IMAGE $NETWORK_NAME $N $PROXY_APP $MANUAL_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 manual_peers from one node
CLIENT_NAME="dial_manual_peers"
bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME $CLIENT_NAME "test/p2p/pex/dial_manual_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_manual_peers_basic"
bash test/p2p/client.sh $DOCKER_IMAGE $NETWORK_NAME $CLIENT_NAME "test/p2p/basic/test.sh $N"

View File

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

View File

@ -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)
MANUAL_PEERS=$(bash test/p2p/manual_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" "$MANUAL_PEERS"
# test basic connectivity and consensus
# start client container and check the num peers and height for all nodes