Last active
March 7, 2025 03:46
-
-
Save cordt-sei/69b0886c94575663aa6b521a495bfdcc to your computer and use it in GitHub Desktop.
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 | |
# Enhanced initialize_local_chain.sh with multiple setup options | |
# This script provides various options for setting up Sei local environments | |
set -e | |
# Color codes for better output | |
GREEN='\033[0;32m' | |
YELLOW='\033[1;33m' | |
RED='\033[0;31m' | |
BLUE='\033[0;34m' | |
NC='\033[0m' # No Color | |
# Print with timestamp | |
log() { | |
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | |
} | |
warn() { | |
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | |
} | |
error() { | |
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | |
exit 1 | |
} | |
# Get the project root directory | |
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) | |
# Default configuration | |
DISABLE_ORACLE=false | |
USE_DOCKER=false | |
MULTI_NODE=false | |
NO_RUN=0 | |
NODE_COUNT=4 | |
USE_EXISTING_SCRIPT=false | |
keyname=admin | |
# Display menu and get user choice | |
show_menu() { | |
clear | |
echo -e "${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}" | |
echo -e "${BLUE}║ SEI LOCAL SETUP OPTIONS ║${NC}" | |
echo -e "${BLUE}╚═══════════════════════════════════════════════════════════════╝${NC}" | |
echo | |
echo "Please select a setup option:" | |
echo | |
echo " 1) Standard single-node setup (existing behavior)" | |
echo " 2) Single-node setup with oracle requirement disabled" | |
echo " 3) Multi-node local test cluster (4 validators)" | |
echo " 4) Multi-node local test cluster with oracle requirement disabled" | |
echo " 5) Custom configuration" | |
echo " 0) Exit" | |
echo | |
read -p "Enter your choice [0-5]: " choice | |
case $choice in | |
1) | |
USE_EXISTING_SCRIPT=true | |
log "Selected standard single-node setup" | |
;; | |
2) | |
DISABLE_ORACLE=true | |
log "Selected single-node setup with oracle requirement disabled" | |
;; | |
3) | |
MULTI_NODE=true | |
log "Selected multi-node local test cluster" | |
;; | |
4) | |
MULTI_NODE=true | |
DISABLE_ORACLE=true | |
log "Selected multi-node local test cluster with oracle requirement disabled" | |
;; | |
5) | |
custom_config | |
;; | |
0) | |
log "Exiting..." | |
exit 0 | |
;; | |
*) | |
error "Invalid choice. Please enter a number between 0 and 5." | |
;; | |
esac | |
} | |
# Allow custom configuration | |
custom_config() { | |
echo | |
echo -e "${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}" | |
echo -e "${BLUE}║ CUSTOM CONFIGURATION ║${NC}" | |
echo -e "${BLUE}╚═══════════════════════════════════════════════════════════════╝${NC}" | |
echo | |
# Oracle requirement | |
read -p "Disable oracle requirement? (y/n): " -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
DISABLE_ORACLE=true | |
log "Oracle requirement will be disabled" | |
else | |
log "Oracle requirement will remain enabled" | |
fi | |
# Single or multi-node | |
read -p "Set up multiple validator nodes (cluster)? (y/n): " -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
MULTI_NODE=true | |
read -p "Number of validator nodes (2-10) [default: 4]: " NODE_COUNT | |
NODE_COUNT=${NODE_COUNT:-4} | |
if ! [[ "$NODE_COUNT" =~ ^[2-9]$|^10$ ]]; then | |
NODE_COUNT=4 | |
warn "Invalid number. Using default: 4 nodes" | |
fi | |
log "Will set up a ${NODE_COUNT}-node validator cluster" | |
# Docker option (only for multi-node) | |
if [ -f "${PROJECT_ROOT}/docker/docker-compose.yml" ]; then | |
read -p "Use Docker for multi-node setup? (y/n): " -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
USE_DOCKER=true | |
log "Will use Docker for multi-node setup" | |
else | |
log "Will use direct execution for multi-node setup" | |
fi | |
fi | |
else | |
log "Will set up a single validator node" | |
fi | |
# No run option | |
read -p "Set up only without starting? (y/n): " -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
NO_RUN=1 | |
log "Will set up without starting the node(s)" | |
else | |
log "Will set up and start the node(s)" | |
fi | |
} | |
# Function to run the original initialize_local_chain.sh script | |
run_original_script() { | |
log "Running original initialize_local_chain.sh script..." | |
# Use python3 as default, but fall back to python if python3 doesn't exist | |
PYTHON_CMD=python3 | |
if ! command -v $PYTHON_CMD &> /dev/null | |
then | |
PYTHON_CMD=python | |
fi | |
# clean up old sei directory | |
rm -rf ~/.sei | |
log "Building..." | |
#install seid | |
make install | |
# initialize chain with chain ID and add the first key | |
~/go/bin/seid init demo --chain-id sei-chain | |
~/go/bin/seid keys add $keyname --keyring-backend test | |
# add the key as a genesis account with massive balances of several different tokens | |
~/go/bin/seid add-genesis-account $(~/go/bin/seid keys show $keyname -a --keyring-backend test) 100000000000000000000usei,100000000000000000000uusdc,100000000000000000000uatom --keyring-backend test | |
# gentx for account | |
~/go/bin/seid gentx $keyname 7000000000000000usei --chain-id sei-chain --keyring-backend test | |
# add validator information to genesis file | |
KEY=$(jq '.pub_key' ~/.sei/config/priv_validator_key.json -c) | |
jq '.validators = [{}]' ~/.sei/config/genesis.json > ~/.sei/config/tmp_genesis.json | |
jq '.validators[0] += {"power":"7000000000"}' ~/.sei/config/tmp_genesis.json > ~/.sei/config/tmp_genesis_2.json | |
jq '.validators[0] += {"pub_key":'$KEY'}' ~/.sei/config/tmp_genesis_2.json > ~/.sei/config/tmp_genesis_3.json | |
mv ~/.sei/config/tmp_genesis_3.json ~/.sei/config/genesis.json && rm ~/.sei/config/tmp_genesis.json && rm ~/.sei/config/tmp_genesis_2.json | |
log "Creating Accounts" | |
# create test accounts + fund them | |
python3 loadtest/scripts/populate_genesis_accounts.py 20 loc | |
~/go/bin/seid collect-gentxs | |
# update some params in genesis file for easier use of the chain localls (make gov props faster) | |
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["max_deposit_period"]="60s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="30s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["expedited_voting_period"]="10s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["vote_period"]="2"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["whitelist"]=[{"name": "ueth"},{"name": "ubtc"},{"name": "uusdc"},{"name": "uusdt"},{"name": "uosmo"},{"name": "uatom"},{"name": "usei"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["distribution"]["params"]["community_tax"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="35000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.consensus_params["block"]["min_txs_in_block"]="2"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["staking"]["params"]["max_voting_power_ratio"]="1.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["bank"]["denom_metadata"]=[{"denom_units":[{"denom":"usei","exponent":0,"aliases":["USEI"]}],"base":"usei","display":"usei","name":"USEI","symbol":"USEI"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
# Use the Python command to get the dates | |
START_DATE=$($PYTHON_CMD -c "from datetime import datetime; print(datetime.now().strftime('%Y-%m-%d'))") | |
END_DATE_3DAYS=$($PYTHON_CMD -c "from datetime import datetime, timedelta; print((datetime.now() + timedelta(days=3)).strftime('%Y-%m-%d'))") | |
END_DATE_5DAYS=$($PYTHON_CMD -c "from datetime import datetime, timedelta; print((datetime.now() + timedelta(days=5)).strftime('%Y-%m-%d'))") | |
cat ~/.sei/config/genesis.json | jq --arg start_date "$START_DATE" --arg end_date "$END_DATE_3DAYS" '.app_state["mint"]["params"]["token_release_schedule"]=[{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq --arg start_date "$END_DATE_3DAYS" --arg end_date "$END_DATE_5DAYS" '.app_state["mint"]["params"]["token_release_schedule"] += [{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
if [ ! -z "$2" ]; then | |
APP_TOML_PATH="$2" | |
else | |
APP_TOML_PATH="$HOME/.sei/config/app.toml" | |
fi | |
# Enable OCC and SeiDB | |
sed -i.bak -e 's/# concurrency-workers = .*/concurrency-workers = 500/' $APP_TOML_PATH | |
sed -i.bak -e 's/occ-enabled = .*/occ-enabled = true/' $APP_TOML_PATH | |
sed -i.bak -e 's/sc-enable = .*/sc-enable = true/' $APP_TOML_PATH | |
sed -i.bak -e 's/ss-enable = .*/ss-enable = true/' $APP_TOML_PATH | |
# set block time to 2s | |
if [ ! -z "$1" ]; then | |
CONFIG_PATH="$1" | |
else | |
CONFIG_PATH="$HOME/.sei/config/config.toml" | |
fi | |
if [ ! -z "$2" ]; then | |
APP_PATH="$2" | |
else | |
APP_PATH="$HOME/.sei/config/app.toml" | |
fi | |
if [[ "$OSTYPE" == "linux-gnu"* ]]; then | |
sed -i 's/mode = "full"/mode = "validator"/g' $CONFIG_PATH | |
sed -i 's/indexer = \["null"\]/indexer = \["kv"\]/g' $CONFIG_PATH | |
sed -i 's/timeout_prevote =.*/timeout_prevote = "2000ms"/g' $CONFIG_PATH | |
sed -i 's/timeout_precommit =.*/timeout_precommit = "2000ms"/g' $CONFIG_PATH | |
sed -i 's/timeout_commit =.*/timeout_commit = "2000ms"/g' $CONFIG_PATH | |
sed -i 's/skip_timeout_commit =.*/skip_timeout_commit = false/g' $CONFIG_PATH | |
elif [[ "$OSTYPE" == "darwin"* ]]; then | |
sed -i '' 's/mode = "full"/mode = "validator"/g' $CONFIG_PATH | |
sed -i '' 's/indexer = \["null"\]/indexer = \["kv"\]/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-propose-timeout-override =.*/unsafe-propose-timeout-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-propose-timeout-delta-override =.*/unsafe-propose-timeout-delta-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-vote-timeout-override =.*/unsafe-vote-timeout-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-vote-timeout-delta-override =.*/unsafe-vote-timeout-delta-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-commit-timeout-override =.*/unsafe-commit-timeout-override = "2s"/g' $CONFIG_PATH | |
else | |
printf "Platform not supported, please ensure that the following values are set in your config.toml:\n" | |
printf "### Consensus Configuration Options ###\n" | |
printf "\t timeout_prevote = \"2000ms\"\n" | |
printf "\t timeout_precommit = \"2000ms\"\n" | |
printf "\t timeout_commit = \"2000ms\"\n" | |
printf "\t skip_timeout_commit = false\n" | |
exit 1 | |
fi | |
~/go/bin/seid config keyring-backend test | |
if [ $NO_RUN = 1 ]; then | |
log "No run flag set, exiting without starting the chain" | |
exit 0 | |
fi | |
# start the chain with log tracing | |
log "Starting the Sei chain..." | |
GORACE="log_path=/tmp/race/seid_race" ~/go/bin/seid start --trace --chain-id sei-chain | |
} | |
# Function to run script with oracle requirement disabled (single node) | |
run_with_oracle_disabled() { | |
log "Running Sei setup with oracle requirement disabled..." | |
# This function is similar to run_original_script but adds the oracle disabling commands | |
# Use python3 as default, but fall back to python if python3 doesn't exist | |
PYTHON_CMD=python3 | |
if ! command -v $PYTHON_CMD &> /dev/null | |
then | |
PYTHON_CMD=python | |
fi | |
# clean up old sei directory | |
rm -rf ~/.sei | |
log "Building..." | |
#install seid | |
make install | |
# initialize chain with chain ID and add the first key | |
~/go/bin/seid init demo --chain-id sei-chain | |
~/go/bin/seid keys add $keyname --keyring-backend test | |
# add the key as a genesis account with massive balances of several different tokens | |
~/go/bin/seid add-genesis-account $(~/go/bin/seid keys show $keyname -a --keyring-backend test) 100000000000000000000usei,100000000000000000000uusdc,100000000000000000000uatom --keyring-backend test | |
# gentx for account | |
~/go/bin/seid gentx $keyname 7000000000000000usei --chain-id sei-chain --keyring-backend test | |
# add validator information to genesis file | |
KEY=$(jq '.pub_key' ~/.sei/config/priv_validator_key.json -c) | |
jq '.validators = [{}]' ~/.sei/config/genesis.json > ~/.sei/config/tmp_genesis.json | |
jq '.validators[0] += {"power":"7000000000"}' ~/.sei/config/tmp_genesis.json > ~/.sei/config/tmp_genesis_2.json | |
jq '.validators[0] += {"pub_key":'$KEY'}' ~/.sei/config/tmp_genesis_2.json > ~/.sei/config/tmp_genesis_3.json | |
mv ~/.sei/config/tmp_genesis_3.json ~/.sei/config/genesis.json && rm ~/.sei/config/tmp_genesis.json && rm ~/.sei/config/tmp_genesis_2.json | |
log "Creating Accounts" | |
# create test accounts + fund them | |
python3 loadtest/scripts/populate_genesis_accounts.py 20 loc | |
~/go/bin/seid collect-gentxs | |
# MODIFICATION: Disable oracle voting requirement by setting critical parameters to 0 | |
log "Disabling oracle voting requirements..." | |
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["min_valid_per_window"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["vote_threshold"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["slash_fraction"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
# update some params in genesis file for easier use of the chain localls (make gov props faster) | |
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["max_deposit_period"]="60s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="30s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["expedited_voting_period"]="10s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["vote_period"]="2"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["whitelist"]=[{"name": "ueth"},{"name": "ubtc"},{"name": "uusdc"},{"name": "uusdt"},{"name": "uosmo"},{"name": "uatom"},{"name": "usei"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["distribution"]["params"]["community_tax"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="35000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.consensus_params["block"]["min_txs_in_block"]="2"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["staking"]["params"]["max_voting_power_ratio"]="1.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq '.app_state["bank"]["denom_metadata"]=[{"denom_units":[{"denom":"usei","exponent":0,"aliases":["USEI"]}],"base":"usei","display":"usei","name":"USEI","symbol":"USEI"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
# Use the Python command to get the dates | |
START_DATE=$($PYTHON_CMD -c "from datetime import datetime; print(datetime.now().strftime('%Y-%m-%d'))") | |
END_DATE_3DAYS=$($PYTHON_CMD -c "from datetime import datetime, timedelta; print((datetime.now() + timedelta(days=3)).strftime('%Y-%m-%d'))") | |
END_DATE_5DAYS=$($PYTHON_CMD -c "from datetime import datetime, timedelta; print((datetime.now() + timedelta(days=5)).strftime('%Y-%m-%d'))") | |
cat ~/.sei/config/genesis.json | jq --arg start_date "$START_DATE" --arg end_date "$END_DATE_3DAYS" '.app_state["mint"]["params"]["token_release_schedule"]=[{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
cat ~/.sei/config/genesis.json | jq --arg start_date "$END_DATE_3DAYS" --arg end_date "$END_DATE_5DAYS" '.app_state["mint"]["params"]["token_release_schedule"] += [{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json | |
if [ ! -z "$2" ]; then | |
APP_TOML_PATH="$2" | |
else | |
APP_TOML_PATH="$HOME/.sei/config/app.toml" | |
fi | |
# Enable OCC and SeiDB | |
sed -i.bak -e 's/# concurrency-workers = .*/concurrency-workers = 500/' $APP_TOML_PATH | |
sed -i.bak -e 's/occ-enabled = .*/occ-enabled = true/' $APP_TOML_PATH | |
sed -i.bak -e 's/sc-enable = .*/sc-enable = true/' $APP_TOML_PATH | |
sed -i.bak -e 's/ss-enable = .*/ss-enable = true/' $APP_TOML_PATH | |
# set block time to 2s | |
if [ ! -z "$1" ]; then | |
CONFIG_PATH="$1" | |
else | |
CONFIG_PATH="$HOME/.sei/config/config.toml" | |
fi | |
if [ ! -z "$2" ]; then | |
APP_PATH="$2" | |
else | |
APP_PATH="$HOME/.sei/config/app.toml" | |
fi | |
if [[ "$OSTYPE" == "linux-gnu"* ]]; then | |
sed -i 's/mode = "full"/mode = "validator"/g' $CONFIG_PATH | |
sed -i 's/indexer = \["null"\]/indexer = \["kv"\]/g' $CONFIG_PATH | |
sed -i 's/timeout_prevote =.*/timeout_prevote = "2000ms"/g' $CONFIG_PATH | |
sed -i 's/timeout_precommit =.*/timeout_precommit = "2000ms"/g' $CONFIG_PATH | |
sed -i 's/timeout_commit =.*/timeout_commit = "2000ms"/g' $CONFIG_PATH | |
sed -i 's/skip_timeout_commit =.*/skip_timeout_commit = false/g' $CONFIG_PATH | |
elif [[ "$OSTYPE" == "darwin"* ]]; then | |
sed -i '' 's/mode = "full"/mode = "validator"/g' $CONFIG_PATH | |
sed -i '' 's/indexer = \["null"\]/indexer = \["kv"\]/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-propose-timeout-override =.*/unsafe-propose-timeout-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-propose-timeout-delta-override =.*/unsafe-propose-timeout-delta-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-vote-timeout-override =.*/unsafe-vote-timeout-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-vote-timeout-delta-override =.*/unsafe-vote-timeout-delta-override = "2s"/g' $CONFIG_PATH | |
sed -i '' 's/unsafe-commit-timeout-override =.*/unsafe-commit-timeout-override = "2s"/g' $CONFIG_PATH | |
else | |
printf "Platform not supported, please ensure that the following values are set in your config.toml:\n" | |
printf "### Consensus Configuration Options ###\n" | |
printf "\t timeout_prevote = \"2000ms\"\n" | |
printf "\t timeout_precommit = \"2000ms\"\n" | |
printf "\t timeout_commit = \"2000ms\"\n" | |
printf "\t skip_timeout_commit = false\n" | |
exit 1 | |
fi | |
~/go/bin/seid config keyring-backend test | |
if [ $NO_RUN = 1 ]; then | |
log "No run flag set, exiting without starting the chain" | |
exit 0 | |
fi | |
# start the chain with log tracing | |
log "Starting the Sei chain with oracle requirement disabled..." | |
GORACE="log_path=/tmp/race/seid_race" ~/go/bin/seid start --trace --chain-id sei-chain | |
} | |
# Function to create oracle voter script (for fallback) | |
create_oracle_voter_script() { | |
local ORACLE_SCRIPT="${PROJECT_ROOT}/scripts/oracle_voter.py" | |
log "Creating oracle voter script at ${ORACLE_SCRIPT}..." | |
cat > "${ORACLE_SCRIPT}" << 'EOF' | |
#!/usr/bin/env python3 | |
import time | |
import subprocess | |
import requests | |
import sys | |
import logging | |
# Set up logging | |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
# Default configuration | |
KEYNAME = "admin" | |
PASSWORD = "12345678" | |
CHAIN_ID = "sei-chain" | |
VOTE_PERIOD = 10 | |
BINARY = "~/go/bin/seid" | |
NODE = "http://localhost:26657" | |
def get_current_vote_period(): | |
try: | |
res = requests.get(f"{NODE}/blockchain") | |
body = res.json() | |
return int(body["result"]["last_height"]) // VOTE_PERIOD | |
except Exception as e: | |
logging.error(f"Error getting current vote period: {e}") | |
return -1 | |
def execute_cmd(cmd): | |
try: | |
result = subprocess.run(cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) | |
logging.info(f"Command executed successfully: {cmd}") | |
logging.debug(f"Output: {result.stdout}") | |
return result.stdout | |
except subprocess.CalledProcessError as e: | |
logging.error(f"Command failed: {cmd}") | |
logging.error(f"Error: {e.stderr}") | |
return None | |
def get_validator_address(): | |
cmd = f"printf '{PASSWORD}\\n' | {BINARY} keys show {KEYNAME} --bech=val | grep address | cut -d':' -f2 | xargs" | |
result = execute_cmd(cmd) | |
if result: | |
val_addr = result.strip() | |
logging.info(f"Validator address: {val_addr}") | |
return val_addr | |
return None | |
def vote(): | |
val_addr = get_validator_address() | |
if not val_addr: | |
logging.error("Could not get validator address") | |
return False | |
# Construct fake prices (1 for each whitelisted token) | |
prices = "1usei,1ueth,1ubtc,1uusdc,1uusdt,1uosmo,1uatom" | |
# Submit vote | |
cmd = f"printf '{PASSWORD}\\n' | {BINARY} tx oracle aggregate-vote {prices} {val_addr} --from {KEYNAME} --chain-id={CHAIN_ID} -y --broadcast-mode=sync" | |
result = execute_cmd(cmd) | |
return result is not None | |
def main(): | |
logging.info("Starting automatic oracle voter") | |
logging.info(f"Chain ID: {CHAIN_ID}") | |
logging.info(f"Node: {NODE}") | |
last_voted_period = -1 | |
while True: | |
try: | |
current_period = get_current_vote_period() | |
if current_period > last_voted_period: | |
logging.info(f"Submitting oracle vote for period {current_period}") | |
if vote(): | |
last_voted_period = current_period | |
logging.info(f"Vote submitted successfully for period {current_period}") | |
else: | |
logging.error(f"Failed to submit vote for period {current_period}") | |
time.sleep(1) # Check every second | |
except Exception as e: | |
logging.error(f"Unexpected error: {e}") | |
time.sleep(5) # Wait a bit longer on error | |
if __name__ == "__main__": | |
try: | |
main() | |
except KeyboardInterrupt: | |
logging.info("Oracle voter stopped by user") | |
EOF | |
chmod +x "${ORACLE_SCRIPT}" | |
log "Oracle voter script created successfully" | |
} | |
# Function to create the patch genesis script for multi-node setup | |
create_patch_genesis_script() { | |
local PATCH_SCRIPT="${PROJECT_ROOT}/docker/patch_genesis.sh" | |
log "Creating genesis patch script at ${PATCH_SCRIPT}..." | |
cat > "${PATCH_SCRIPT}" << 'EOF' | |
#!/bin/bash | |
# This script patches the genesis file to disable oracle requirements | |
# It will be executed in the Docker container | |
set -e | |
echo "Patching genesis files to disable oracle requirements..." | |
# Function to patch a single genesis file | |
patch_genesis() { | |
local genesis_file=$1 | |
echo "Patching $genesis_file" | |
# Create a backup | |
cp "$genesis_file" "${genesis_file}.bak" | |
# Disable oracle voting requirement | |
cat "$genesis_file" | jq '.app_state["oracle"]["params"]["min_valid_per_window"]="0.000000000000000000"' > "${genesis_file}.tmp" | |
mv "${genesis_file}.tmp" "$genesis_file" | |
cat "$genesis_file" | jq '.app_state["oracle"]["params"]["vote_threshold"]="0.000000000000000000"' > "${genesis_file}.tmp" | |
mv "${genesis_file}.tmp" "$genesis_file" | |
cat "$genesis_file" | jq '.app_state["oracle"]["params"]["slash_fraction"]="0.000000000000000000"' > "${genesis_file}.tmp" | |
mv "${genesis_file}.tmp" "$genesis_file" | |
echo "Successfully patched $genesis_file" | |
} | |
# Wait for the genesis file to be created | |
MAX_ATTEMPTS=30 | |
ATTEMPT=0 | |
GENESIS_FILE="/sei-protocol/sei-chain/build/generated/validator-0/sei/config/genesis.json" | |
while [ ! -f "$GENESIS_FILE" ] && [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do | |
echo "Waiting for genesis file to be created... (attempt $ATTEMPT/$MAX_ATTEMPTS)" | |
sleep 5 | |
ATTEMPT=$((ATTEMPT + 1)) | |
done | |
if [ ! -f "$GENESIS_FILE" ]; then | |
echo "Genesis file not found after waiting. Cannot patch." | |
exit 1 | |
fi | |
# Patch the main genesis file | |
patch_genesis "$GENESIS_FILE" | |
# Find and patch all other genesis files | |
find /sei-protocol/sei-chain/build/generated -name "genesis.json" | while read -r genesis_file; do | |
if [ "$genesis_file" != "$GENESIS_FILE" ]; then | |
patch_genesis "$genesis_file" | |
fi | |
done | |
echo "All genesis files have been patched successfully!" | |
EOF | |
chmod +x "${PATCH_SCRIPT}" | |
log "Genesis patch script created successfully" | |
} | |
# Function to run multi-node setup with Docker | |
run_multinode_docker() { | |
log "Setting up multi-node cluster using Docker..." | |
# Ensure the docker directory exists | |
if [ ! -f "${PROJECT_ROOT}/docker/docker-compose.yml" ]; then | |
error "Docker configuration not found at ${PROJECT_ROOT}/docker/docker-compose.yml" | |
fi | |
# Create the patch script if oracle requirement should be disabled | |
if [ "$DISABLE_ORACLE" = true ]; then | |
create_patch_genesis_script | |
fi | |
# Create a wrapper script for the Docker setup | |
local WRAPPER_SCRIPT="${PROJECT_ROOT}/run_docker_cluster.sh" | |
cat > "${WRAPPER_SCRIPT}" << 'EOF' | |
#!/bin/bash | |
set -e | |
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) | |
cd "${PROJECT_ROOT}" | |
# Make directory for generated files | |
mkdir -p build/generated | |
# Build Docker image | |
echo "Building Docker node image..." | |
make build-docker-node | |
# Run directly using make command which properly sets up environment variables | |
cd "${PROJECT_ROOT}" | |
# Check if we need to run or just setup | |
if [ "${NO_RUN}" = "1" ]; then | |
echo "Setting up without starting..." | |
make docker-cluster-stop | |
else | |
echo "Starting docker cluster..." | |
# Apply patch_genesis.sh if needed | |
if [ -f "${PROJECT_ROOT}/docker/patch_genesis.sh" ]; then | |
# First run a single validator to generate the genesis file | |
echo "Starting validator-0 to generate initial genesis..." | |
cd "${PROJECT_ROOT}" && make docker-cluster-start-skipbuild | |
# Wait a bit for the genesis to be created | |
sleep 5 | |
# Now stop and restart with our modified configuration | |
make docker-cluster-stop | |
sleep 3 | |
echo "Restarting with patched genesis..." | |
fi | |
# Start the cluster | |
cd "${PROJECT_ROOT}" && make docker-cluster-start-skipbuild | |
fi | |
EOF | |
chmod +x "${WRAPPER_SCRIPT}" | |
# Run the wrapper script | |
log "Running Docker cluster setup..." | |
export NO_RUN=${NO_RUN} | |
bash "${WRAPPER_SCRIPT}" | |
} | |
# Function to run multi-node setup with direct execution | |
run_multinode_direct() { | |
log "Setting up multi-node cluster using direct execution..." | |
if [ "$DISABLE_ORACLE" = true ]; then | |
log "You've selected to disable oracle requirements." | |
fi | |
log "Direct execution of multi-node setup is not fully implemented yet." | |
log "Would you like to use Docker for the multi-node setup instead? (y/n)" | |
read -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
USE_DOCKER=true | |
run_multinode_docker | |
else | |
# Create a simple way to launch multiple nodes | |
log "Creating a simple multi-node direct execution script..." | |
local MULTINODE_SCRIPT="${PROJECT_ROOT}/run_multinode_direct.sh" | |
cat > "${MULTINODE_SCRIPT}" << 'EOF' | |
#!/bin/bash | |
# Script to run multiple Sei validator nodes directly (without Docker) | |
set -e | |
NODE_COUNT=${1:-4} | |
DISABLE_ORACLE=${2:-false} | |
NO_RUN=${3:-0} | |
echo "Setting up $NODE_COUNT Sei validator nodes..." | |
# Create and configure the nodes | |
for i in $(seq 0 $((NODE_COUNT-1))); do | |
echo "Setting up validator-$i..." | |
# Create separate data directory for each node | |
NODE_HOME="$HOME/.sei-validator-$i" | |
rm -rf "$NODE_HOME" | |
mkdir -p "$NODE_HOME" | |
# Initialize the node | |
seid --home "$NODE_HOME" init "validator-$i" --chain-id sei-chain | |
# Create account | |
seid --home "$NODE_HOME" keys add validator --keyring-backend test | |
# Add test funds | |
seid --home "$NODE_HOME" add-genesis-account $(seid --home "$NODE_HOME" keys show validator -a --keyring-backend test) 100000000000000000000usei,100000000000000000000uusdc,100000000000000000000uatom --keyring-backend test | |
# Create genesis transaction | |
seid --home "$NODE_HOME" gentx validator 7000000000000000usei --chain-id sei-chain --keyring-backend test | |
# Disable oracle requirement if requested | |
if [ "$DISABLE_ORACLE" = true ]; then | |
echo "Disabling oracle requirements for validator-$i..." | |
cat "$NODE_HOME/config/genesis.json" | jq '.app_state["oracle"]["params"]["min_valid_per_window"]="0.000000000000000000"' > "$NODE_HOME/config/tmp_genesis.json" && mv "$NODE_HOME/config/tmp_genesis.json" "$NODE_HOME/config/genesis.json" | |
cat "$NODE_HOME/config/genesis.json" | jq '.app_state["oracle"]["params"]["vote_threshold"]="0.000000000000000000"' > "$NODE_HOME/config/tmp_genesis.json" && mv "$NODE_HOME/config/tmp_genesis.json" "$NODE_HOME/config/genesis.json" | |
cat "$NODE_HOME/config/genesis.json" | jq '.app_state["oracle"]["params"]["slash_fraction"]="0.000000000000000000"' > "$NODE_HOME/config/tmp_genesis.json" && mv "$NODE_HOME/config/tmp_genesis.json" "$NODE_HOME/config/genesis.json" | |
fi | |
# Configure P2P for each node | |
sed -i.bak "s/26656/2${i}656/g" "$NODE_HOME/config/config.toml" | |
sed -i.bak "s/26657/2${i}657/g" "$NODE_HOME/config/config.toml" | |
sed -i.bak "s/26658/2${i}658/g" "$NODE_HOME/config/config.toml" | |
sed -i.bak "s/6060/6${i}60/g" "$NODE_HOME/config/config.toml" | |
# Configure API for each node | |
sed -i.bak "s/1317/1${i}17/g" "$NODE_HOME/config/app.toml" | |
sed -i.bak "s/9090/9${i}90/g" "$NODE_HOME/config/app.toml" | |
sed -i.bak "s/9091/9${i}91/g" "$NODE_HOME/config/app.toml" | |
done | |
echo "Basic node setup completed!" | |
echo "Note: This is a simplified multi-node setup that creates separate node directories." | |
echo "Further configuration is needed to make them connect as a network." | |
if [ "$NO_RUN" = "1" ]; then | |
echo "No-run flag set. Exiting without starting nodes." | |
exit 0 | |
fi | |
echo "Starting validator-0 (primary node)..." | |
seid --home "$HOME/.sei-validator-0" start --trace --chain-id sei-chain | |
EOF | |
chmod +x "${MULTINODE_SCRIPT}" | |
log "Created multi-node direct execution script at ${MULTINODE_SCRIPT}" | |
log "Note: Direct multi-node execution is experimental and needs further development." | |
# Offer to run the script | |
read -p "Would you like to attempt running the multi-node direct execution? (y/n): " -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
bash "${MULTINODE_SCRIPT}" "${NODE_COUNT}" "${DISABLE_ORACLE}" "${NO_RUN}" | |
else | |
log "Okay. You can run it later with: ${MULTINODE_SCRIPT}" | |
fi | |
fi | |
} | |
# Cleanup of previous deployment | |
perform_cleanup() { | |
log "Starting comprehensive cleanup..." | |
# Stop any running Docker containers related to Sei | |
if command -v docker &> /dev/null; then | |
log "Stopping and removing Docker containers..." | |
cd "${PROJECT_ROOT}" && make docker-cluster-stop 2>/dev/null || true | |
docker ps -a | grep sei | awk '{print $1}' | xargs -r docker rm -f 2>/dev/null || true | |
fi | |
# Kill any running seid processes | |
log "Stopping any running seid processes..." | |
pkill -f "seid" 2>/dev/null || true | |
# Remove Sei data directories | |
log "Removing Sei data directories..." | |
rm -rf ~/.sei | |
# Remove all validator directories | |
for i in {0..10}; do | |
rm -rf ~/.sei-validator-$i 2>/dev/null || true | |
done | |
# Remove generated files in project directory | |
log "Removing generated files..." | |
rm -rf "${PROJECT_ROOT}/build/generated" 2>/dev/null || true | |
# Remove any temporary scripts we created | |
log "Removing temporary scripts..." | |
rm -f "${PROJECT_ROOT}/docker/patch_genesis.sh" 2>/dev/null || true | |
rm -f "${PROJECT_ROOT}/run_docker_cluster.sh" 2>/dev/null || true | |
rm -f "${PROJECT_ROOT}/run_multinode_direct.sh" 2>/dev/null || true | |
# Kill any oracle voter processes | |
log "Stopping any running oracle voter processes..." | |
pkill -f "oracle_voter.py" 2>/dev/null || true | |
# Remove oracle voter logs | |
rm -f oracle_voter.log 2>/dev/null || true | |
log "Cleanup completed successfully!" | |
} | |
# Main function | |
main() { | |
# Ask if user wants to clean up first | |
read -p "Do you want to perform a complete cleanup of previous executions first? (y/n): " -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
perform_cleanup | |
fi | |
# Display the menu and get user choice | |
show_menu | |
# Run the selected setup | |
if [ "$USE_EXISTING_SCRIPT" = true ]; then | |
run_original_script | |
elif [ "$MULTI_NODE" = true ]; then | |
if [ "$USE_DOCKER" = true ]; then | |
run_multinode_docker | |
else | |
# Check if Docker is available and suggest it | |
if [ -f "${PROJECT_ROOT}/docker/docker-compose.yml" ]; then | |
log "Multi-node setup is easier with Docker. Would you like to use Docker? (y/n)" | |
read -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
USE_DOCKER=true | |
run_multinode_docker | |
else | |
run_multinode_direct | |
fi | |
else | |
run_multinode_direct | |
fi | |
fi | |
else | |
if [ "$DISABLE_ORACLE" = true ]; then | |
# If oracle requirement is disabled, create the voter script (just in case) | |
create_oracle_voter_script | |
run_with_oracle_disabled | |
else | |
run_original_script | |
fi | |
fi | |
} | |
# Execute main function | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment