From b3cdb4fdbb65e2d57a87db5f1168cb542351bd7a Mon Sep 17 00:00:00 2001 From: Greg Szabo Date: Tue, 4 May 2021 19:50:20 -0400 Subject: [PATCH 1/3] Scripts for Gaiad network with full-mesh IBC connections --- scripts/full-mesh/.gitignore | 6 + scripts/full-mesh/1-create-network-config.sh | 80 +++++++++ scripts/full-mesh/2-create-hermes-config.sh | 67 +++++++ scripts/full-mesh/3-create-onchain-config.sh | 32 ++++ scripts/full-mesh/4-create-relayer-config.sh | 43 +++++ scripts/full-mesh/Makefile | 44 +++++ scripts/full-mesh/README.md | 177 +++++++++++++++++++ scripts/full-mesh/make.drawio | 1 + scripts/full-mesh/make.png | Bin 0 -> 46963 bytes 9 files changed, 450 insertions(+) create mode 100644 scripts/full-mesh/.gitignore create mode 100755 scripts/full-mesh/1-create-network-config.sh create mode 100755 scripts/full-mesh/2-create-hermes-config.sh create mode 100755 scripts/full-mesh/3-create-onchain-config.sh create mode 100755 scripts/full-mesh/4-create-relayer-config.sh create mode 100644 scripts/full-mesh/Makefile create mode 100644 scripts/full-mesh/README.md create mode 100644 scripts/full-mesh/make.drawio create mode 100644 scripts/full-mesh/make.png diff --git a/scripts/full-mesh/.gitignore b/scripts/full-mesh/.gitignore new file mode 100644 index 0000000000..89348ef504 --- /dev/null +++ b/scripts/full-mesh/.gitignore @@ -0,0 +1,6 @@ +docker-compose.gaiad.yml +docker-compose.yml +paths +network*/ +.hermes/ +.gaia/ diff --git a/scripts/full-mesh/1-create-network-config.sh b/scripts/full-mesh/1-create-network-config.sh new file mode 100755 index 0000000000..344e962acc --- /dev/null +++ b/scripts/full-mesh/1-create-network-config.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +############################## +## Script setup +############################## + +# Fail if there are any errors +set -eu + +# Run in a subfolder, not in your $HOME (safeguard against accidental .gaia-deletions) +test "$HOME" != "$(pwd)" + +EXPECTED_GAIAD_VERSION=4.2.1 +DOCKER_IMAGE="cephalopodequipment/gaiad:${EXPECTED_GAIAD_VERSION}" +GAIAD="docker run --rm -v $(pwd):/home/gaiad --entrypoint /usr/bin/gaiad ${DOCKER_IMAGE}" +N="${1:-5}" +echo "N=$N" + +############################## +## Create gaiad config +############################## + +for i in $(seq 1 "$N") +do + test -d "network$i" && continue + echo "i=$i" + $GAIAD testnet --chain-id "network$i" --keyring-backend test --node-dir-prefix "network${i}v" -o . --node-daemon-home . --v 1 + mv "network${i}v0" "network$i" + mv "gentxs" "network$i" + $GAIAD keys add "network${i}c0" --keyring-backend test --keyring-dir "network$i" --output json > "network${i}/client_wallet_seed.json" + $GAIAD add-genesis-account "network${i}c0" "10000000stake,10000network${i}coin" --keyring-backend test --home "network$i" +done + +############################## +## Create docker-compose.gaiad.yml +############################## + +cat < docker-compose.gaiad.yml +services: +EOF + +for i in $(seq 1 "$N") +do + RPC="$((26000 + 10 * i))" + LEET="$((RPC + 1))" + GRPC="$((RPC + 2))" + PP="$((RPC + 3))" + + cat <> docker-compose.gaiad.yml + network${i}: + container_name: network${i} + image: "$DOCKER_IMAGE" + entrypoint: "/usr/bin/gaiad" + command: start --x-crisis-skip-assert-invariants + ports: + - "$RPC:26657" + - "$LEET:1317" + - "$GRPC:9090" + - "$PP:26656" + volumes: + - $(pwd)/network${i}:/home/gaiad/.gaia +EOF + +done + +############################## +## Create full-mesh (default) networks connection graph +############################## + +echo "# IBC full-mesh connection graph" > paths + +for i in $(seq 1 "$((N-1))") +do + for j in $(seq "$((i+1))" "$N") + do + test $i -eq $j && continue + echo "$i $j" >> paths + done +done + diff --git a/scripts/full-mesh/2-create-hermes-config.sh b/scripts/full-mesh/2-create-hermes-config.sh new file mode 100755 index 0000000000..2cf099cc2b --- /dev/null +++ b/scripts/full-mesh/2-create-hermes-config.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +############################## +## Script setup +############################## + +# Fail if there are any errors +set -eu + +# Run in a subfolder, not in your $HOME (safeguard against accidental .hermes-deletions) +test "$HOME" != "$(pwd)" +# But if hermes was not run locally, we're going to overcome the issue of not having a --home parameter +ln -s $(pwd)/.hermes $HOME/.hermes || echo "Warning: hermes home folder is .hermes, but binary will search at $HOME/.hermes" + +EXPECTED_HERMES_VERSION=0.2.0 +DOCKER_IMAGE="informaldev/hermes:${EXPECTED_HERMES_VERSION}" +HERMES="docker run --rm -v $(pwd):/home/hermes --entrypoint /usr/bin/hermes ${DOCKER_IMAGE}" +N="${1:-5}" +echo "N=$N" + +############################## +## Create config.toml +############################## + +rm -rf .hermes && mkdir .hermes + +cat < .hermes/config.toml +[global] +strategy = 'naive' +log_level = 'info' + +EOF + +for i in $(seq 1 "$N") +do + RPC="$((26000 + 10 * i))" + GRPC="$((RPC + 2))" + + cat <> .hermes/config.toml +[[chains]] +id='network${i}' +rpc_addr='http://localhost:${RPC}' +grpc_addr='https://localhost:${GRPC}' +websocket_addr='ws://localhost:${RPC}/websocket' +rpc_timeout='1s' +account_prefix='cosmos' +key_name='network${i}c0' +store_prefix='ibc' +fee_denom='stake' + +[chains.trust_threshold] +numerator = '1' +denominator = '3' + +EOF + +done + +############################## +## Add keys to hermes +############################## + +for i in $(seq 1 "$N") +do + $HERMES keys add "network$i" -f "network${i}/client_wallet_seed.json" +done + diff --git a/scripts/full-mesh/3-create-onchain-config.sh b/scripts/full-mesh/3-create-onchain-config.sh new file mode 100755 index 0000000000..09af31ab99 --- /dev/null +++ b/scripts/full-mesh/3-create-onchain-config.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +############################## +## Script setup +############################## + +# Fail if there are any errors +set -eu + +# Run in a subfolder, not in your $HOME (safeguard against accidental .hermes-deletions) +test "$HOME" != "$(pwd)" +# But if hermes was not run locally, we're going to overcome the issue of not having a --home parameter +test -e $HOME/.hermes || ln -s $(pwd)/.hermes $HOME/.hermes + +EXPECTED_HERMES_VERSION=0.2.0 +DOCKER_IMAGE="informaldev/hermes:${EXPECTED_HERMES_VERSION}" +HERMES="docker run --rm -v $(pwd)/.hermes:/home/hermes/.hermes --net=host --entrypoint /usr/bin/hermes ${DOCKER_IMAGE}" + +############################## +## Create paths on the networks +############################## + +while read -r line; +do + VALID="$(echo "$line" | grep '^[ ]*[0-9]\+[ ]\+[0-9]\+[ ]*$' || echo "")" + test -n "$VALID" || continue + i="$(echo "$line" | grep -o '[0-9]\+' | head -1)" + j="$(echo "$line" | grep -o '[0-9]\+' | tail -1)" + echo "Connecting network$i and network$j" + $HERMES create channel "network$i" "network$j" --port-a transfer --port-b transfer +done < paths + diff --git a/scripts/full-mesh/4-create-relayer-config.sh b/scripts/full-mesh/4-create-relayer-config.sh new file mode 100755 index 0000000000..3006e3b971 --- /dev/null +++ b/scripts/full-mesh/4-create-relayer-config.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +############################## +## Script setup +############################## + +# Fail if there are any errors +set -eu + +# Run in a subfolder, not in your $HOME (safeguard against accidental .hermes-deletions) +test "$HOME" != "$(pwd)" + +EXPECTED_HERMES_VERSION=0.2.0 +DOCKER_IMAGE="informaldev/hermes:${EXPECTED_HERMES_VERSION}" + +############################## +## Create docker-compose.yml (set of hermes relayers) +############################## + +cat < docker-compose.yml +services: +EOF + +while read -r line; +do + VALID="$(echo "$line" | grep '^[ ]*[0-9]\+[ ]\+[0-9]\+[ ]*$' || echo "")" + test -n "$VALID" || continue + i="$(echo "$line" | grep -o '[0-9]\+' | head -1)" + j="$(echo "$line" | grep -o '[0-9]\+' | tail -1)" + + cat <> docker-compose.yml + hermes-${i}-${j}: + container_name: hermes-${i}-${j} + network_mode: "host" + image: "$DOCKER_IMAGE" + entrypoint: "/usr/bin/hermes" + command: start network$i network$j -p transfer -c channel-0 + volumes: + - $(pwd)/.hermes:/home/hermes/.hermes +EOF + +done < paths + diff --git a/scripts/full-mesh/Makefile b/scripts/full-mesh/Makefile new file mode 100644 index 0000000000..ad108cbfa7 --- /dev/null +++ b/scripts/full-mesh/Makefile @@ -0,0 +1,44 @@ +# Number of nodes +N?=5 + +all: setup-network setup-relay + +setup-network: config-files network-up +setup-relay: config-onchain relay-up + +config-files: + ./1-create-network-config.sh $(N) + ./2-create-hermes-config.sh $(N) + +network-up: + docker compose -f docker-compose.gaiad.yml -p gaiad up -d + sleep 5 + +network-down: + docker compose -f docker-compose.gaiad.yml -p gaiad down || true + +config-onchain: paths + ./3-create-onchain-config.sh + ./4-create-relayer-config.sh + + +# Todo: move the relay-* commands to `docker compose` when this is fixed: +# https://github.com/docker/compose-cli/issues/1637 +# Use docker-compose until then. +relay-up: + docker-compose up -d + +relay-start: + docker-compose start + +relay-stop: + docker-compose stop + +relay-down: + docker-compose down || true + +clean: relay-down network-down + @rm -rf gentxs network[0-9]* docker-compose.gaiad.yml docker-compose.yml paths .gaia .hermes + @echo DONE + +.PHONY: config-files network-up network-down config-onchain relay-up relay-start relay-stop relay-down clean all diff --git a/scripts/full-mesh/README.md b/scripts/full-mesh/README.md new file mode 100644 index 0000000000..33f7eed8e1 --- /dev/null +++ b/scripts/full-mesh/README.md @@ -0,0 +1,177 @@ +# Multi-chain (full-mesh) tool +This tool will create multiple chains and IBC connections among them with minimal help. + +Tested on MacOS Mojave. + +## Requirements +* Docker +* `make` for convenient command execution + +Note: the files are kept simple where possible. If `make` is not available, you can copy-paste the instructions from the +Makefile fairly easily. + +## Quick start +Run the below to create 5 blockchain networks with a full mesh of IBC connections. +``` +make +``` +The chains will be named network1, network2, network3, network4 and network5 and they are created using `docker compose`. + +Sending all IBC connection messages can take up to 10-12 minutes (todo: make this parallel). + +If you want something quicker, run the same command instead for 3 blockchain networks by running: +``` +make N=3 +``` + +All configuration is locally editable: networks have their own folder with the configuration and the database so +you can easily change anything or reset the network. Networks can be stopped and restarted using regular docker commands. + +The hermes configuration is stored locally under the `.hermes` folder. + +To delete all networks and configuration, run: +``` +make clean +``` +This will stop the chains, the relayers and clean up the configuration files. + +### Less-than full mesh +You can tell the setup process which blockchain networks should have IBC connections. + +For this, you have to run the setup process in two steps and edit a file in-between that describes the network connections: +``` +make setup-network +vi paths +make setup-relay +``` +The first step will run the blockchain networks and provide a file (`paths`) that contains the full-mesh configuration. +Edit this file to your liking by removing any connections among blockchain networks that you don't want to set up. +The third command will resume the setup process and create the hermes configuration and start the relayers based on this file. + +Example paths file for a five-network full mesh: +``` +# IBC full-mesh connection graph +1 2 +1 3 +1 4 +1 5 +2 3 +2 4 +2 5 +3 4 +3 5 +4 5 +``` + +## Command reference + +![MAKE command hierarchy](make.png "MAKE hierarchy") + +### `make all` +* Same as `make`. +* Equals to `make setup-network setup-relay` +* Creates a 5-network full-mesh. Use the `N=` parameter to change the number of networks. + +### `make setup-network` +* Set up the configuration for the gaiad blockchain networks and start them using docker-compose. +* Equals to `make config-files network-up` +* Creates a 5-network full-mesh. Use the `N=` parameter to change the number of networks. + +### `make setup-relay` +* Set up the configuration for hermes and the relayer processes and start them using docker-compose. +* Equals to `make config-onchain relay-up` +* Uses the `paths` file to figure out which networks have connections. + +### `make config-files` +* Creates the blockchain networks configuration files. (Under `network1`, `network2`, etc...) +* Creates the `.hermes` folder and adds all network keys to hermes. +* Creates the `paths` file with the descriptions of the network connections. +* Equals to running two bash scripts (`1-create-network-config.sh` and `2-create-hermes-config.sh`). +* Creates a 5-network configuration. Use the `N=` parameter to change the number of networks. + +### `make network-up` +* Runs the gaiad blockchain networks using docker. +* Equals to `docker compose -f docker-compose.gaiad.yml -p gaiad up -d` +* Pairs with `make network-down`. + +Convenience function. There is another set of containers (the relayers) that are configured separately with less parameters. +(Hence the `--project` and `--file` parameters here.) + +### `make config-onchain` +* Configure the networks' IBC connections to each other using hermes. +* Configure the `docker-compose.yml` that describes the relayer processes among the networks. +* Equals to running two bash scripts (`3-create-onchain-config.sh` and `4-create-relayer-config.sh`). +* Uses the `paths` file to figure out which networks connect to which networks. + +### `make relay-up` +* Start the hermes relayer services using `docker-compose.yml`. +* Equals to `docker-compose up -d` (yay). +* Pairs with `make relay-down`. + +### `make relay-down` +* Stop the hermes relayer services using `docker-compose.yml`. +* This does not delete the hermes configuration. +* Equals to `docker-compose down`. +* Pairs with `make relay-up`. + +### `make network-down` +* Stop and delete the gaiad blockchain networks' docker containers. +* This does not delete the blockchain configuration or database. +* Equals to `docker compose -f docker-compose.gaiad.yml -p gaiad down -d` +* Pairs with `make network-up`. + +### `make clean` +* Stop and delete all docker containers (gaiad and relayers). +* Delete all networks data and configuration as well as hermes configuration. +* Might show error messages on the screen if some of the docker containers are not running. + It will still exit with error code 0. + +## Wallets +Each chain has two wallet addresses preconfigured with tokens: one for the validator and one additional for generic use. + +Wallets can be reached by using the `--keyring-backend test --keyring-dir networkX` parameters where networkX is the +chain's configuration folder. + +## Ports +All ports are forwarded to the host machine on port 26XXY where XX is the (zero-padded) network identifier number and +Y is the port as follows: +``` +0 - RPC (26657) +1 - APP (1317) +2 - GRPC (9090) +3 - P2P (26656) +``` + +This way `network1`'s ports are: +``` +26010 - RPC +26011 - APP +26012 - GRPC +26013 - P2P +``` + +whereas `network5`'s ports are: +``` +26050 - RPC +26051 - APP +26052 - GRPC +26053 - P2P +``` + +## Examples +Query list of keys on network1: +``` +gaiad keys list --keyring-backend test --keyring-dir network1 +``` + +Get the account balance of a key on network1: +``` +gaiad query bank balances cosmos135vqr04clpx0d0nw3xljpuggps7ffvq3u5mww7 --node http://localhost:26010 +``` + +## Statistics +Setup on my machine: +* N=2 takes about 1.5 minutes +* N=3 takes about 4 minutes +* N=4 takes about 8 minutes +* N=5 takes about 11 minutes diff --git a/scripts/full-mesh/make.drawio b/scripts/full-mesh/make.drawio new file mode 100644 index 0000000000..36a0ecfc94 --- /dev/null +++ b/scripts/full-mesh/make.drawio @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/full-mesh/make.png b/scripts/full-mesh/make.png new file mode 100644 index 0000000000000000000000000000000000000000..ed853d7817aaf7c091e21d40c61192731a04d45b GIT binary patch literal 46963 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 Date: Wed, 5 May 2021 20:11:53 -0400 Subject: [PATCH 2/3] Fixes and improvements --- CHANGELOG.md | 4 ++++ scripts/full-mesh/2-create-hermes-config.sh | 2 +- scripts/full-mesh/3-create-onchain-config.sh | 2 +- scripts/full-mesh/Makefile | 21 +++++++++----------- scripts/full-mesh/README.md | 18 +++++++++++++---- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cda932d5b2..c8693321e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ Jongwhan Lee (@leejw51crypto) ([#878]). - [ibc-relayer] - Change the default for client creation to allow governance recovery in case of expiration or misbehaviour ([#785]) +- [scripts] + - Added "full-mesh" scripts to simulate multiple interconnected networks on a local machine ([#897]) + ### BUG FIXES - [ibc] @@ -53,6 +56,7 @@ Jongwhan Lee (@leejw51crypto) ([#878]). [#861]: https://github.com/informalsystems/ibc-rs/issues/861 [#869]: https://github.com/informalsystems/ibc-rs/issues/869 [#878]: https://github.com/informalsystems/ibc-rs/issues/878 +[#897]: https://github.com/informalsystems/ibc-rs/issues/897 ## v0.2.0 diff --git a/scripts/full-mesh/2-create-hermes-config.sh b/scripts/full-mesh/2-create-hermes-config.sh index 2cf099cc2b..f8ade4824e 100755 --- a/scripts/full-mesh/2-create-hermes-config.sh +++ b/scripts/full-mesh/2-create-hermes-config.sh @@ -10,7 +10,7 @@ set -eu # Run in a subfolder, not in your $HOME (safeguard against accidental .hermes-deletions) test "$HOME" != "$(pwd)" # But if hermes was not run locally, we're going to overcome the issue of not having a --home parameter -ln -s $(pwd)/.hermes $HOME/.hermes || echo "Warning: hermes home folder is .hermes, but binary will search at $HOME/.hermes" +ln -s $(pwd)/.hermes $HOME/.hermes || echo "$HOME/.hermes is already set, make sure you link it to .hermes here if you run things locally" EXPECTED_HERMES_VERSION=0.2.0 DOCKER_IMAGE="informaldev/hermes:${EXPECTED_HERMES_VERSION}" diff --git a/scripts/full-mesh/3-create-onchain-config.sh b/scripts/full-mesh/3-create-onchain-config.sh index 09af31ab99..1d85a47049 100755 --- a/scripts/full-mesh/3-create-onchain-config.sh +++ b/scripts/full-mesh/3-create-onchain-config.sh @@ -10,7 +10,7 @@ set -eu # Run in a subfolder, not in your $HOME (safeguard against accidental .hermes-deletions) test "$HOME" != "$(pwd)" # But if hermes was not run locally, we're going to overcome the issue of not having a --home parameter -test -e $HOME/.hermes || ln -s $(pwd)/.hermes $HOME/.hermes +ln -s $(pwd)/.hermes $HOME/.hermes || echo "$HOME/.hermes is already set, make sure you link it to .hermes here if you run things locally" EXPECTED_HERMES_VERSION=0.2.0 DOCKER_IMAGE="informaldev/hermes:${EXPECTED_HERMES_VERSION}" diff --git a/scripts/full-mesh/Makefile b/scripts/full-mesh/Makefile index ad108cbfa7..f47f8a12ef 100644 --- a/scripts/full-mesh/Makefile +++ b/scripts/full-mesh/Makefile @@ -14,6 +14,12 @@ network-up: docker compose -f docker-compose.gaiad.yml -p gaiad up -d sleep 5 +network-start: + docker compose -f docker-compose.gaiad.yml -p gaiad start + +network-stop: + docker compose -f docker-compose.gaiad.yml -p gaiad stop + network-down: docker compose -f docker-compose.gaiad.yml -p gaiad down || true @@ -21,21 +27,12 @@ config-onchain: paths ./3-create-onchain-config.sh ./4-create-relayer-config.sh - -# Todo: move the relay-* commands to `docker compose` when this is fixed: -# https://github.com/docker/compose-cli/issues/1637 -# Use docker-compose until then. +# If this command fails with aliases, you need to upgrade Docker CLI to 1.0.14 or above. relay-up: - docker-compose up -d - -relay-start: - docker-compose start - -relay-stop: - docker-compose stop + docker compose up -d relay-down: - docker-compose down || true + docker compose down || true clean: relay-down network-down @rm -rf gentxs network[0-9]* docker-compose.gaiad.yml docker-compose.yml paths .gaia .hermes diff --git a/scripts/full-mesh/README.md b/scripts/full-mesh/README.md index 33f7eed8e1..4036bb3025 100644 --- a/scripts/full-mesh/README.md +++ b/scripts/full-mesh/README.md @@ -73,12 +73,12 @@ Example paths file for a five-network full mesh: * Creates a 5-network full-mesh. Use the `N=` parameter to change the number of networks. ### `make setup-network` -* Set up the configuration for the gaiad blockchain networks and start them using docker-compose. +* Set up the configuration for the gaiad blockchain networks and start them using docker compose. * Equals to `make config-files network-up` * Creates a 5-network full-mesh. Use the `N=` parameter to change the number of networks. ### `make setup-relay` -* Set up the configuration for hermes and the relayer processes and start them using docker-compose. +* Set up the configuration for hermes and the relayer processes and start them using docker compose. * Equals to `make config-onchain relay-up` * Uses the `paths` file to figure out which networks have connections. @@ -105,13 +105,13 @@ Convenience function. There is another set of containers (the relayers) that are ### `make relay-up` * Start the hermes relayer services using `docker-compose.yml`. -* Equals to `docker-compose up -d` (yay). +* Equals to `docker compose up -d` (yay, easy). * Pairs with `make relay-down`. ### `make relay-down` * Stop the hermes relayer services using `docker-compose.yml`. * This does not delete the hermes configuration. -* Equals to `docker-compose down`. +* Equals to `docker compose down`. * Pairs with `make relay-up`. ### `make network-down` @@ -120,6 +120,16 @@ Convenience function. There is another set of containers (the relayers) that are * Equals to `docker compose -f docker-compose.gaiad.yml -p gaiad down -d` * Pairs with `make network-up`. +### `make network-start` +* Start an existing gaiad blockchain networks' docker containers that were previously stopped. +* Equals to `docker compose -f docker-compose.gaiad.yml -p gaiad start` +* Pairs with `make network-stop`. + +### `make network-stop` +* Stop a running set of gaiad blockchain networks' docker containers. +* Equals to `docker compose -f docker-compose.gaiad.yml -p gaiad stop` +* Pairs with `make network-start`. + ### `make clean` * Stop and delete all docker containers (gaiad and relayers). * Delete all networks data and configuration as well as hermes configuration. From 9ecc59cd5a5e2a0ff336c86c31f4c0f0b558ef31 Mon Sep 17 00:00:00 2001 From: Greg Szabo Date: Fri, 7 May 2021 11:22:59 -0400 Subject: [PATCH 3/3] README update --- scripts/full-mesh/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/full-mesh/README.md b/scripts/full-mesh/README.md index 4036bb3025..1bf1dae5e2 100644 --- a/scripts/full-mesh/README.md +++ b/scripts/full-mesh/README.md @@ -4,12 +4,14 @@ This tool will create multiple chains and IBC connections among them with minima Tested on MacOS Mojave. ## Requirements -* Docker +* Docker (with Docker CLI v1.0.14 or above, released in 2021 April) * `make` for convenient command execution Note: the files are kept simple where possible. If `make` is not available, you can copy-paste the instructions from the Makefile fairly easily. +Note: if you get startup issues with "network-scoped alias support" errors, you need to [upgrade your Docker CLI to v1.0.14 or above](https://github.com/docker/compose-cli/issues/1637). + ## Quick start Run the below to create 5 blockchain networks with a full mesh of IBC connections. ```