Last active
February 1, 2025 03:23
-
-
Save bufrr/0caa7b0bea2873264f83729b899a174e to your computer and use it in GitHub Desktop.
evmos multiple node deploy script
This file contains hidden or 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
#!/bin/bash | |
# Exit on error, undefined variables, and propagate pipeline failures | |
set -e | |
################################################################################ | |
# Configuration | |
################################################################################ | |
# Default values | |
CHAIN_ID="evmos_9002-1" | |
KEYRING="test" | |
KEYALGO="eth_secp256k1" | |
DENOM="aevmos" | |
NODES=4 | |
HOME_PREFIX="$HOME/.tmp-evmosd-multi" | |
LOGLEVEL="info" | |
# Token amounts (using readable format with exponents) | |
GENESIS_BALANCE="1000000000000000000000" # 1,000 EVMOS (1e21 aevmos) | |
GENTX_STAKE="1000000000000000000" # 1 EVMOS (1e18 aevmos) | |
# Check if evmosd is installed | |
if ! command -v evmosd &> /dev/null; then | |
echo "Error: evmosd is not installed. Please install it first." | |
exit 1 | |
fi | |
################################################################################ | |
# Helper Functions | |
################################################################################ | |
log() { | |
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | |
} | |
check_port_availability() { | |
local port=$1 | |
if lsof -i:${port} > /dev/null 2>&1; then | |
echo "Error: Port ${port} is already in use" | |
exit 1 | |
fi | |
} | |
################################################################################ | |
# Main Script | |
################################################################################ | |
# Detect OS for sed compatibility | |
if [[ "$OSTYPE" == "darwin"* ]]; then | |
# macOS | |
SED_INPLACE="sed -i ''" | |
else | |
# Linux and others | |
SED_INPLACE="sed -i" | |
fi | |
# 1. Clean up any old data | |
log "Removing old data under $HOME_PREFIX*" | |
rm -rf "${HOME_PREFIX}"* | |
# 2. Initialize each node | |
for (( i=0; i<${NODES}; i++ )); do | |
HOMEDIR="${HOME_PREFIX}${i}" | |
log "Initializing node${i} at ${HOMEDIR}" | |
# 2.1: evmosd init | |
evmosd init "node${i}" --chain-id="${CHAIN_ID}" --home "${HOMEDIR}" | |
# 2.2: Create validator key | |
evmosd keys add "validator${i}" \ | |
--keyring-backend="${KEYRING}" \ | |
--algo="${KEYALGO}" \ | |
--home "${HOMEDIR}" | |
done | |
# 3. Add genesis accounts | |
log "Adding genesis accounts to Node 0's genesis..." | |
for (( j=0; j<${NODES}; j++ )); do | |
VAL_ADDR="$(evmosd keys show "validator${j}" -a \ | |
--keyring-backend="${KEYRING}" \ | |
--home "${HOME_PREFIX}${j}")" | |
evmosd add-genesis-account "${VAL_ADDR}" \ | |
"${GENESIS_BALANCE}${DENOM}" \ | |
--home "${HOME_PREFIX}0" | |
done | |
# 4. Create gentx for each validator | |
log "Generating gentx for each validator..." | |
for (( i=0; i<${NODES}; i++ )); do | |
HOMEDIR="${HOME_PREFIX}${i}" | |
# Only copy Node 0's genesis to node i if i != 0 | |
if [[ $i -ne 0 ]]; then | |
cp "${HOME_PREFIX}0/config/genesis.json" "${HOMEDIR}/config/genesis.json" | |
fi | |
evmosd gentx "validator${i}" \ | |
"${GENTX_STAKE}${DENOM}" \ | |
--chain-id="${CHAIN_ID}" \ | |
--keyring-backend="${KEYRING}" \ | |
--home "${HOMEDIR}" | |
done | |
# 5. Collect all gentxs in Node 0 | |
log "Collecting gentxs in Node 0..." | |
for (( i=1; i<${NODES}; i++ )); do | |
cp "${HOME_PREFIX}${i}/config/gentx/"* "${HOME_PREFIX}0/config/gentx/" | |
done | |
evmosd collect-gentxs --home "${HOME_PREFIX}0" | |
# 6. Distribute final genesis to all nodes | |
log "Copying final genesis from Node 0 to all nodes..." | |
for (( i=1; i<${NODES}; i++ )); do | |
cp "${HOME_PREFIX}0/config/genesis.json" "${HOME_PREFIX}${i}/config/genesis.json" | |
done | |
# 7. Configure networking | |
log "Configuring ports and P2P for each node..." | |
NODE0_ID=$(evmosd tendermint show-node-id --home "${HOME_PREFIX}0") | |
for (( i=0; i<${NODES}; i++ )); do | |
HOMEDIR="${HOME_PREFIX}${i}" | |
# Port configuration | |
P2P_PORT=$((26656 + i*2)) | |
RPC_PORT=$((26657 + i*2)) | |
PROXY_APP_PORT=$((26658 + i*2)) | |
API_PORT=$((1317 + i*100)) | |
GRPC_PORT=$((9090 + i*100)) | |
GRPC_WEB_PORT=$((9092 + i*100)) | |
check_port_availability ${P2P_PORT} | |
check_port_availability ${RPC_PORT} | |
check_port_availability ${API_PORT} | |
check_port_availability ${GRPC_PORT} | |
check_port_availability ${GRPC_WEB_PORT} | |
# Configure config.toml | |
$SED_INPLACE \ | |
-e "s/^moniker *=.*/moniker = \"node${i}\"/" \ | |
-e "s/^proxy_app *=.*/proxy_app = \"tcp:\/\/127.0.0.1:${PROXY_APP_PORT}\"/" \ | |
-e "s/^laddr *=.*/laddr = \"tcp:\/\/0.0.0.0:${P2P_PORT}\"/" \ | |
-e "s/^rpc_laddr *=.*/rpc_laddr = \"tcp:\/\/127.0.0.1:${RPC_PORT}\"/" \ | |
-e "s/^allow_duplicate_ip *=.*/allow_duplicate_ip = true/" \ | |
-e "s/^#allow_duplicate_ip *=.*/allow_duplicate_ip = true/" \ | |
-e "s/^type *=.*/type = \"narwhal\"/" \ | |
"${HOMEDIR}/config/config.toml" | |
# Configure app.toml - Cross-platform compatible version | |
$SED_INPLACE \ | |
-e "/^\[api\]/,/^\[/s|^address *= *.*|address = \"tcp://0.0.0.0:${API_PORT}\"|" \ | |
"${HOMEDIR}/config/app.toml" | |
$SED_INPLACE \ | |
-e "/^\[grpc\]/,/^\[/s|^address *= *.*|address = \"0.0.0.0:${GRPC_PORT}\"|" \ | |
"${HOMEDIR}/config/app.toml" | |
$SED_INPLACE \ | |
-e "/^\[grpc-web\]/,/^\[/s|^address *= *.*|address = \"0.0.0.0:${GRPC_WEB_PORT}\"|" \ | |
"${HOMEDIR}/config/app.toml" | |
done | |
# Configure P2P networking | |
for (( i=1; i<${NODES}; i++ )); do | |
HOMEDIR="${HOME_PREFIX}${i}" | |
PEERS="${NODE0_ID}@127.0.0.1:26656" | |
$SED_INPLACE \ | |
-e "s/^persistent_peers *=.*/persistent_peers = \"${PEERS}\"/" \ | |
-e "s/^pex *=.*/pex = false/" \ | |
"${HOMEDIR}/config/config.toml" | |
done | |
# Node 0 configuration | |
$SED_INPLACE \ | |
-e "s/^persistent_peers *=.*/persistent_peers = \"\"/" \ | |
-e "s/^pex *=.*/pex = true/" \ | |
"${HOME_PREFIX}0/config/config.toml" | |
# Generate start scripts | |
SCRIPT_DIR="${HOME_PREFIX}/scripts" | |
mkdir -p "${SCRIPT_DIR}" | |
# Generate individual start scripts | |
for (( i=0; i<${NODES}; i++ )); do | |
START_SCRIPT="${SCRIPT_DIR}/start-node${i}.sh" | |
cat > "${START_SCRIPT}" << EOF | |
#!/bin/bash | |
evmosd start --log_level ${LOGLEVEL} \\ | |
--chain-id ${CHAIN_ID} \\ | |
--home ${HOME_PREFIX}${i} \\ | |
--p2p.laddr tcp://0.0.0.0:$((26656 + i*2)) \\ | |
--rpc.laddr tcp://127.0.0.1:$((26657 + i*2)) | |
EOF | |
chmod +x "${START_SCRIPT}" | |
done | |
# Generate start-all script | |
cat > "${SCRIPT_DIR}/start-all.sh" << EOF | |
#!/bin/bash | |
for (( i=0; i<${NODES}; i++ )); do | |
"${SCRIPT_DIR}/start-node\${i}.sh" > "${HOME_PREFIX}/node\${i}.log" 2>&1 & | |
done | |
echo "Started all nodes in background. Check logs in ${HOME_PREFIX}/node*.log" | |
EOF | |
chmod +x "${SCRIPT_DIR}/start-all.sh" | |
# Print summary | |
echo "" | |
echo "=============================================" | |
echo "✅ Local Evmos testnet initialized with ${NODES} nodes!" | |
echo "Chain ID: ${CHAIN_ID}" | |
echo "Home dirs: ${HOME_PREFIX}*" | |
echo "=============================================" | |
echo "To start all nodes in background:" | |
echo " ${SCRIPT_DIR}/start-all.sh" | |
echo "Or start individual nodes:" | |
echo " ${SCRIPT_DIR}/start-node[0-$((NODES-1))].sh" | |
echo "=============================================" | |
echo "To check node status:" | |
echo " curl localhost:26657/status" | |
echo "=============================================" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment