-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: devnet for regen-ledger (#2224)
Co-authored-by: Pablo Estrada <[email protected]>
- Loading branch information
Showing
6 changed files
with
515 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Use Go 1.23 as the base image for building and setting up the environment | ||
FROM golang:1.23 as builder | ||
|
||
# Define a build argument for the base path | ||
ARG BASE_PATH=/mnt/nvme | ||
|
||
# Set the working directory using the base path | ||
WORKDIR ${BASE_PATH} | ||
|
||
# Update package lists and install dependencies (jq) | ||
RUN apt-get update && apt-get install -y jq | ||
|
||
# Clone the regen repository and checkout the specific version (this can be parameterized) | ||
ARG REGEN_VERSION=v5.1.4 | ||
RUN git clone https://github.com/regen-network/regen-ledger.git && \ | ||
cd regen-ledger && \ | ||
git checkout ${REGEN_VERSION} | ||
|
||
# Build the regen binary using the Makefile | ||
RUN cd ${BASE_PATH}/regen-ledger && make build && cp build/regen /usr/local/bin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# Regen Network DevNet Setup Guide | ||
|
||
This README provides step-by-step instructions for setting up a multi-node Regen Network development network (DevNet) using Docker Compose. This guide aims to help developers quickly spin up a local Regen Network for testing and development purposes. | ||
|
||
|
||
## Prerequisites | ||
Before starting, ensure you have the following installed on your machine: | ||
|
||
* **Docker:** Download and install Docker | ||
* **Docker Compose:** Download and install Docker Compose | ||
* **Git:** Download and install Git | ||
* **jq:** Command-line JSON processor (Install Guide) | ||
|
||
## Usage | ||
```shell | ||
chmod +x setup.sh | ||
./setup.sh | ||
``` | ||
**Note:** The script will clean up any existing data to ensure a fresh start. | ||
|
||
## Interacting with the network | ||
Once the nodes are running, you can interact with them using regen CLI commands. | ||
|
||
For example, to query the status of the first node: | ||
|
||
```shell | ||
regen status --node http://localhost:26657 | ||
``` | ||
|
||
Replace 26657 with the appropriate RPC port if interacting with other nodes (26659, 26661). | ||
|
||
|
||
## File Structure | ||
```text | ||
├── Dockerfile # Defines the Docker image used for the Regen nodes. | ||
├── docker-compose.yml # Docker Compose configuration for the three nodes. | ||
├── entrypoint.sh # Entry script executed inside each Docker container to initialize and start the node. | ||
├── setup.sh # Script to generate keys, write environment variables, and start the network. | ||
└── shared/ # Shared directory for nodes to exchange files (e.g., genesis files, gentxs). | ||
``` | ||
|
||
## Scripts Overview | ||
### `setup.sh` | ||
This script automates the initial setup: | ||
|
||
1. **Generates Validator Keys:** Creates keys for each node and extracts their addresses and mnemonics. | ||
2. **Writes .env File:** Stores the addresses and mnemonics as environment variables. | ||
3. **Starts Docker Compose:** Brings up the network with all three nodes. | ||
|
||
### `entrypoint.sh` | ||
Executed inside each Docker container, this script: | ||
|
||
1. Initializes the node if it's not already initialized. | ||
2. Imports the validator key using the mnemonic. | ||
3. Generates the gentx file. | ||
4. Coordinates with other nodes to collect gentx files and finalize the genesis file. | ||
5. Configures persistent peers and starts the node. | ||
|
||
#### Key Features: | ||
|
||
**Synchronization Mechanisms:** Ensures nodes wait for each other during initialization. | ||
|
||
### `docker-compose.yml` | ||
Defines the Docker services for the three nodes. | ||
|
||
Services: | ||
* regen-node1 | ||
* regen-node2 | ||
* regen-node3 | ||
|
||
|
||
#### Configurations: | ||
|
||
* **Environment Variables:** Loaded from the .env file. | ||
* **Ports:** Exposes RPC and P2P ports for each node. | ||
* **Volumes:** Mounts the shared directory and entrypoint.sh script. | ||
* **Networks:** All nodes are on the same Docker network for internal communication. | ||
* **.env File**: Automatically generated by setup.sh, this file contains validator addresses and mnemonics for all nodes. | ||
Example Contents: | ||
|
||
``` | ||
REGEN_NODE1_VALIDATOR_ADDRESS=regen1... | ||
REGEN_NODE1_VALIDATOR_MNEMONIC="mnemonic words ..." | ||
REGEN_NODE2_VALIDATOR_ADDRESS=regen1... | ||
REGEN_NODE2_VALIDATOR_MNEMONIC="mnemonic words ..." | ||
REGEN_NODE3_VALIDATOR_ADDRESS=regen1... | ||
REGEN_NODE3_VALIDATOR_MNEMONIC="mnemonic words ..." | ||
``` | ||
|
||
# State Initialization | ||
For state initialization we recommend using a `state_init.sh` script | ||
written by the developer. This script should contain a list of txs using | ||
the regen cli to initialize the desired state before the usage of the tesnet. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
#!/bin/bash | ||
set -e | ||
|
||
# Constants | ||
BASE_PATH=${BASE_PATH:-/mnt/nvme} | ||
HOME_DIR=${BASE_PATH}/.regen | ||
SHARED_DIR=${BASE_PATH}/shared | ||
GENTX_DIR="$SHARED_DIR/gentxs" | ||
INITIAL_GENESIS_READY="$SHARED_DIR/initial_genesis_ready" | ||
FINAL_GENESIS_READY="$SHARED_DIR/final_genesis_ready" | ||
CHAIN_ID="regen-devnet" | ||
|
||
# Colors and Emojis | ||
GREEN='\033[0;32m' | ||
NC='\033[0m' | ||
INFO="${GREEN}ℹ️${NC}" | ||
SUCCESS="${GREEN}✅${NC}" | ||
WAIT="${GREEN}⏳${NC}" | ||
|
||
# Helper: Print message with emoji | ||
log() { echo -e "${1} ${2}"; } | ||
|
||
# Ensure shared directories exist | ||
mkdir -p "$GENTX_DIR" | ||
|
||
# Determine the number of nodes | ||
NODE_COUNT="${NODE_COUNT:-3}" | ||
NODE_NAMES=($(for i in $(seq 1 "$NODE_COUNT"); do echo "regen-node$i"; done)) | ||
|
||
# Fetch ports from environment variables | ||
P2P_PORT=${P2P_PORT:-26656} | ||
RPC_PORT=${RPC_PORT:-26657} | ||
|
||
configure_rpc_and_p2p() { | ||
CONFIG_FILE="$HOME_DIR/config/config.toml" | ||
APP_FILE="$HOME_DIR/config/app.toml" | ||
|
||
log "$INFO" "🔍 Verifying configuration of RPC, P2P, and gRPC for ${NODE_NAME}..." | ||
|
||
# Configure RPC in the [rpc] section of config.toml | ||
if [ -f "$CONFIG_FILE" ]; then | ||
log "$INFO" "⚙️ Configuring RPC and P2P in $CONFIG_FILE..." | ||
|
||
# Update RPC address only in the [rpc] section | ||
sed -i "/\[rpc\]/,/^\[.*\]/ s|^laddr *=.*|laddr = \"tcp://0.0.0.0:$RPC_PORT\"|" "$CONFIG_FILE" | ||
|
||
# Update P2P address only in the [p2p] section | ||
sed -i "/\[p2p\]/,/^\[.*\]/ s|^laddr *=.*|laddr = \"tcp://0.0.0.0:$P2P_PORT\"|" "$CONFIG_FILE" | ||
sed -i "/\[p2p\]/,/^\[.*\]/ s|^external_address *=.*|external_address = \"tcp://0.0.0.0:$P2P_PORT\"|" "$CONFIG_FILE" | ||
|
||
log "$SUCCESS" "✅ Configured RPC on $RPC_PORT and P2P on $P2P_PORT in $CONFIG_FILE." | ||
else | ||
log "$INFO" "⚠️ $CONFIG_FILE not found. Skipping P2P and RPC configuration." | ||
fi | ||
|
||
# Configure gRPC and API in app.toml | ||
if [ -f "$APP_FILE" ]; then | ||
log "$INFO" "⚙️ Configuring gRPC and API in $APP_FILE..." | ||
|
||
# Update gRPC address in the [grpc] section | ||
sed -i "/\[grpc\]/,/^\[.*\]/ s|^address *=.*|address = \"localhost:$GRPC_PORT\"|" "$APP_FILE" | ||
|
||
|
||
log "$SUCCESS" "✅ Configured gRPC on $GRPC_PORT and API enabled in $APP_FILE." | ||
else | ||
log "$INFO" "⚠️ $APP_FILE not found. Skipping gRPC and API configuration." | ||
fi | ||
} | ||
|
||
|
||
fetch_environment_variables() { | ||
NODE_ENV_NAME=$(echo "${NODE_NAME^^}" | tr '-' '_') | ||
VALIDATOR_MNEMONIC_VAR="${NODE_ENV_NAME}_VALIDATOR_MNEMONIC" | ||
VALIDATOR_ADDRESS_VAR="${NODE_ENV_NAME}_VALIDATOR_ADDRESS" | ||
|
||
VALIDATOR_MNEMONIC="${!VALIDATOR_MNEMONIC_VAR}" | ||
VALIDATOR_ADDRESS="${!VALIDATOR_ADDRESS_VAR}" | ||
|
||
if [ -z "$VALIDATOR_MNEMONIC" ] || [ -z "$VALIDATOR_ADDRESS" ]; then | ||
log "$WAIT" "Mnemonic or address not found for ${NODE_NAME}!" | ||
exit 1 | ||
fi | ||
log "$SUCCESS" "Fetched mnemonic and address for ${NODE_NAME}." | ||
} | ||
|
||
initialize_node() { | ||
if [ ! -f "$HOME_DIR/config/node_key.json" ]; then | ||
regen init "$NODE_NAME" --chain-id "$CHAIN_ID" --home "$HOME_DIR" | ||
log "$SUCCESS" "Initialized ${NODE_NAME}." | ||
fi | ||
} | ||
|
||
save_node_id() { | ||
NODE_ID=$(regen tendermint show-node-id --home "$HOME_DIR") | ||
echo "$NODE_ID" > "$SHARED_DIR/${NODE_NAME}_id" | ||
log "$SUCCESS" "Saved Node ID for ${NODE_NAME}: $NODE_ID" | ||
} | ||
|
||
add_validator_accounts_to_genesis() { | ||
log "$INFO" "Adding validator accounts to genesis..." | ||
for NODE in "${NODE_NAMES[@]}"; do | ||
NODE_ENV=$(echo "${NODE^^}" | tr '-' '_') | ||
ADDR_VAR="${NODE_ENV}_VALIDATOR_ADDRESS" | ||
ADDRESS="${!ADDR_VAR}" | ||
log "$INFO" "Adding ${NODE}'s address: ${ADDRESS}" | ||
regen add-genesis-account "$ADDRESS" 100000000uregen --home "$HOME_DIR" | ||
done | ||
log "$SUCCESS" "All validator accounts added to genesis." | ||
} | ||
|
||
generate_gentx() { | ||
log "$INFO" "Generating gentx for ${NODE_NAME}..." | ||
echo "$VALIDATOR_MNEMONIC" | regen keys add my_validator --recover --keyring-backend test --home "$HOME_DIR" | ||
regen gentx my_validator 50000000uregen --keyring-backend test --chain-id "$CHAIN_ID" --home "$HOME_DIR" | ||
cp "$HOME_DIR/config/gentx/"*.json "$GENTX_DIR/${NODE_NAME}_gentx.json" | ||
log "$SUCCESS" "Generated gentx for ${NODE_NAME}." | ||
} | ||
|
||
wait_for_gentx_files() { | ||
log "$INFO" "Waiting for all gentx files..." | ||
for NODE in "${NODE_NAMES[@]}"; do | ||
if [ "$NODE" != "$NODE_NAME" ]; then | ||
while [ ! -f "$GENTX_DIR/${NODE}_gentx.json" ]; do | ||
log "$WAIT" "Waiting for gentx from ${NODE}..." | ||
sleep 2 | ||
done | ||
log "$SUCCESS" "Received gentx from ${NODE}." | ||
fi | ||
done | ||
} | ||
|
||
wait_for_initial_genesis() { | ||
log "$INFO" "${NODE_NAME} waiting for initial genesis.json..." | ||
while [ ! -f "$INITIAL_GENESIS_READY" ]; do | ||
sleep 2 | ||
done | ||
cp "$SHARED_DIR/genesis.json" "$HOME_DIR/config/genesis.json" | ||
log "$SUCCESS" "Initial genesis.json received for ${NODE_NAME}." | ||
} | ||
|
||
wait_for_final_genesis() { | ||
log "$INFO" "Waiting for finalized genesis.json..." | ||
while [ ! -f "$FINAL_GENESIS_READY" ]; do | ||
sleep 2 | ||
done | ||
cp "$SHARED_DIR/genesis.json" "$HOME_DIR/config/genesis.json" | ||
log "$SUCCESS" "Finalized genesis.json received for ${NODE_NAME}." | ||
} | ||
|
||
collect_and_finalize_genesis() { | ||
log "$INFO" "Collecting and validating gentx files..." | ||
regen collect-gentxs --gentx-dir "$GENTX_DIR" --home "$HOME_DIR" | ||
regen validate-genesis --home "$HOME_DIR" | ||
cp "$HOME_DIR/config/genesis.json" "$SHARED_DIR/genesis.json" | ||
touch "$FINAL_GENESIS_READY" | ||
log "$SUCCESS" "Finalized genesis.json saved." | ||
} | ||
|
||
# Main Setup Logic | ||
log "$INFO" "Starting setup for ${NODE_NAME}..." | ||
|
||
|
||
fetch_environment_variables | ||
initialize_node | ||
save_node_id | ||
configure_rpc_and_p2p | ||
|
||
if [ "$NODE_NAME" == "regen-node1" ]; then | ||
jq '.app_state.staking.params.bond_denom = "uregen"' "$HOME_DIR/config/genesis.json" > "$HOME_DIR/config/genesis_tmp.json" | ||
mv "$HOME_DIR/config/genesis_tmp.json" "$HOME_DIR/config/genesis.json" | ||
log "$SUCCESS" "Modified genesis.json for ${NODE_NAME}." | ||
|
||
add_validator_accounts_to_genesis | ||
|
||
# Save initial genesis.json and notify other nodes | ||
cp "$HOME_DIR/config/genesis.json" "$SHARED_DIR/genesis.json" | ||
touch "$INITIAL_GENESIS_READY" | ||
log "$SUCCESS" "Initial genesis.json saved." | ||
|
||
wait_for_gentx_files | ||
collect_and_finalize_genesis | ||
else | ||
wait_for_initial_genesis | ||
generate_gentx | ||
wait_for_final_genesis | ||
fi | ||
|
||
|
||
log "$INFO" "Starting ${NODE_NAME}..." | ||
exec regen start --home "$HOME_DIR" --minimum-gas-prices="0.025uregen" |
Oops, something went wrong.