Skip to content

Instantly share code, notes, and snippets.

@bufrr
Last active February 1, 2025 03:23
Show Gist options
  • Save bufrr/0caa7b0bea2873264f83729b899a174e to your computer and use it in GitHub Desktop.
Save bufrr/0caa7b0bea2873264f83729b899a174e to your computer and use it in GitHub Desktop.
evmos multiple node deploy script
#!/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