From f28efaa1f19ee8d92198bdb75f45ae200bb447b0 Mon Sep 17 00:00:00 2001 From: adlrocha <6717133+adlrocha@users.noreply.github.com> Date: Tue, 26 Sep 2023 20:24:51 +0200 Subject: [PATCH] FM-150: Subnet deployment scripts (#222) * Add scripts to deploy testnet nodes Co-authored-by: Denis Kolegov Co-authored-by: Akosh Farkash --- Cargo.lock | 86 ++++++++++++-- Cargo.toml | 1 + README.md | 2 + docs/localnet.md | 61 ++++++++++ fendermint/app/Cargo.toml | 1 + fendermint/app/options/src/key.rs | 17 +++ fendermint/app/src/cmd/key.rs | 46 ++++++-- infra/.env | 1 + infra/Cargo.toml | 11 ++ infra/Makefile.toml | 98 ++++++++++++++++ infra/docker-compose.yml | 62 ++++++++++ infra/run.sh | 50 ++++++++ infra/scripts/cometbft.toml | 43 +++++++ infra/scripts/docker.toml | 24 ++++ infra/scripts/ethapi.toml | 32 ++++++ infra/scripts/fendermint.toml | 46 ++++++++ infra/scripts/node.toml | 111 ++++++++++++++++++ infra/scripts/testnet.toml | 185 ++++++++++++++++++++++++++++++ 18 files changed, 853 insertions(+), 24 deletions(-) create mode 100644 docs/localnet.md create mode 100644 infra/.env create mode 100644 infra/Cargo.toml create mode 100644 infra/Makefile.toml create mode 100644 infra/docker-compose.yml create mode 100755 infra/run.sh create mode 100644 infra/scripts/cometbft.toml create mode 100644 infra/scripts/docker.toml create mode 100644 infra/scripts/ethapi.toml create mode 100644 infra/scripts/fendermint.toml create mode 100644 infra/scripts/node.toml create mode 100644 infra/scripts/testnet.toml diff --git a/Cargo.lock b/Cargo.lock index 48ba4096..3a5dd9cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2737,7 +2737,7 @@ dependencies = [ "futures", "im", "structopt", - "tendermint", + "tendermint 0.31.1", "tokio", "tower", "tower-abci", @@ -2791,8 +2791,9 @@ dependencies = [ "serde_json", "serde_with", "tempfile", - "tendermint", - "tendermint-proto", + "tendermint 0.31.1", + "tendermint-config 0.33.1", + "tendermint-proto 0.31.1", "tendermint-rpc", "tokio", "tower-abci", @@ -2871,7 +2872,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "tendermint", + "tendermint 0.31.1", "tendermint-rpc", "thiserror", "tokio", @@ -2928,8 +2929,8 @@ dependencies = [ "lazy_static", "prost", "serde", - "tendermint", - "tendermint-proto", + "tendermint 0.31.1", + "tendermint-proto 0.31.1", "tendermint-rpc", "tokio", "tracing", @@ -8453,7 +8454,36 @@ dependencies = [ "signature 2.1.0", "subtle", "subtle-encoding", - "tendermint-proto", + "tendermint-proto 0.31.1", + "time", + "zeroize", +] + +[[package]] +name = "tendermint" +version = "0.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c293cdbb6e13bad728bce26584a3a89d7cb5ea0b4b9db796fded10bae4a0b06b" +dependencies = [ + "bytes", + "digest 0.10.7", + "ed25519 2.2.2", + "ed25519-consensus", + "flex-error", + "futures", + "num-traits", + "once_cell", + "prost", + "prost-types", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2 0.10.7", + "signature 2.1.0", + "subtle", + "subtle-encoding", + "tendermint-proto 0.33.1", "time", "zeroize", ] @@ -8467,7 +8497,21 @@ dependencies = [ "flex-error", "serde", "serde_json", - "tendermint", + "tendermint 0.31.1", + "toml 0.5.11", + "url", +] + +[[package]] +name = "tendermint-config" +version = "0.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007da10d992c93039bde6a962ec0ab12e3520695cebb9542d5c9011de29341e3" +dependencies = [ + "flex-error", + "serde", + "serde_json", + "tendermint 0.33.1", "toml 0.5.11", "url", ] @@ -8490,6 +8534,24 @@ dependencies = [ "time", ] +[[package]] +name = "tendermint-proto" +version = "0.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03dcd29922e5670af2307f3d8e58c9720ec94b15b92ef85fe9ed0f4b25fbde44" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost", + "prost-types", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + [[package]] name = "tendermint-rpc" version = "0.31.1" @@ -8514,8 +8576,8 @@ dependencies = [ "serde_json", "subtle", "subtle-encoding", - "tendermint", - "tendermint-config", + "tendermint 0.31.1", + "tendermint-config 0.31.1", "thiserror", "time", "tokio", @@ -8846,8 +8908,8 @@ dependencies = [ "futures", "pin-project", "prost", - "tendermint", - "tendermint-proto", + "tendermint 0.31.1", + "tendermint-proto 0.31.1", "tokio", "tokio-stream", "tokio-util 0.6.10", diff --git a/Cargo.toml b/Cargo.toml index f128df0e..f8c29476 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,6 +120,7 @@ cid = { version = "0.8", features = ["serde-codec", "std"] } # Using the same tendermint-rs dependency as tower-abci. From both we are interested in v037 modules. tower-abci = { version = "0.7" } tendermint = { version = "0.31", features = ["secp256k1"] } +tendermint-config = "0.33.0" tendermint-rpc = { version = "0.31", features = ["secp256k1", "http-client", "websocket-client"] } tendermint-proto = { version = "0.31" } diff --git a/README.md b/README.md index d6e7960d..35b3263f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Fendermint is an effort to implement [IPC with Tendermint Core](https://docs.google.com/document/d/1cFoTdoRuYgxmWJia6K-b5vmEj-4MvyHCNvShZpyconU/edit#). There is a preliminary [roadmap](https://docs.google.com/spreadsheets/d/1eVwkHEPGNg0js8DKRDIX7sugf5JqbI9zRBddIqzJFfI/edit#gid=0) that lays out the tasks towards implementing subnets that run IPLD and FVM under the Filecoin rootnet, sharing components with the Lotus/Eudico based implementation. +## Quick Start +- [Local testnets](./docs/localnet.md) ## Docs diff --git a/docs/localnet.md b/docs/localnet.md new file mode 100644 index 00000000..bb4f7770 --- /dev/null +++ b/docs/localnet.md @@ -0,0 +1,61 @@ +# Local Testnets + +Prerequisites: +```bash +make build docker-build +``` + +## Single node deployment + +To run IPC in the local rootnet just perform the following : +```bash +cargo make --makefile ./infra/Makefile.toml node + +``` + +It will create three docker containers (cometbft, fendermint, and eth-api). + +To stop run the following: +```bash +cargo make --makefile ./infra/Makefile.toml node-down +``` + +## Local 4-nodes deployment +To run IPC in the local rootnet with 4 nodes perform the following command : +```bash +cargo make --makefile ./infra/Makefile.toml testnet + +``` + +To stop the network: +```bash +cargo make --makefile ./infra/Makefile.toml testnet-down +``` + +The testnet contains four logical nodes. Each node consists of cometbft, fendermint, and ethapi containers. +The Docker internal network is `192.167.10.0/24`. + +ETH-API is accessible on the following interfaces on the Docker internal network: +- `192.167.10.10:8545` or `ethapi-node0:8545` +- `192.167.10.11:8545` or `ethapi-node1:8545` +- `192.167.10.12:8545` or `ethapi-node2:8545` +- `192.167.10.13:8545` or `ethapi-node3:8545` + +and on the following interfaces from the host machine: +- `127.0.0.1:8545` +- `127.0.0.1:8546` +- `127.0.0.1:8547` +- `127.0.0.1:8548` + +## Deployment process + +The deployment process is as follows: +- Remove all docker containers, files, networks, etc. from the previous deployment +- Create all necessary directories +- Initialize CometBFT testnet by creating `config` and `data` directories using `cometbft` tools +- Read cometbft nodes private keys,derive node IDs and store in `config.toml` for each node +- Create the `genesis` file for Fendermint +- Share the genesis among all Fendermint nodes +- Run Fendermint application in 4 containers +- Run CometBFT in 4 containers +- Run Eth API in 4 containers \ No newline at end of file diff --git a/fendermint/app/Cargo.toml b/fendermint/app/Cargo.toml index 1a0e4ca2..4ade5f03 100644 --- a/fendermint/app/Cargo.toml +++ b/fendermint/app/Cargo.toml @@ -25,6 +25,7 @@ serde = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } tendermint = { workspace = true } +tendermint-config = { workspace = true } tendermint-rpc = { workspace = true } tendermint-proto = { workspace = true } tokio = { workspace = true } diff --git a/fendermint/app/options/src/key.rs b/fendermint/app/options/src/key.rs index 9f6aed12..b399249d 100644 --- a/fendermint/app/options/src/key.rs +++ b/fendermint/app/options/src/key.rs @@ -13,6 +13,8 @@ pub enum KeyCommands { IntoTendermint(KeyIntoTendermintArgs), /// Convert a public key file from base64 into an f1 Address format an print it to STDOUT. Address(KeyAddressArgs), + /// Get the peer ID corresponding to a node ID and its network address and print it to a local file. + AddPeer(AddPeer), } #[derive(Args, Debug)] @@ -21,6 +23,21 @@ pub struct KeyArgs { pub command: KeyCommands, } +#[derive(Args, Debug)] +pub struct AddPeer { + /// The path to a CometBFT node key file. + #[arg(long, short = 'n')] + pub node_key_file: PathBuf, + /// The path to a temporal local file where the peer IDs will be added. + /// The file will be created if it doesn't exist. + #[arg(long, short)] + pub local_peers_file: PathBuf, + /// The target CometBFT node network interface in the following format `IP:Port`. + /// For example: `192.168.10.7:26656`. + #[arg(long, short)] + pub network_addr: String, +} + #[derive(Args, Debug)] pub struct KeyGenArgs { /// Name used to distinguish the files from other exported keys. diff --git a/fendermint/app/src/cmd/key.rs b/fendermint/app/src/cmd/key.rs index 1a439b2c..7bcc7ca5 100644 --- a/fendermint/app/src/cmd/key.rs +++ b/fendermint/app/src/cmd/key.rs @@ -7,21 +7,25 @@ use fvm_shared::address::Address; use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; use serde_json::json; use std::path::{Path, PathBuf}; +use tendermint_config::NodeKey; use super::{from_b64, to_b64}; use crate::{ cmd, - options::key::{KeyAddressArgs, KeyArgs, KeyCommands, KeyGenArgs, KeyIntoTendermintArgs}, + options::key::{ + AddPeer, KeyAddressArgs, KeyArgs, KeyCommands, KeyGenArgs, KeyIntoTendermintArgs, + }, }; cmd! { - KeyArgs(self) { - match &self.command { - KeyCommands::Gen(args) => args.exec(()).await, - KeyCommands::IntoTendermint(args) => args.exec(()).await, - KeyCommands::Address(args) => args.exec(()).await, + KeyArgs(self) { + match &self.command { + KeyCommands::Gen(args) => args.exec(()).await, + KeyCommands::IntoTendermint(args) => args.exec(()).await, + KeyCommands::AddPeer(args) => args.exec(()).await, + KeyCommands::Address(args) => args.exec(()).await, + } } - } } cmd! { @@ -67,14 +71,32 @@ cmd! { } cmd! { - KeyAddressArgs(self) { - let pk = read_public_key(&self.public_key)?; - let addr = Address::new_secp256k1(&pk.serialize())?; - println!("{}", addr); - Ok(()) + AddPeer(self) { + let node_key = NodeKey::load_json_file(&self.node_key_file).context("failed to read node key file")?; + let peer_id = format!("{}@{}", node_key.node_id(), self.network_addr); + let mut peers = std::fs::read_to_string(&self.local_peers_file).unwrap_or_default(); + + if peers.is_empty() { + peers.push_str(&peer_id); + } else { + peers.push(','); + peers.push_str(peer_id.as_str()); + } + + std::fs::write(&self.local_peers_file, peers).context("failed to write to the peers file")?; + Ok(()) } } +cmd! { + KeyAddressArgs(self) { + let pk = read_public_key(&self.public_key)?; + let addr = Address::new_secp256k1(&pk.serialize())?; + println!("{}", addr); + Ok(()) + } +} + fn secret_to_b64(sk: &SecretKey) -> String { to_b64(sk.serialize().as_ref()) } diff --git a/infra/.env b/infra/.env new file mode 100644 index 00000000..6093e7d7 --- /dev/null +++ b/infra/.env @@ -0,0 +1 @@ +COMETBFT_VERSION=v0.37.x \ No newline at end of file diff --git a/infra/Cargo.toml b/infra/Cargo.toml new file mode 100644 index 00000000..5f80a05d --- /dev/null +++ b/infra/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "fendermint_infra" +description = "Workflows for the deployment of Fendermint infrastructure" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/infra/Makefile.toml b/infra/Makefile.toml new file mode 100644 index 00000000..1724fed0 --- /dev/null +++ b/infra/Makefile.toml @@ -0,0 +1,98 @@ +extend = [ + { path = "scripts/docker.toml" }, + { path = "scripts/cometbft.toml" }, + { path = "scripts/fendermint.toml" }, + { path = "scripts/ethapi.toml" }, + { path = "scripts/node.toml" }, + { path = "scripts/testnet.toml" } +] + +[config] +default_to_workspace = false + +[env] +CHAIN_NAME = { value = "root", condition = { env_not_set = ["CHAIN_NAME"] }} +BALANCE = { value = "1000", condition = { env_not_set = ["BALANCE"] }} +BASE_FEE = { value = "1000", condition = { env_not_set = ["BASE_FEE"] }} +TIMESTAMP = { value = "1680101412", condition = { env_not_set = ["TIMESTAMP"] }} +BASE_DIR="${HOME}/.ipc/${CHAIN_NAME}" +FM_DIR="${BASE_DIR}/fendermint" +CMT_DIR="${BASE_DIR}/cometbft" + +GENESIS_FILE="${FM_DIR}/genesis.json" +KEYS_DIR="${FM_DIR}/keys" +KEY_NAME="validator_key" +PUB_KEY_PATH="${KEYS_DIR}/${KEY_NAME}.pk" +PRIV_KEY_PATH="${KEYS_DIR}/${KEY_NAME}.sk" + +NETWORK_NAME = "${CHAIN_NAME}" + +CMT_CONTAINER_NAME = "${NETWORK_NAME}-cometbft" +FM_CONTAINER_NAME = "${NETWORK_NAME}-fendermint" +ETHAPI_CONTAINER_NAME = "${NETWORK_NAME}-ethapi" + +CMT_DOCKER_IMAGE = "cometbft/cometbft:v0.37.x" +FM_DOCKER_IMAGE = "fendermint:latest" +TEST_DATA_DIR = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/fendermint/testing/smoke-test/test-data" +TEST_SCRIPTS_DIR = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/fendermint/testing/smoke-test/scripts" +ACTORS_BUNDLE = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/../builtin-actors/output/bundle.car" +CMT_HOST_PORT = 26657 +ETHAPI_HOST_PORT = 8545 +# If this wasn't present, any wait task is skipped. +CARGO_MAKE_WAIT_MILLISECONDS = 5000 +# This wait time seems to work locally. +CMT_WAIT_MILLIS = 10000 +# Keep example logs to a minimum. +VERBOSITY = "" + +[tasks.info] +script=""" +echo +echo Chain info: +echo - Chain: ${CHAIN_NAME} +echo - Balance: ${BALANCE} +echo - Base Fee: ${BASE_FEE} +echo - Timestamp: ${TIMESTAMP} +echo +echo Single node testnet layout: +echo - IPC directory: ${BASE_DIR} +echo - IPC Testnet directory: ${BASE_TESTNET_DIR} +echo - CometBFT directory: ${CMT_DIR} +echo - Fendermint directory: ${FM_DIR} +echo - Keys directory: ${KEYS_DIR} +echo - Genesis file: ${GENESIS_FILE} +echo - Private key: ${PRIV_KEY_PATH} +echo - Network: ${NETWORK_NAME} +echo - CometBFT container: ${CMT_CONTAINER_NAME} +echo - Fendermint container: ${FM_CONTAINER_NAME} +echo +echo +echo 4 nodes testnet layout: +echo - IPC directory: ${BASE_TESTNET_DIR} +echo - Genesis file: ${GENESIS_FILE} +echo - Network: ${NETWORK_NAME} +echo +""" + +[tasks.default] +clear = true +script_runner = "@duckscript" +script = [''' + echo + echo Main tasks: + echo - clear: Clear all information: private keys, cache, database, etc. + echo - init: Initialize the system + echo - info: Print the setup information + echo - start: Start Fendermint/CometBFT docker containers with the genesis + echo - teardown: Stop the system and clears all data + echo - run: Init and then start the system + echo + echo Most tasks use these environment variables: + echo - CHAIN_NAME (default '${CHAIN_NAME}'): the target IPC subnet + echo + echo Run 'cargo make -e CHAIN_NAME=chain -e BALANCE=100 -e BASE_FEE=200 ... COMMAND' to populate the variables from CLI or + echo Run 'cargo make --env-file=/PATH/.env COMMAND' to populate the variables from the file before running the command. + echo + echo Run 'cargo make --list-all-steps' for a complete list of available tasks. + echo +'''] diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml new file mode 100644 index 00000000..01bce9ea --- /dev/null +++ b/infra/docker-compose.yml @@ -0,0 +1,62 @@ +services: + cometbft-node: + container_name: cometbft-node${NODE_ID} + user: ${UID}:${GID} + image: "cometbft/cometbft:${COMETBFT_VERSION}" + ports: + - "${PORT1}-${PORT2}:26656-26657" + environment: + - ID=${NODE_ID} + - LOG=${LOG:-cometbft-node${NODE_ID}.log} + - CMT_PEX=true + - CMT_PROXY_APP=tcp://fendermint-node${NODE_ID}:26658 + - CMT_PERSISTENT_PEERS="${CMT_PERSISTENT_PEERS}" + volumes: + - $BASE_DIR/node${NODE_ID}/cometbft:/cometbft + healthcheck: + test: curl --fail http://localhost:26657 || exit 1 + interval: 8s + timeout: 10s + retries: 20 + networks: + testnet: + ipv4_address: ${CMT_NODE_ADDR} + + fendermint-node: + container_name: fendermint-node${NODE_ID} + user: ${UID}:${GID} + image: "fendermint:latest" + environment: + - FM_DATA_DIR=/data/fendermint/data + - FM_CHAIN_NAME=$CHAIN_NAME + - LOG_LEVEL=info + volumes: + - $BASE_DIR/node${NODE_ID}:/data + networks: + testnet: + ipv4_address: ${FMT_NODE_ADDR} + + ethapi-node: + container_name: ethapi-node${NODE_ID} + user: ${UID}:${GID} + image: "fendermint:latest" + command: "eth run" + environment: + - TENDERMINT_WS_URL=ws://cometbft-node${NODE_ID}:26657/websocket + - LOG_LEVEL=debug + - RUST_BACKTRACE=1 + ports: + - ${PORT3}:8545 + volumes: + - $BASE_DIR/node${NODE_ID}:/data + depends_on: + cometbft-node: + condition: service_healthy + networks: + testnet: + ipv4_address: ${ETHAPI_NODE_ADDR} + +networks: + testnet: + name: ${NETWORK_NAME} + external: true \ No newline at end of file diff --git a/infra/run.sh b/infra/run.sh new file mode 100755 index 00000000..c244a7d3 --- /dev/null +++ b/infra/run.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +if [ $# -ne 1 ]; then + echo "usage: $0 (start|stop)" + exit 1 +fi + +PORT1=26656 +PORT2=26657 +PORT3=8545 + +ACTION= + +case $1 in + start) ACTION="up -d" ;; + stop) ACTION="down" ;; + *) + echo "usage: $0 (start|stop)" + exit 1 + ;; +esac + +if [ "$1" == "start" ]; then + # we need to remove the network with the same name + # because that network might me created without subnet with necessary IP address space + docker network rm -f ${NETWORK_NAME} + docker network create --subnet 192.167.10.0/16 ${NETWORK_NAME} +fi + +export NETWORK_NAME=${NETWORK_NAME} + +for i in $(seq 0 3); do + export NODE_ID=${i} + export PORT1 + export PORT2 + export PORT3 + export CMT_NODE_ADDR=192.167.10.$((${i}+2)) + export FMT_NODE_ADDR=192.167.10.$((${i}+6)) + export ETHAPI_NODE_ADDR=192.167.10.$((${i}+10)) + docker compose -f ./infra/docker-compose.yml -p testnet_node_${i} $ACTION & + PORT1=$((PORT1+3)) + PORT2=$((PORT2+3)) + PORT3=$((PORT3+1)) +done + +wait $(jobs -p) + +if [ "$1" == "stop" ]; then + docker network rm -f ${NETWORK_NAME} +fi diff --git a/infra/scripts/cometbft.toml b/infra/scripts/cometbft.toml new file mode 100644 index 00000000..987a40ca --- /dev/null +++ b/infra/scripts/cometbft.toml @@ -0,0 +1,43 @@ +[tasks.cometbft-pull] +command = "docker" +args = ["pull", "${CMT_DOCKER_IMAGE}"] + +[tasks.cometbft-init] +extend = "cometbft-run" +env = { "CMD" = "init", "FLAGS" = "-a STDOUT -a STDERR --rm" } + +[tasks.cometbft-start] +extend = "cometbft-run" +env = { "CMD" = "start", "FLAGS" = "-d" } + +[tasks.cometbft-wait] +extend = "wait" +env = { "CARGO_MAKE_WAIT_MILLISECONDS" = "${CMT_WAIT_MILLIS}" } + +[tasks.cometbft-run] +script = """ +docker run \ + ${FLAGS} \ + --name ${CMT_CONTAINER_NAME} \ + --user $(id -u) \ + --network ${NETWORK_NAME} \ + --publish 26657:${CMT_HOST_PORT} \ + --volume ${CMT_DIR}:/cometbft \ + --env CMT_PROXY_APP=tcp://${FM_CONTAINER_NAME}:26658 \ + --env CMT_PEX=false \ + ${CMT_DOCKER_IMAGE} \ + ${CMD} +""" +dependencies = ["cometbft-pull", "docker-network-create"] + +[tasks.cometbft-rm] +extend = "docker-rm" +env = { "CONTAINER_NAME" = "${CMT_CONTAINER_NAME}" } + +[tasks.cometbft-stop] +extend = "docker-stop" +env = { "CONTAINER_NAME" = "${CMT_CONTAINER_NAME}" } + +[tasks.cometbft-logs] +extend = "docker-logs" +env = { "CONTAINER_NAME" = "${CMT_CONTAINER_NAME}" } \ No newline at end of file diff --git a/infra/scripts/docker.toml b/infra/scripts/docker.toml new file mode 100644 index 00000000..7c8cc75c --- /dev/null +++ b/infra/scripts/docker.toml @@ -0,0 +1,24 @@ +[tasks.docker-network-create] +command = "docker" +args = ["network", "create", "${NETWORK_NAME}"] +ignore_errors = true + +[tasks.docker-network-rm] +command = "docker" +args = ["network", "rm", "${NETWORK_NAME}"] +ignore_errors = true + +[tasks.docker-stop] +command = "docker" +args = ["stop", "${CONTAINER_NAME}"] +ignore_errors = true + +[tasks.docker-rm] +command = "docker" +args = ["rm", "--force", "${CONTAINER_NAME}"] +ignore_errors = true + +[tasks.docker-logs] +command = "docker" +args = ["logs", "${CONTAINER_NAME}"] +ignore_errors = true diff --git a/infra/scripts/ethapi.toml b/infra/scripts/ethapi.toml new file mode 100644 index 00000000..29ab0d96 --- /dev/null +++ b/infra/scripts/ethapi.toml @@ -0,0 +1,32 @@ +[tasks.ethapi-run] +script = """ +docker run \ + ${FLAGS} \ + --name ${ETHAPI_CONTAINER_NAME} \ + --init \ + --user $(id -u) \ + --network ${NETWORK_NAME} \ + --publish 8545:${ETHAPI_HOST_PORT} \ + --env TENDERMINT_WS_URL=ws://${CMT_CONTAINER_NAME}:26657/websocket \ + --env LOG_LEVEL=debug \ + --env RUST_BACKTRACE=1 \ + ${FM_DOCKER_IMAGE} \ + ${CMD} +""" +dependencies = ["docker-network-create"] + +[tasks.ethapi-start] +extend = "ethapi-run" +env = { "CMD" = "eth run", "FLAGS" = "-d" } + +[tasks.ethapi-rm] +extend = "docker-rm" +env = { "CONTAINER_NAME" = "${ETHAPI_CONTAINER_NAME}" } + +[tasks.ethapi-stop] +extend = "docker-stop" +env = { "CONTAINER_NAME" = "${ETHAPI_CONTAINER_NAME}" } + +[tasks.ethapi-logs] +extend = "docker-logs" +env = { "CONTAINER_NAME" = "${ETHAPI_CONTAINER_NAME}" } \ No newline at end of file diff --git a/infra/scripts/fendermint.toml b/infra/scripts/fendermint.toml new file mode 100644 index 00000000..966c5af5 --- /dev/null +++ b/infra/scripts/fendermint.toml @@ -0,0 +1,46 @@ +[tasks.fendermint-start] +extend = "fendermint-run" +env = { "ENTRY" = "fendermint", "CMD" = "run", "FLAGS" = "-d" } + +[tasks.fendermint-run] +script = """ +docker run \ + ${FLAGS} \ + --name ${FM_CONTAINER_NAME} \ + --init \ + --user $(id -u) \ + --network ${NETWORK_NAME} \ + --volume ${BASE_DIR}:/data \ + --env FM_DATA_DIR=/data/fendermint/data \ + --env FM_CHAIN_NAME=${NETWORK_NAME} \ + --env LOG_LEVEL=info \ + --entrypoint ${ENTRY} \ + ${FM_DOCKER_IMAGE} \ + ${CMD} +""" +dependencies = ["docker-network-create", "fendermint-deps"] + +[tasks.fendermint-deps] +script = """ +# Check if the image exists +# TODO: Check the version or use a flag to always re-build? +if docker images | awk '{print $1":"$2}' | grep fendermint; then + echo fendermint image already exists + docker images | grep fendermint +else + cd ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY} + make docker-build +fi +""" + +[tasks.fendermint-rm] +extend = "docker-rm" +env = { "CONTAINER_NAME" = "${FM_CONTAINER_NAME}" } + +[tasks.fendermint-stop] +extend = "docker-stop" +env = { "CONTAINER_NAME" = "${FM_CONTAINER_NAME}" } + +[tasks.fendermint-logs] +extend = "docker-logs" +env = { "CONTAINER_NAME" = "${FM_CONTAINER_NAME}" } \ No newline at end of file diff --git a/infra/scripts/node.toml b/infra/scripts/node.toml new file mode 100644 index 00000000..a697cbee --- /dev/null +++ b/infra/scripts/node.toml @@ -0,0 +1,111 @@ +[tasks.node] +workspace = false +dependencies = [ + "node-down", + "node-init", + "node-network-create", + "cometbft-init", + "fendermint-deps", + "node-config", + "fendermint-start", + "cometbft-start", + "cometbft-wait", + "ethapi-start" +] + +[tasks.node-network-create] +env = { "NETWORK_NAME"="${NETWORK_NAME}"} +extend = "docker-network-create" + + +[tasks.node-init] +dependencies = [ + "node-clear", + "node-mkdir", +] + +[tasks.node-clear] +script=""" +echo clearing all IPC data +rm -rf ${BASE_DIR} +""" + +[tasks.node-mkdir] +script=""" +echo creating directories: $BASE_DIR $FM_DIR $CMT_DIR +mkdir -p $BASE_DIR +mkdir -p $FM_DIR + +mkdir -p $CMT_DIR +""" + +[tasks.node-down] +# `dependencies` doesn't seem to work with `cleanup_task`. +run_task = { name = [ + "cometbft-stop", + "cometbft-rm", + "fendermint-stop", + "fendermint-rm", + "ethapi-stop", + "ethapi-rm", + "docker-network-rm" +]} + +# This task create all necessary data structures to run Fendermint: +# the genesis file with necessary entities and cryptographic keys. +[tasks.node-config] +dependencies = [ + "node-script-new-genesis", + "node-script-new-key", + "node-script-new-account", + "node-script-add-validator", + "node-script-new-gateway", + "node-script-export-keys" +] + +[tasks.node-script-new-genesis] +cwd = "./target/release" +script = """ +./fendermint genesis --genesis-file ${GENESIS_FILE} new --chain-name ${CHAIN_NAME} --base-fee ${BASE_FEE} --timestamp ${TIMESTAMP} +""" + +[tasks.node-script-new-key] +cwd = "./target/release" +script=""" +mkdir -p $KEYS_DIR + +./fendermint key gen --out-dir $KEYS_DIR --name $KEY_NAME; +chmod 600 ${PRIV_KEY_PATH} +""" + +[tasks.node-script-new-account] +cwd = "./target/release" +script=""" +./fendermint genesis --genesis-file ${GENESIS_FILE} add-account --public-key ${PUB_KEY_PATH} --balance ${BALANCE} +""" + + +[tasks.node-script-add-validator] +cwd = "./target/release" +script = """ +./fendermint genesis --genesis-file ${GENESIS_FILE} add-validator --public-key ${PUB_KEY_PATH} --power 1 +""" + +[tasks.node-script-new-gateway] +cwd = "./target/release" +script = """ +./fendermint genesis --genesis-file ${GENESIS_FILE} ipc gateway --subnet-id /r0 \ + --top-down-check-period 10 \ + --bottom-up-check-period 10 \ + --msg-fee 10 \ + --majority-percentage 67 +""" + +[tasks.node-script-export-keys] +cwd = "./target/release" +script = """ +./fendermint genesis --genesis-file ${GENESIS_FILE} into-tendermint --out ${CMT_DIR}/config/genesis.json + +./fendermint key into-tendermint --secret-key ${PRIV_KEY_PATH} --out ${CMT_DIR}/config/priv_validator_key.json +chmod 600 ${CMT_DIR}/config/priv_validator_key.json +""" \ No newline at end of file diff --git a/infra/scripts/testnet.toml b/infra/scripts/testnet.toml new file mode 100644 index 00000000..8cba2259 --- /dev/null +++ b/infra/scripts/testnet.toml @@ -0,0 +1,185 @@ +######################################################################################################################## +# Testnet node +######################################################################################################################## +[tasks.testnet] +dependencies = [ + "testnet-down", + "testnet-init", + "fendermint-deps", + "testnet-config", + "testnet-up" +] + +[tasks.testnet-up] +script = """ +if [ -z $GID ]; then GID=$(id -g); fi +if [ -z $UID ]; then UID=$(id -u); fi +export UID +export GID +export CMT_PERSISTENT_PEERS=`cat $BASE_DIR/peers` +export CHAIN_NAME=$CHAIN_NAME +export BASE_DIR=$BASE_DIR +./infra/run.sh start +""" + +[tasks.testnet-down] +dependencies = [ + "testnet-docker-compose-down", + "docker-network-rm", +] + +[tasks.testnet-docker-compose-down] +script = """ +export CMT_PERSISTENT_PEERS="UNDEFINED" +if [ -z $GID ]; then GID=$(id -g); fi +if [ -z $UID ]; then UID=$(id -u); fi +export UID +export GID +./infra/run.sh stop +""" + +[tasks.testnet-init] +dependencies = [ + "testnet-clear", + "testnet-network-create", + "cometbft-pull", + "testnet-mkdir", + "testnet-cometbft-init", +] + +[tasks.testnet-network-create] +env = { "NETWORK_NAME"="${NETWORK_NAME}"} +extend = "docker-network-create" + +[tasks.testnet-clear] +script=""" +echo clearing all IPC data +rm -rf ${BASE_DIR} +""" + +[tasks.testnet-mkdir] +script=""" +mkdir -p $BASE_DIR +mkdir -p $BASE_DIR/out + +for i in $(seq 0 3); do + mkdir -p $BASE_DIR/node${i} + mkdir -p $BASE_DIR/node${i}/fendermint + mkdir -p $BASE_DIR/node${i}/cometbft +done +""" + +[tasks.testnet-cometbft-init] +dependencies = ["testnet-cometbft-init-node0", "testnet-cometbft-init-node1", "testnet-cometbft-init-node2", "testnet-cometbft-init-node3"] + +[tasks.testnet-cometbft-init-node0] +extend = "cometbft-init" +env = { "CMD" = "init", "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/node0/cometbft", "CMT_CONTAINER_NAME" = "cometbft-node0", "FLAGS" = "-a STDOUT -a STDERR --rm"} + +[tasks.testnet-cometbft-init-node1] +extend = "cometbft-init" +env = { "CMD" = "init", "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/node1/cometbft", "CMT_CONTAINER_NAME" = "cometbft-node1", "FLAGS" = "-a STDOUT -a STDERR --rm" } + +[tasks.testnet-cometbft-init-node2] +extend = "cometbft-init" +env = { "CMD" = "init", "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/node2/cometbft", "CMT_CONTAINER_NAME" = "cometbft-node2", "FLAGS" = "-a STDOUT -a STDERR --rm" } + +[tasks.testnet-cometbft-init-node3] +extend = "cometbft-init" +env = { "CMD" = "init", "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/node3/cometbft", "CMT_CONTAINER_NAME" = "cometbft-node3", "FLAGS" = "-a STDOUT -a STDERR --rm" } + +[tasks.testnet-config] +dependencies = [ + "testnet-script-new-genesis", + "testnet-script-add-peers", + "testnet-script-new-key", + "testnet-script-new-account", + "testnet-script-new-gateway", + "testnet-script-share-genesis" +] + +[tasks.testnet-script-new-genesis] +cwd = "./target/release" +script = """ +./fendermint genesis --genesis-file $BASE_DIR/genesis.json \ + new --chain-name ${CHAIN_NAME} --base-fee ${BASE_FEE} --timestamp ${TIMESTAMP} + +cat $BASE_DIR/genesis.json +""" + +[tasks.testnet-script-new-key] +cwd = "./target/release" +script=""" +for i in $(seq 0 3); do + mkdir -p $BASE_DIR/node${i}/fendermint/keys + ./fendermint key gen --out-dir $BASE_DIR/node${i}/fendermint/keys --name validator${i}_key +done +""" + +[tasks.testnet-script-new-account] +cwd = "./target/release" +script=""" +for i in $(seq 0 3); do +./fendermint genesis --genesis-file $BASE_DIR/genesis.json add-account \ + --public-key $BASE_DIR/node${i}/fendermint/keys/validator${i}_key.pk --balance ${BALANCE} +done +""" + +[tasks.testnet-script-add-peers] +cwd = "./target/release" +script=""" +for i in $(seq 0 3); do + ./fendermint key add-peer \ + --node-key-file $BASE_DIR/node${i}/cometbft/config/node_key.json \ + --network-addr 192.167.10.$((${i}+2)):26656 \ + --local-peers-file $BASE_DIR/peers +done + +unset CMT_PERSISTENT_PEERS +export CMT_PERSISTENT_PEERS=`cat $BASE_DIR/peers` +echo Persistent peers: $CMT_PERSISTENT_PEERS + +for i in $(seq 0 3); do + sed -i'bak' "s/persistent_peers = \\"\\"/persistent_peers = \\"$CMT_PERSISTENT_PEERS\\"/" $BASE_DIR/node${i}/cometbft/config/config.toml +done +""" + +[tasks.testnet-script-new-gateway] +cwd = "./target/release" +script = """ +for i in $(seq 0 3); do + ./fendermint genesis \ + --genesis-file $BASE_DIR/genesis.json add-validator \ + --public-key $BASE_DIR/node${i}/fendermint/keys/validator${i}_key.pk \ + --power 1 +done + +./fendermint genesis --genesis-file $BASE_DIR/genesis.json ipc gateway \ + --subnet-id /r0 \ + --top-down-check-period 10 \ + --bottom-up-check-period 10 \ + --msg-fee 10 \ + --majority-percentage 67 \ + --min-collateral 1 + +./fendermint \ + genesis --genesis-file $BASE_DIR/genesis.json \ + into-tendermint --out $BASE_DIR/out/genesis.json + +for i in $(seq 0 3); do + ./fendermint key into-tendermint \ + --secret-key $BASE_DIR/node${i}/fendermint/keys/validator${i}_key.sk \ + --out $BASE_DIR/node${i}/cometbft/config/priv_validator_key.json +done + +echo "GENESIS:" +cat $BASE_DIR/genesis.json +""" + +[tasks.testnet-script-share-genesis] +cwd = "./target/release" +script = """ +for i in $(seq 0 3); do + cp $BASE_DIR/out/genesis.json $BASE_DIR/node${i}/cometbft/config/genesis.json +done +"""