Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: devnet for regen-ledger #2224

Open
wants to merge 1 commit into
base: robert/cosmos-sdk-047
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,8 @@ dist/
.localnet

completions

## Devnet
# Ignore everything in the nodes/ directory
scripts/devnet/shared
/scripts/devnet/.env
24 changes: 24 additions & 0 deletions scripts/devnet/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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

# Copy the setup scripts into the container
COPY setup-scripts/ ${BASE_PATH}/setup-scripts/
RUN chmod -R +x ${BASE_PATH}/setup-scripts/
89 changes: 89 additions & 0 deletions scripts/devnet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# 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 ..."
```
75 changes: 75 additions & 0 deletions scripts/devnet/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
version: '3.8'

services:
regen-node1:
build:
context: .
dockerfile: Dockerfile
container_name: regen-node1
environment:
- NODE_NAME=regen-node1
- REGEN_NODE1_VALIDATOR_ADDRESS=${REGEN_NODE1_VALIDATOR_ADDRESS}
- REGEN_NODE1_VALIDATOR_MNEMONIC=${REGEN_NODE1_VALIDATOR_MNEMONIC}
- REGEN_NODE2_VALIDATOR_ADDRESS=${REGEN_NODE2_VALIDATOR_ADDRESS}
- REGEN_NODE2_VALIDATOR_MNEMONIC=${REGEN_NODE2_VALIDATOR_MNEMONIC}
- REGEN_NODE3_VALIDATOR_ADDRESS=${REGEN_NODE3_VALIDATOR_ADDRESS}
- REGEN_NODE3_VALIDATOR_MNEMONIC=${REGEN_NODE3_VALIDATOR_MNEMONIC}
volumes:
- ./shared:/mnt/nvme/shared
- ./entrypoint.sh:/entrypoint.sh
ports:
- "26656:26656" # P2P Port
- "26657:26657" # RPC Port
entrypoint: ["/bin/bash", "/entrypoint.sh"]
networks:
- regen-network

regen-node2:
build:
context: .
dockerfile: Dockerfile
container_name: regen-node2
environment:
- NODE_NAME=regen-node2
- REGEN_NODE1_VALIDATOR_ADDRESS=${REGEN_NODE1_VALIDATOR_ADDRESS}
- REGEN_NODE1_VALIDATOR_MNEMONIC=${REGEN_NODE1_VALIDATOR_MNEMONIC}
- REGEN_NODE2_VALIDATOR_ADDRESS=${REGEN_NODE2_VALIDATOR_ADDRESS}
- REGEN_NODE2_VALIDATOR_MNEMONIC=${REGEN_NODE2_VALIDATOR_MNEMONIC}
- REGEN_NODE3_VALIDATOR_ADDRESS=${REGEN_NODE3_VALIDATOR_ADDRESS}
- REGEN_NODE3_VALIDATOR_MNEMONIC=${REGEN_NODE3_VALIDATOR_MNEMONIC}
volumes:
- ./shared:/mnt/nvme/shared
- ./entrypoint.sh:/entrypoint.sh
ports:
- "26658:26656" # P2P Port
- "26659:26657" # RPC Port
entrypoint: ["/bin/bash", "/entrypoint.sh"]
networks:
- regen-network

regen-node3:
build:
context: .
dockerfile: Dockerfile
container_name: regen-node3
environment:
- NODE_NAME=regen-node3
- REGEN_NODE1_VALIDATOR_ADDRESS=${REGEN_NODE1_VALIDATOR_ADDRESS}
- REGEN_NODE1_VALIDATOR_MNEMONIC=${REGEN_NODE1_VALIDATOR_MNEMONIC}
- REGEN_NODE2_VALIDATOR_ADDRESS=${REGEN_NODE2_VALIDATOR_ADDRESS}
- REGEN_NODE2_VALIDATOR_MNEMONIC=${REGEN_NODE2_VALIDATOR_MNEMONIC}
- REGEN_NODE3_VALIDATOR_ADDRESS=${REGEN_NODE3_VALIDATOR_ADDRESS}
- REGEN_NODE3_VALIDATOR_MNEMONIC=${REGEN_NODE3_VALIDATOR_MNEMONIC}
volumes:
- ./shared:/mnt/nvme/shared
- ./entrypoint.sh:/entrypoint.sh
ports:
- "26660:26656" # P2P Port
- "26661:26657" # RPC Port
entrypoint: ["/bin/bash", "/entrypoint.sh"]
networks:
- regen-network

networks:
regen-network:
driver: bridge
152 changes: 152 additions & 0 deletions scripts/devnet/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/bin/bash
# Entry script to initialize and start the Regen node with persistent peers

set -e

# Set the base path for the node's home directory
BASE_PATH=${BASE_PATH:-/mnt/nvme}
HOME_DIR=${BASE_PATH}/.regen

# Create a directory for shared Node IDs and genesis files
SHARED_DIR=${BASE_PATH}/shared
mkdir -p "$SHARED_DIR/gentxs"

# List of all node names
NODE_NAMES=("regen-node1" "regen-node2" "regen-node3")

# Retrieve environment variables for validator address and mnemonic
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}"

# Add debugging statements
echo "[$NODE_NAME] NODE_ENV_NAME: $NODE_ENV_NAME"
echo "[$NODE_NAME] VALIDATOR_MNEMONIC_VAR: $VALIDATOR_MNEMONIC_VAR"
echo "[$NODE_NAME] VALIDATOR_ADDRESS_VAR: $VALIDATOR_ADDRESS_VAR"
echo "[$NODE_NAME] VALIDATOR_MNEMONIC: $VALIDATOR_MNEMONIC"
echo "[$NODE_NAME] VALIDATOR_ADDRESS: $VALIDATOR_ADDRESS"

# Ensure environment variables are set
if [ -z "$VALIDATOR_MNEMONIC" ] || [ -z "$VALIDATOR_ADDRESS" ]; then
echo "[$NODE_NAME] ERROR: Validator mnemonic and address must be set via environment variables."
exit 1
fi

COMPLETION_FILE="$SHARED_DIR/regen-node1_genesis_init_done"

# **Regen-node1 initializes the genesis.json**
if [ "$NODE_NAME" == "regen-node1" ]; then
echo "[$NODE_NAME] Initializing the Regen node..."
regen init "$NODE_NAME" --chain-id regen-devnet --home "$HOME_DIR"

# **Update the staking bond_denom to uregen**
sed -i 's/"bond_denom": "stake"/"bond_denom": "uregen"/' "$HOME_DIR/config/genesis.json"

# **Add all validator accounts to the genesis file**
echo "[$NODE_NAME] Adding validator accounts to genesis..."
for NODE in "${NODE_NAMES[@]}"; do
NODE_LOOP_ENV_NAME=$(echo "${NODE^^}" | tr '-' '_')
ADDRESS_VAR="${NODE_LOOP_ENV_NAME}_VALIDATOR_ADDRESS"
ADDRESS="${!ADDRESS_VAR}"
echo "[$NODE_NAME] Processing $NODE: ADDRESS_VAR=$ADDRESS_VAR, ADDRESS=$ADDRESS"

if [ -z "$ADDRESS" ]; then
echo "[$NODE_NAME] ERROR: Address for $NODE is not set."
exit 1
fi
# Use the address directly
regen add-genesis-account "$ADDRESS" 100000000uregen --home "$HOME_DIR"
done

# **Copy the initial genesis.json to the shared directory**
cp "$HOME_DIR/config/genesis.json" "$SHARED_DIR/genesis.json"
touch "$COMPLETION_FILE"

else
# **Other nodes wait for genesis initialization by regen-node1**
while [ ! -f "$COMPLETION_FILE" ]; do
echo "[$NODE_NAME] Waiting for regen-node1 to initialize genesis..."
sleep 2
done

echo "[$NODE_NAME] Copying genesis.json from regen-node1..."
regen init "$NODE_NAME" --chain-id regen-devnet --home "$HOME_DIR"
cp "$SHARED_DIR/genesis.json" "$HOME_DIR/config/genesis.json"
fi

# **Import the validator key using the mnemonic**
echo "[$NODE_NAME] Importing validator key..."
echo "$VALIDATOR_MNEMONIC" | regen keys add my_validator --recover --keyring-backend test --home "$HOME_DIR"

# **Generate the genesis transaction to stake tokens**
echo "[$NODE_NAME] Generating gentx..."
regen gentx my_validator 50000000uregen --keyring-backend test --chain-id regen-devnet --home "$HOME_DIR"

# **Copy the gentx to the shared directory**
echo "[$NODE_NAME] Copying gentx to shared directory..."
cp "$HOME_DIR/config/gentx/"*.json "$SHARED_DIR/gentxs/${NODE_NAME}_gentx.json"

# **Wait for all gentx files from all nodes**
for NODE in "${NODE_NAMES[@]}"; do
while [ ! -f "$SHARED_DIR/gentxs/${NODE}_gentx.json" ]; do
echo "[$NODE_NAME] Waiting for gentx file from $NODE..."
sleep 2
done
done

# **Regen-node1 collects all gentx files and creates the final genesis.json**
COMPLETION_FILE_GENTX="$SHARED_DIR/regen-node1_gentx_collect_done"
if [ "$NODE_NAME" == "regen-node1" ]; then
echo "[$NODE_NAME] Collecting all genesis transactions..."
regen collect-gentxs --gentx-dir "$SHARED_DIR/gentxs" --home "$HOME_DIR"

echo "[$NODE_NAME] Validating the final genesis file..."
regen validate-genesis --home "$HOME_DIR"

cp "$HOME_DIR/config/genesis.json" "$SHARED_DIR/genesis.json"
touch "$COMPLETION_FILE_GENTX"
else
# **Other nodes wait for the final genesis.json**
while [ ! -f "$COMPLETION_FILE_GENTX" ]; do
echo "[$NODE_NAME] Waiting for regen-node1 to collect and finalize gentx..."
sleep 2
done

cp "$SHARED_DIR/genesis.json" "$HOME_DIR/config/genesis.json"
regen validate-genesis --home "$HOME_DIR"
fi

# **Retrieve Node ID and save it to shared directory**
NODE_ID=$(regen tendermint show-node-id --home "$HOME_DIR")
echo "[$NODE_NAME] My Node ID: $NODE_ID"
echo "$NODE_ID" > "$SHARED_DIR/${NODE_NAME}_id"

# **Wait for all Node IDs**
for NODE in "${NODE_NAMES[@]}"; do
while [ ! -f "$SHARED_DIR/${NODE}_id" ]; do
echo "[$NODE_NAME] Waiting for Node ID from $NODE..."
sleep 2
done
done

# **Configure persistent peers**
PERSISTENT_PEERS=""
for NODE in "${NODE_NAMES[@]}"; do
if [ "$NODE" != "$NODE_NAME" ]; then
PEER_ID=$(cat "$SHARED_DIR/${NODE}_id")
PERSISTENT_PEERS+="$PEER_ID@$NODE:26656,"
fi
done

PERSISTENT_PEERS=${PERSISTENT_PEERS%,}
sed -i "s/^persistent_peers = .*/persistent_peers = \"$PERSISTENT_PEERS\"/" "$HOME_DIR/config/config.toml"
sed -i 's/^addr_book_strict *=.*/addr_book_strict = false/' "$HOME_DIR/config/config.toml"


# **Start the node**
echo "[$NODE_NAME] Starting the Regen node..."
exec regen start --home "$HOME_DIR" --minimum-gas-prices="0.025uregen"
35 changes: 35 additions & 0 deletions scripts/devnet/setup-scripts/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Makefile for managing Regen DevNet Node operations

.PHONY: init config config-core config-node start all clean reset

# Paths and variables
BASE_PATH := /mnt/nvme
HOME_DIR := $(BASE_PATH)/.regen
MONIKER ?= regen-devnet-node

# Execute scripts for initializing, configuring, and starting the node
init:
@echo "Initializing Regen node with moniker $(MONIKER)..."
@./initchain.bash $(MONIKER)

config-node:
@echo "Configuring Regen node with persistent peers: $(REGEN_P2P_PERSISTENT_PEERS)..."
@REGEN_P2P_PERSISTENT_PEERS=$(REGEN_P2P_PERSISTENT_PEERS) ./setconfig-node.bash

start:
@echo "Starting Regen node..."
@./startnode.bash $(BASE_PATH)

# Combine all steps into a single make command
all: init config-node start

# Clean up data, logs, and temporary files
clean:
@echo "Cleaning up temporary files..."
@find . -name "*.log" -type f -delete
@find . -name "*.tmp" -type f -delete

# Reset everything to start from scratch
reset:
@echo "Removing all configurations and data to start from scratch..."
@rm -rf $(HOME_DIR)
Loading
Loading