diff --git a/README.md b/README.md index 96a27bb1..24713b60 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ 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 @@ -10,8 +11,19 @@ Fendermint is an effort to implement [IPC with Tendermint Core](https://docs.goo Please have a look in the [docs](./docs/README.md) to see an overview of the project, how to run the components, and previous demos. ## IPC + Fendermint is built with support for [IPC](https://github.com/consensus-shipyard/ipc) by design. If you are looking to deploy the infrastructure Fendermint-based IPC subnet, refer to the [IPC main repo](https://github.com/consensus-shipyard/ipc), or have a look at the [IPC infrastructure docs](./docs/ipc.md). +## Building from source + +**Linux.** Install the following pre-requisites (instructions for Ubuntu): + +- Install system packages: `sudo apt install build-essential clang cmake pkg-config libssl-dev protobuf-compiler`. +- Install Rust. See [instructions](https://www.rust-lang.org/tools/install). +- Install cargo-make: `cargo install --force cargo-make`. +- Install Foundry. See [instructions](https://book.getfoundry.sh/getting-started/installation). +- Install Docker (if you intend to build Docker images). See [instructions](https://docs.docker.com/engine/install/ubuntu/). + ## Testing The following command runs unit and integration tests: @@ -28,7 +40,6 @@ while the next command builds docker images and runs an end-to-end test using th make e2e ``` - ## IPC Solidity Actors We generate Rust bindings for the Solidity actors we need to invoke from the [ipc-solidity-actors](https://github.com/consensus-shipyard/ipc-solidity-actors) library, some of which are deployed during the genesis process. The bindings live in [ipc_actors](./fendermint/vm/ipc_actors/), and are generated automatically during the build, or with the following command: @@ -47,7 +58,6 @@ To test whether the genesis process works, we can run the following unit test: cargo test --release -p fendermint_vm_interpreter load_genesis ``` - ## Pre-built Docker Image The CI build publishes a [Docker image](https://github.com/consensus-shipyard/fendermint/pkgs/container/fendermint) to Github Container Registry upon a successful build on the `main` branch. This is the same image as the one used in the End-to-End tests; it contains the built-in actor bundle and IPC Solidity actors, ready to be deployed during genesis. diff --git a/docs/ipc.md b/docs/ipc.md index ac4ed101..bfe1feea 100644 --- a/docs/ipc.md +++ b/docs/ipc.md @@ -49,7 +49,7 @@ Once a child subnet has been bootstrapped in its parent, its subnet actor has be In order to spawn a validator node in a child subnet, you need to run: ```bash cargo make --makefile infra/Makefile.toml \ - -e VALIDATOR_PRIV_KEY= \ + -e PRIVATE_KEY_PATH= \ -e SUBNET_ID= \ -e CMT_P2P_HOST_PORT= \ -e CMT_RPC_HOST_PORT= \ @@ -66,7 +66,7 @@ This command will run the infrastructure for a Fendermint validator in the child - `CMT_RPC_HOST_PORT` (optional): Specifies the listening port in the localhost for CometBFT's RPC. - `ETHAPI_HOST_PORT` (optional): Specifies the listening port in the localhost for the ETH RPC of the node. - `NODE_NAME` (optional): Name for the node deployment. Along with `CMT_P2P_HOST_PORT`, `CMT_RPC_HOST_PORT` and `ETHAPI_HOST_PORT`, these variables come really handy for the deployment of several validator nodes over the same system. -- `VALIDATOR_PRIV_KEY`: Path of the private key for your validator (it should be the corresponding one used to join the subnet in the parent). +- `PRIVATE_KEY_PATH`: Path of the hex encoded private key for your validator (it should be the corresponding one used to join the subnet in the parent). This can be exported from the `ipc-cli` or any other wallet like Metamask. - `SUBNET_ID`: SubnetID for the child subnet. - `BOOTSTRAPS`: Comma separated list of bootstraps (or seeds in CometBFT parlance). - `PARENT_ENDPOINT`: Public endpoint that the validator should use to connect to the parent. diff --git a/docs/localnet.md b/docs/localnet.md index c001623d..7b4310c8 100644 --- a/docs/localnet.md +++ b/docs/localnet.md @@ -1,16 +1,33 @@ # Local Testnets -Prerequisites: -```bash -make build docker-build -``` +Setting up a Fendermint local testnet is a way to get started quickly with IPC. + +This guide offers two flavours: + +- A single node deployment: useful for developing smart contracts and testing the APIs. +- A 4 node testnet: useful for testing consensus, checkpointing, and more. + +## Prerequisites + +On Linux (links and instructions for Ubuntu): + +- Install Docker. See [instructions](https://docs.docker.com/engine/install/ubuntu/). +- Install Rust. See [instructions](https://www.rust-lang.org/tools/install). +- Install cargo-make: `cargo install --force cargo-make`. + +## Docker images + +These commands will pull various Docker images from remote repositories, including `fendermint:latest`, by default. + +- To override which Fendermint Docker image to pull, set the `FM_DOCKER_TAG` env variable to the desired tag. +- To use a local Fendermint image, set the `FM_PULL_SKIP` env variable to some value, e.g. `FM_PULL_SKIP=true`. ## Single node deployment -To run IPC in the local rootnet just perform the following : +To run IPC in the local rootnet just perform the following: + ```bash cargo make --makefile ./infra/Makefile.toml testnode - ``` It will create three docker containers (cometbft, fendermint, and eth-api). @@ -21,13 +38,15 @@ cargo make --makefile ./infra/Makefile.toml testnode-down ``` ## Local 4-nodes deployment -To run IPC in the local rootnet with 4 nodes perform the following command : + +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 ``` @@ -35,27 +54,32 @@ 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: +The Ethereum API is accessible on the following endpoints 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: +And on the following endpoints 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 +## What's happening behind the scenes + +> For a 4-node deployment. + +The deployment process performs the following steps: + +- Remove all Docker containers, files, networks, etc. from any previous deployments. +- 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 them 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. diff --git a/infra/Makefile.toml b/infra/Makefile.toml index b7b7fc2f..02d9358b 100644 --- a/infra/Makefile.toml +++ b/infra/Makefile.toml @@ -3,10 +3,12 @@ extend = [ { path = "scripts/cometbft.toml" }, { path = "scripts/fendermint.toml" }, { path = "scripts/ethapi.toml" }, + { path = "scripts/genesis.toml"}, { path = "scripts/node.toml" }, { path = "scripts/testnet.toml" }, { path = "scripts/testnode.toml" }, - { path = "scripts/subnet.toml" } + { path = "scripts/subnet.toml" }, + { path = "scripts/bootstrap.toml" }, ] [config] @@ -14,7 +16,10 @@ default_to_workspace = false [env] # General network-specific parameters -SUBNET_ID = { value = "/r0", condition = { env_not_set = ["SUBNET_ID"] }} +SUBNET_ID = { value = "/r0", condition = { env_not_set = ["SUBNET_ID"] } } +# The network name is derived from the SUBNET_ID, replacing slashes with dashes, and dropping the first dash if any. +NETWORK_NAME = { script = ["echo $SUBNET_ID | sed -e 's/\\//-/g' -e 's/^-//1'"] } + 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"] }} @@ -29,38 +34,40 @@ NODE_NAME = { value = "ipc-node", condition = { env_not_set = ["NODE_NAME"] } } PARENT_ENDPOINT = { value = "https://api.calibration.node.glif.io/rpc/v1", condition = { env_not_set = ["PARENT_ENDPOINT"] } } PARENT_GATEWAY = { value = "0x56948d2CFaa2EF355B8C08Ac925202db212146D1", condition = { env_not_set = ["PARENT_GATEWAY"] } } PARENT_REGISTRY = { value = "0x6A4884D2B6A597792dC68014D4B7C117cca5668e", condition = { env_not_set = ["PARENT_REGISTRY"] } } -NETWORK_TYPE = { value = "test", condition = { env_not_set = ["NETWORK_TYPE"] } } -VALIDATOR_PRIV_KEY = { value = "~/.ipc/priv.key", condition = { env_not_set = ["VALIDATOR_PRIV_KEY"] } } +FM_NETWORK = { value = "test", condition = { env_not_set = ["FM_NETWORK"] } } TOPDOWN_CHAIN_HEAD_DELAY = { value = "10", condition = { env_not_set = ["TOPDOWN_CHAIN_HEAD_DELAY"] } } # Comma-separated list of bootstrap nodes to be used by the CometBFT node. BOOTSTRAPS = { value = "", condition = { env_not_set = ["BOOTSTRAPS"] } } +PRIVATE_KEY_PATH = { value = "", condition = { env_not_set = ["PRIVATE_KEY_PATH"] } } # Deployment-related -BASE_DIR="${HOME}/.ipc/${SUBNET_ID}" -FM_DIR="${BASE_DIR}/fendermint" -CMT_DIR="${BASE_DIR}/cometbft" +BASE_DIR="${HOME}/.ipc/${NETWORK_NAME}" +FM_DIR="${BASE_DIR}/${NODE_NAME}/fendermint" +CMT_DIR="${BASE_DIR}/${NODE_NAME}/cometbft" -GENESIS_FILE="${FM_DIR}/genesis.json" -KEYS_DIR="${FM_DIR}/keys" +GENESIS_FILE="${BASE_DIR}/genesis.json" +KEYS_SUBDIR="keys" KEY_NAME="validator_key" -PUB_KEY_PATH="${KEYS_DIR}/${KEY_NAME}.pk" -PRIV_KEY_PATH="${KEYS_DIR}/${KEY_NAME}.sk" +PUB_KEY_PATH="${KEYS_SUBDIR}/${KEY_NAME}.pk" +PRIV_KEY_PATH="${KEYS_SUBDIR}/${KEY_NAME}.sk" -NETWORK_NAME = "${SUBNET_ID}" +COMETBFT_SUBDIR = "cometbft" 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" +FM_DOCKER_TAG = "latest" +FM_DOCKER_IMAGE = "fendermint:${FM_DOCKER_TAG}" +FM_REMOTE_DOCKER_IMAGE = "ghcr.io/consensus-shipyard/fendermint:${FM_DOCKER_TAG}" 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" # 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 = 30000 +CMT_WAIT_MILLIS = 20000 # Keep example logs to a minimum. VERBOSITY = "" diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index f7166e31..3cb19357 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -1,4 +1,20 @@ services: + fendermint-node: + container_name: fendermint-node${NODE_ID} + user: ${UID}:${GID} + image: "fendermint:latest" + environment: + - FM_DATA_DIR=/data/fendermint/data + - FM_CHAIN_NAME=$NETWORK_NAME + - TENDERMINT_RPC_URL=http://cometbft-node${NODE_ID}:26657 + - LOG_LEVEL=info + - FM_NETWORK=$FM_NETWORK + volumes: + - $BASE_DIR/node${NODE_ID}:/data + networks: + testnet: + ipv4_address: ${FMT_NODE_ADDR} + cometbft-node: container_name: cometbft-node${NODE_ID} user: ${UID}:${GID} @@ -22,20 +38,6 @@ services: 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=$SUBNET_ID - - 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} diff --git a/infra/scripts/bootstrap.toml b/infra/scripts/bootstrap.toml new file mode 100644 index 00000000..89ae3557 --- /dev/null +++ b/infra/scripts/bootstrap.toml @@ -0,0 +1,11 @@ +[tasks.bootstrap] +env = { "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/bootstrap/cometbft", "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}-bootstrap" } +run_task = "new-node" + +[tasks.bootstrap-id] +env = { "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}-bootstrap" } +run_task = "cometbft-node-id" + +[tasks.bootstrap-down] +env = { "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}-bootstrap" } +run_task = "node-down" \ No newline at end of file diff --git a/infra/scripts/fendermint.toml b/infra/scripts/fendermint.toml index 48fe887c..a37fd428 100644 --- a/infra/scripts/fendermint.toml +++ b/infra/scripts/fendermint.toml @@ -2,8 +2,15 @@ extend = "fendermint-run" env = { "ENTRY" = "fendermint", "CMD" = "run", "FLAGS" = "-d" } -[tasks.fendermint-run] +[tasks.fendermint-pull] +condition = { env_not_set = ["FM_PULL_SKIP"], fail_message = "Skipped pulling fendermint Docker image." } script = """ + docker pull ghcr.io/consensus-shipyard/fendermint:${FM_DOCKER_TAG} + docker tag ghcr.io/consensus-shipyard/fendermint:${FM_DOCKER_TAG} fendermint:${FM_DOCKER_TAG} +""" + +[tasks.fendermint-run] +script.main = """ docker run \ ${FLAGS} \ --name ${FM_CONTAINER_NAME} \ @@ -15,9 +22,11 @@ docker run \ --env FM_CHAIN_NAME=${NETWORK_NAME} \ --env TENDERMINT_RPC_URL=http://${CMT_CONTAINER_NAME}:26657 \ --env LOG_LEVEL=info \ + --env RUST_BACKTRACE=1 \ --entrypoint ${ENTRY} \ ${FM_DOCKER_IMAGE} \ - --network=${NETWORK_TYPE} ${CMD} + --network=${FM_NETWORK} \ + ${CMD} """ dependencies = ["docker-network-create", "fendermint-deps"] @@ -36,7 +45,7 @@ docker run \ --volume ${BASE_DIR}:/data \ --env FM_DATA_DIR=/data/fendermint/data \ --env FM_CHAIN_NAME=${NETWORK_NAME} \ - --env FM_IPC__SUBNET_ID=${NETWORK_NAME} \ + --env FM_IPC__SUBNET_ID=${SUBNET_ID} \ --env FM_IPC__TOPDOWN__CHAIN_HEAD_DELAY=${TOPDOWN_CHAIN_HEAD_DELAY} \ --env FM_IPC__TOPDOWN__PARENT_HTTP_ENDPOINT=${PARENT_ENDPOINT} \ --env FM_IPC__TOPDOWN__PARENT_REGISTRY=${PARENT_REGISTRY} \ @@ -49,13 +58,30 @@ docker run \ --env FM_TENDERMINT_RPC_URL=http://${CMT_CONTAINER_NAME}:26657 \ --env TENDERMINT_RPC_URL=http://${CMT_CONTAINER_NAME}:26657 \ --env LOG_LEVEL=info \ + --env RUST_BACKTRACE=1 \ --entrypoint ${ENTRY} \ ${FM_DOCKER_IMAGE} \ - --network=${NETWORK_TYPE} \ + --network=${FM_NETWORK} \ ${CMD} """ dependencies = ["docker-network-create", "fendermint-deps"] +[tasks.fendermint-tool] +script.main = """ +docker run \ + ${FLAGS} \ + --init \ + --user $(id -u) \ + --volume ${BASE_DIR}:/data \ + --env LOG_LEVEL=info \ + --env RUST_BACKTRACE=1 \ + --entrypoint ${ENTRY} \ + ${FM_DOCKER_IMAGE} \ + --network=${FM_NETWORK} \ + ${CMD} +""" +dependencies = ["fendermint-deps"] + [tasks.fendermint-deps] script = """ # Check if the image exists diff --git a/infra/scripts/genesis.toml b/infra/scripts/genesis.toml new file mode 100644 index 00000000..88798065 --- /dev/null +++ b/infra/scripts/genesis.toml @@ -0,0 +1,40 @@ +[tasks.genesis-new] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "genesis --genesis-file /data/genesis.json new --chain-name ${NETWORK_NAME} --base-fee ${BASE_FEE} --timestamp ${TIMESTAMP} --power-scale ${POWER_SCALE}" } + +## Takes: +## - KEYS_SUBDIR: directory under /data where to store the key. +## - KEY_NAME: name of the key. +[tasks.genesis-new-key] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "key gen --out-dir /data/${NODE_NAME}/${KEYS_SUBDIR} --name ${KEY_NAME}" } +script.pre = "mkdir -p ${BASE_DIR}/${NODE_NAME}/${KEYS_SUBDIR}" +script.post = "chmod 600 ${BASE_DIR}/${NODE_NAME}/${KEYS_SUBDIR}/${KEY_NAME}.sk" + +[tasks.genesis-new-accounts] +dependencies = ["genesis-new-account-f1", "genesis-new-account-eth"] + +[tasks.genesis-new-account-f1] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "genesis --genesis-file /data/genesis.json add-account --public-key /data/${NODE_NAME}/${PUB_KEY_PATH} --balance ${BALANCE}" } + +[tasks.genesis-new-account-eth] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "genesis --genesis-file /data/genesis.json add-account --kind ethereum --public-key /data/${NODE_NAME}/${PUB_KEY_PATH} --balance ${BALANCE}" } + +[tasks.genesis-add-validator] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "genesis --genesis-file /data/genesis.json add-validator --public-key /data/${NODE_NAME}/${PUB_KEY_PATH} --power 1" } + +[tasks.genesis-new-gateway] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = """genesis --genesis-file /data/genesis.json ipc gateway --subnet-id /r0 \ + --bottom-up-check-period 10 \ + --msg-fee 10 \ + --majority-percentage 67 \ + --min-collateral 1""" } + +[tasks.genesis-write] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "genesis --genesis-file /data/genesis.json into-tendermint --out /data/genesis.committed.json" } +script.post = "cp ${BASE_DIR}/genesis.committed.json ${CMT_DIR}/config/genesis.json" diff --git a/infra/scripts/node.toml b/infra/scripts/node.toml index 82a00140..91c46892 100644 --- a/infra/scripts/node.toml +++ b/infra/scripts/node.toml @@ -2,18 +2,6 @@ # Node helpers ######################################################################################################################## -[tasks.bootstrap] -env = { "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/bootstrap/cometbft", "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}-bootstrap" } -run_task = "new-node" - -[tasks.bootstrap-id] -env = { "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}-bootstrap" } -run_task = "cometbft-node-id" - -[tasks.bootstrap-down] -env = { "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}-bootstrap" } -run_task = "node-down" - [tasks.node-down] dependencies = [ "cometbft-stop", diff --git a/infra/scripts/subnet.toml b/infra/scripts/subnet.toml index 07cb3268..f7aede78 100644 --- a/infra/scripts/subnet.toml +++ b/infra/scripts/subnet.toml @@ -2,56 +2,67 @@ # Child subnet peer ######################################################################################################################## - -[tasks.child-validator] -env = {"BASE_DIR"="${HOME}/.ipc/${NODE_NAME}", "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/cometbft", "FM_DIR"="${BASE_DIR}/fendermint", "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}", "ETHAPI_CONTAINER_NAME" = "eth-${NODE_NAME}", "FM_CONTAINER_NAME"= "fendermint-${NODE_NAME}", "GENESIS_FILE"="${FM_DIR}/genesis.json" } - -run_task = "validator-run" - [tasks.child-validator-down] -env = {"BASE_DIR"="${HOME}/.ipc/${NODE_NAME}", "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/cometbft", "FM_DIR"="${BASE_DIR}/fendermint", "CMT_CONTAINER_NAME" = "cometbft-${NODE_NAME}", "ETHAPI_CONTAINER_NAME" = "eth-${NODE_NAME}", "FM_CONTAINER_NAME"= "fendermint-${NODE_NAME}", "GENESIS_FILE"="${FM_DIR}/genesis.json" } - run_task = "testnode-down" -[tasks.validator-run] +[tasks.child-validator] workspace = false dependencies = [ "testnode-down", + "fendermint-pull", "node-init", - "testnode-network-create", + "docker-network-create", "cometbft-init", "fendermint-deps", "subnet-config", "fendermint-start-ipc", "cometbft-start", "cometbft-wait", - "ethapi-start" + "ethapi-start", + "validator-report", ] -# Subnet validator -# ENV variable for where things are put. -# Merge everything and test [tasks.subnet-config] dependencies = [ - "subnet-genesis", - "subnet-fm-prepare", + "subnet-fetch-genesis", + "subnet-convert-eth-key", + "testnode-export-keys", + "genesis-write", ] +[tasks.subnet-convert-eth-key] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "key eth-to-fendermint --secret-key /data/${NODE_NAME}/${KEYS_SUBDIR}/eth.sk --name validator_key --out-dir /data/${NODE_NAME}/${KEYS_SUBDIR}" } +script.pre = "mkdir ${BASE_DIR}/${NODE_NAME}/${KEYS_SUBDIR}; cp ${PRIVATE_KEY_PATH} ${BASE_DIR}/${NODE_NAME}/keys/eth.sk" + +[tasks.subnet-fetch-genesis] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "genesis --genesis-file /data/genesis.json ipc from-parent --subnet-id ${SUBNET_ID} -p ${PARENT_ENDPOINT} --parent-gateway ${PARENT_GATEWAY} --parent-registry ${PARENT_REGISTRY} --base-fee ${BASE_FEE} --power-scale ${POWER_SCALE}" } + +[tasks.validator-report] +script = """cat << EOF +################################# +# # +# Subnet validator ready! 🚀 # +# # +################################# -[tasks.subnet-genesis] -cwd = "./target/release" -script = """ +Subnet ID: +\t${SUBNET_ID} -./fendermint --network=${NETWORK_TYPE} genesis --genesis-file ${GENESIS_FILE} ipc from-parent --subnet-id ${SUBNET_ID} -p ${PARENT_ENDPOINT} --parent-gateway ${PARENT_GATEWAY} --parent-registry ${PARENT_REGISTRY} --base-fee ${BASE_FEE} --power-scale ${POWER_SCALE} +Eth API: +\thttp://0.0.0.0:${ETHAPI_HOST_PORT} -""" +Chain ID: +\t$(curl -s --location --request POST 'http://localhost:8545/' --header 'Content-Type: application/json' --data-raw '{ "jsonrpc":"2.0", "method":"eth_chainId", "params":[], "id":1 }' | jq -r '.result' | xargs printf "%d") -[tasks.subnet-fm-prepare] -cwd = "./target/release" -script = """ +Fendermint API: +\thttp://localhost:26658 -./fendermint --network=${NETWORK_TYPE} genesis --genesis-file ${GENESIS_FILE} into-tendermint --out ${CMT_DIR}/config/genesis.json +CometBFT API: +\thttp://0.0.0.0:${CMT_RPC_HOST_PORT} -./fendermint --network=${NETWORK_TYPE} key into-tendermint --secret-key ${VALIDATOR_PRIV_KEY} --out ${CMT_DIR}/config/priv_validator_key.json -chmod 600 ${CMT_DIR}/config/priv_validator_key.json -""" +CometBFT P2P: +\thttp://0.0.0.0:${CMT_P2P_HOST_PORT} +EOF +""" \ No newline at end of file diff --git a/infra/scripts/testnet.toml b/infra/scripts/testnet.toml index c6d29b66..30096efd 100644 --- a/infra/scripts/testnet.toml +++ b/infra/scripts/testnet.toml @@ -6,7 +6,6 @@ dependencies = [ "testnet-down", "testnet-init", "fendermint-deps", - "testnet-config", "testnet-up" ] @@ -23,12 +22,6 @@ export BASE_DIR=$BASE_DIR """ [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 @@ -41,100 +34,74 @@ export GID [tasks.testnet-init] dependencies = [ "testnet-clear", - "testnet-network-create", + "fendermint-pull", + "docker-network-create", "cometbft-pull", "testnet-mkdir", - "testnet-cometbft-init", + "genesis-new", + "testnet-init-nodes", + "genesis-write", + "testnet-copy-genesis", + "testnet-setup-persistent-peers", ] -[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-init-nodes] +script_runner = "@duckscript" +script = """ +nodes = range 0 4 -[tasks.testnet-cometbft-init] -dependencies = ["testnet-cometbft-init-node0", "testnet-cometbft-init-node1", "testnet-cometbft-init-node2", "testnet-cometbft-init-node3"] +for i in ${nodes} + NUMBER = set ${i} + NODE_NAME = set "node${NUMBER}" -[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"} + mkdir -p ${BASE_DIR}/${NODE_NAME} + mkdir -p ${BASE_DIR}/${NODE_NAME}/fendermint + mkdir -p ${BASE_DIR}/${NODE_NAME}/cometbft -[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" } + set_env NODE_NAME ${NODE_NAME} + set_env NUMBER ${NUMBER} -[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" } + cm_run_task testnet-cometbft-init + cm_run_task genesis-new-key + cm_run_task genesis-new-accounts + cm_run_task genesis-add-validator -[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" -] + IP_LAST = calc ${NUMBER}+2 + NETWORK_ADDR = set "192.167.10.${IP_LAST}:26656" + set_env NETWORK_ADDR ${NETWORK_ADDR} + cm_run_task testnet-add-peer -[tasks.testnet-script-new-genesis] -cwd = "./target/release" -script = """ -./fendermint genesis --genesis-file $BASE_DIR/genesis.json \ - new --chain-name ${SUBNET_ID} --base-fee ${BASE_FEE} --timestamp ${TIMESTAMP} --power-scale ${POWER_SCALE} + cm_run_task testnode-export-keys +end -cat $BASE_DIR/genesis.json +release ${nodes} """ -[tasks.testnet-script-new-key] -cwd = "./target/release" +[tasks.testnet-clear] 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 +echo clearing all IPC data +rm -rf ${BASE_DIR} """ -[tasks.testnet-script-new-account] -cwd = "./target/release" +[tasks.testnet-mkdir] 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 +mkdir -p ${BASE_DIR} """ -[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 +[tasks.testnet-cometbft-init] +extend = "cometbft-init" +env = { "CMD" = "init", "NETWORK_NAME"="${NETWORK_NAME}", "CMT_DIR" = "${BASE_DIR}/${NODE_NAME}/cometbft", "CMT_CONTAINER_NAME" = "cometbft-node${NUMBER}", "FLAGS" = "-a STDOUT -a STDERR --rm"} +[tasks.testnet-add-peer] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = """key add-peer \ + --node-key-file /data/${NODE_NAME}/${COMETBFT_SUBDIR}/config/node_key.json \ + --network-addr ${NETWORK_ADDR} \ + --local-peers-file /data/peers \ +""" } + +[tasks.testnet-setup-persistent-peers] +script=""" unset CMT_PERSISTENT_PEERS export CMT_PERSISTENT_PEERS=`cat $BASE_DIR/peers` echo Persistent peers: $CMT_PERSISTENT_PEERS @@ -144,41 +111,9 @@ for i in $(seq 0 3); do 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 \ - --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" +[tasks.testnet-copy-genesis] script = """ for i in $(seq 0 3); do - cp $BASE_DIR/out/genesis.json $BASE_DIR/node${i}/cometbft/config/genesis.json + cp $BASE_DIR/genesis.committed.json $BASE_DIR/node${i}/cometbft/config/genesis.json done """ diff --git a/infra/scripts/testnode.toml b/infra/scripts/testnode.toml index 042697c9..8698a381 100644 --- a/infra/scripts/testnode.toml +++ b/infra/scripts/testnode.toml @@ -5,22 +5,19 @@ workspace = false dependencies = [ "testnode-down", + "fendermint-pull", "testnode-init", - "testnode-network-create", + "docker-network-create", "cometbft-init", "fendermint-deps", "testnode-config", "fendermint-start", "cometbft-start", "cometbft-wait", - "ethapi-start" + "ethapi-start", + "testnode-report", ] -[tasks.testnode-network-create] -env = { "NETWORK_NAME"="${NETWORK_NAME}"} -extend = "docker-network-create" - - [tasks.testnode-init] dependencies = [ "node-clear", @@ -58,57 +55,46 @@ run_task = { name = [ # the genesis file with necessary entities and cryptographic keys. [tasks.testnode-config] dependencies = [ - "testnode-script-new-genesis", - "testnode-script-new-key", - "testnode-script-new-account", - "testnode-script-add-validator", - "testnode-script-new-gateway", - "testnode-script-export-keys" + "genesis-new", + "genesis-new-key", + "genesis-new-accounts", + "genesis-add-validator", + "genesis-new-gateway", + "genesis-write", + "testnode-export-keys" ] -[tasks.testnode-script-new-genesis] -cwd = "./target/release" -script = """ -./fendermint genesis --genesis-file ${GENESIS_FILE} new --chain-name ${SUBNET_ID} --base-fee ${BASE_FEE} --timestamp ${TIMESTAMP} --power-scale ${POWER_SCALE} -""" +[tasks.testnode-export-keys] +extend = "fendermint-tool" +env = { "ENTRY" = "fendermint", "CMD" = "key into-tendermint --secret-key /data/${NODE_NAME}/${PRIV_KEY_PATH} --out /data/${NODE_NAME}/${COMETBFT_SUBDIR}/config/priv_validator_key.json" } +script.post = "chmod 600 ${BASE_DIR}/${NODE_NAME}/${COMETBFT_SUBDIR}/config/priv_validator_key.json" -[tasks.testnode-script-new-key] -cwd = "./target/release" -script=""" -mkdir -p $KEYS_DIR +[tasks.testnode-report] +script = """cat << EOF +############################ +# # +# Testnode ready! 🚀 # +# # +############################ -./fendermint key gen --out-dir $KEYS_DIR --name $KEY_NAME; -chmod 600 ${PRIV_KEY_PATH} -""" +Eth API: +\thttp://0.0.0.0:8545 -[tasks.testnode-script-new-account] -cwd = "./target/release" -script=""" -./fendermint genesis --genesis-file ${GENESIS_FILE} add-account --public-key ${PUB_KEY_PATH} --balance ${BALANCE} -""" +Accounts: +$(jq -r '.accounts[] | "\t\\(.meta.Account.owner): \\(.balance) coin units"' ${BASE_DIR}/genesis.json) +Private key (hex ready to import in MetaMask): +\t$(cat ${BASE_DIR}/${NODE_NAME}/${PRIV_KEY_PATH} | base64 -d | xxd -p -c 1000000) -[tasks.testnode-script-add-validator] -cwd = "./target/release" -script = """ -./fendermint genesis --genesis-file ${GENESIS_FILE} add-validator --public-key ${PUB_KEY_PATH} --power 1 -""" +Note: both accounts use the same private key @ ${BASE_DIR}/${PRIV_KEY_PATH} -[tasks.testnode-script-new-gateway] -cwd = "./target/release" -script = """ -./fendermint genesis --genesis-file ${GENESIS_FILE} ipc gateway --subnet-id /r0 \ - --bottom-up-check-period 10 \ - --msg-fee 10 \ - --majority-percentage 67 \ - --min-collateral 1 -""" +Chain ID: +\t$(curl -s --location --request POST 'http://localhost:8545/' --header 'Content-Type: application/json' --data-raw '{ "jsonrpc":"2.0", "method":"eth_chainId", "params":[], "id":1 }' | jq -r '.result' | xargs printf "%d") -[tasks.testnode-script-export-keys] -cwd = "./target/release" -script = """ -./fendermint genesis --genesis-file ${GENESIS_FILE} into-tendermint --out ${CMT_DIR}/config/genesis.json +Fendermint API: +\thttp://localhost:26658 -./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 +CometBFT API: +\thttp://0.0.0.0:26657 +EOF """ \ No newline at end of file