mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
Feat/add networks (#1303)
* No commit suggestions generated * No commit suggestions generated * No commit suggestions generated
This commit is contained in:
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
mkdir -p /tmp/chains $UPGRADE_DIR
|
||||
|
||||
echo "Fetching code from tag"
|
||||
mkdir -p /tmp/chains/$CHAIN_NAME
|
||||
cd /tmp/chains/$CHAIN_NAME
|
||||
|
||||
if [[ $CODE_TAG =~ ^[0-9a-fA-F]{40}$ ]]; then
|
||||
echo "Trying to fetch code from commit hash"
|
||||
curl -LO $CODE_REPO/archive/$CODE_TAG.zip
|
||||
unzip $CODE_TAG.zip
|
||||
code_dir=${CODE_REPO##*/}-${CODE_TAG}
|
||||
elif [[ $CODE_TAG = v* ]]; then
|
||||
echo "Trying to fetch code from tag with 'v' prefix"
|
||||
curl -LO $CODE_REPO/archive/refs/tags/$CODE_TAG.zip
|
||||
unzip $CODE_TAG.zip
|
||||
code_dir=${CODE_REPO##*/}-${CODE_TAG#"v"}
|
||||
else
|
||||
echo "Trying to fetch code from tag or branch"
|
||||
if curl -fsLO $CODE_REPO/archive/refs/tags/$CODE_TAG.zip; then
|
||||
unzip $CODE_TAG.zip
|
||||
code_dir=${CODE_REPO##*/}-$CODE_TAG
|
||||
elif curl -fsLO $CODE_REPO/archive/refs/heads/$CODE_TAG.zip; then
|
||||
unzip $(echo $CODE_TAG | rev | cut -d "/" -f 1 | rev).zip
|
||||
code_dir=${CODE_REPO##*/}-${CODE_TAG/\//-}
|
||||
else
|
||||
echo "Tag or branch '$CODE_TAG' not found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Fetch wasmvm if needed"
|
||||
cd /tmp/chains/$CHAIN_NAME/$code_dir
|
||||
WASM_VERSION=$(cat go.mod | grep -oe "github.com/CosmWasm/wasmvm v[0-9.]*" | cut -d ' ' -f 2)
|
||||
if [[ WASM_VERSION != "" ]]; then
|
||||
mkdir -p /tmp/chains/libwasmvm_muslc
|
||||
cd /tmp/chains/libwasmvm_muslc
|
||||
curl -LO https://github.com/CosmWasm/wasmvm/releases/download/$WASM_VERSION/libwasmvm_muslc.x86_64.a
|
||||
cp libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.a
|
||||
fi
|
||||
|
||||
echo "Build chain binary"
|
||||
cd /tmp/chains/$CHAIN_NAME/$code_dir
|
||||
CGO_ENABLED=1 BUILD_TAGS="muslc linkstatic" LINK_STATICALLY=true LEDGER_ENABLED=false make install
|
||||
|
||||
echo "Copy created binary to the upgrade directories"
|
||||
if [[ $UPGRADE_NAME == "genesis" ]]; then
|
||||
mkdir -p $UPGRADE_DIR/genesis/bin
|
||||
cp $GOBIN/$CHAIN_BIN $UPGRADE_DIR/genesis/bin
|
||||
else
|
||||
mkdir -p $UPGRADE_DIR/upgrades/$UPGRADE_NAME/bin
|
||||
cp $GOBIN/$CHAIN_BIN $UPGRADE_DIR/upgrades/$UPGRADE_NAME/bin
|
||||
fi
|
||||
|
||||
echo "Cleanup"
|
||||
rm -rf /tmp/chains/$CHAIN_NAME
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
# chain-rpc-ready.sh - Check if a CometBFT or Tendermint RPC service is ready
|
||||
# Usage: chain-rpc-ready.sh [RPC_URL]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
RPC_URL=${1:-"http://localhost:26657"}
|
||||
|
||||
echo 1>&2 "Checking if $RPC_URL is ready..."
|
||||
|
||||
# Check if the RPC URL is reachable,
|
||||
json=$(curl -s --connect-timeout 2 "$RPC_URL/status")
|
||||
|
||||
# and the bootstrap block state has been validated,
|
||||
if [ "$(echo "$json" | jq -r '.result.sync_info | (.earliest_block_height < .latest_block_height)')" != true ]; then
|
||||
echo 1>&2 "$RPC_URL is not ready: bootstrap block state has not been validated"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# and the node is not catching up.
|
||||
if [ "$(echo "$json" | jq -r .result.sync_info.catching_up)" != false ]; then
|
||||
echo 1>&2 "$RPC_URL is not ready: node is catching up"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$json" | jq -r .result
|
||||
exit 0
|
||||
+93
-125
@@ -1,146 +1,114 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
# scripts/create-genesis.sh - Create genesis file for Sonr network
|
||||
|
||||
# generate_vrf_key generates a VRF keypair and stores it securely
|
||||
generate_vrf_key() {
|
||||
local home_dir="$1"
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${home_dir}" ]]; then
|
||||
echo "Error: HOME_DIR parameter is required" >&2
|
||||
return 1
|
||||
fi
|
||||
# Source helper libraries
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/lib/env.sh"
|
||||
source "${SCRIPT_DIR}/lib/keys.sh"
|
||||
source "${SCRIPT_DIR}/lib/genesis.sh"
|
||||
|
||||
local genesis_file="${home_dir}/config/genesis.json"
|
||||
|
||||
if [[ ! -f "${genesis_file}" ]]; then
|
||||
echo "Error: Genesis file not found at ${genesis_file}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local chain_id
|
||||
chain_id=$(jq -r '.chain_id' "${genesis_file}" 2>/dev/null)
|
||||
|
||||
if [[ -z "${chain_id}" || "${chain_id}" == "null" ]]; then
|
||||
echo "Error: Failed to extract chain-id from genesis file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Generating VRF keypair for network: ${chain_id}"
|
||||
|
||||
local entropy_seed
|
||||
entropy_seed=$(echo -n "${chain_id}" | sha256sum | cut -d' ' -f1)
|
||||
|
||||
local seed_part1="${entropy_seed}"
|
||||
local seed_part2
|
||||
seed_part2=$(echo -n "${entropy_seed}" | sha256sum | cut -d' ' -f1)
|
||||
|
||||
local vrf_key_hex="${seed_part1}${seed_part2}"
|
||||
|
||||
if [[ ${#vrf_key_hex} -ne 128 ]]; then
|
||||
echo "Error: Generated VRF key has incorrect size: ${#vrf_key_hex}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local vrf_key_path="${home_dir}/vrf_secret.key"
|
||||
mkdir -p "${home_dir}"
|
||||
|
||||
echo -n "${vrf_key_hex}" | xxd -r -p > "${vrf_key_path}"
|
||||
chmod 0600 "${vrf_key_path}"
|
||||
|
||||
local file_size
|
||||
file_size=$(wc -c < "${vrf_key_path}")
|
||||
|
||||
if [[ ${file_size} -ne 64 ]]; then
|
||||
echo "Error: VRF key file has incorrect size: ${file_size} bytes" >&2
|
||||
rm -f "${vrf_key_path}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "✓ VRF keypair generated for network: ${chain_id}"
|
||||
echo "✓ VRF secret key stored securely: ${vrf_key_path}"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
DENOM="${DENOM:=usnr}"
|
||||
# Match init-testnet.sh allocation: 100000000000000000000000000snr = 100000000000000000000000000000000usnr
|
||||
COINS="${COINS:=100000000000000000000000000000000$DENOM,100000000000000000000000000snr}"
|
||||
CHAIN_ID="${CHAIN_ID:=sonrtest_1-1}"
|
||||
CHAIN_BIN="${CHAIN_BIN:=snrd}"
|
||||
CHAIN_DIR="${CHAIN_DIR:=$HOME/.sonr}"
|
||||
KEYS_CONFIG="${KEYS_CONFIG:=configs/keys.json}"
|
||||
# Initialize environment
|
||||
init_env
|
||||
|
||||
# Set defaults for genesis creation
|
||||
FAUCET_ENABLED="${FAUCET_ENABLED:=true}"
|
||||
NUM_VALIDATORS="${NUM_VALIDATORS:=1}"
|
||||
NUM_RELAYERS="${NUM_RELAYERS:=0}"
|
||||
|
||||
# check if the binary has genesis subcommand or not, if not, set CHAIN_GENESIS_CMD to empty
|
||||
CHAIN_GENESIS_CMD=$($CHAIN_BIN 2>&1 | grep -q "genesis-related subcommands" && echo "genesis" || echo "")
|
||||
# Match init-testnet.sh allocation: 100000000000000000000000000snr = 100000000000000000000000000000000usnr
|
||||
BASE_COINS="${BASE_COINS:=100000000000000000000000000000000${DENOM},100000000000000000000000000snr}"
|
||||
VALIDATOR_AMOUNT="1000000000000000000000000000${DENOM}"
|
||||
|
||||
jq -r ".genesis[0].mnemonic" "$KEYS_CONFIG" | $CHAIN_BIN init "$CHAIN_ID" --chain-id "$CHAIN_ID" --default-denom "$DENOM" --recover
|
||||
|
||||
# Add genesis keys to the keyring and self delegate initial coins
|
||||
echo "Adding key...." $(jq -r ".genesis[0].name" "$KEYS_CONFIG")
|
||||
jq -r ".genesis[0].mnemonic" "$KEYS_CONFIG" | $CHAIN_BIN keys add $(jq -r ".genesis[0].name" "$KEYS_CONFIG") --recover --keyring-backend="test"
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" add-genesis-account $($CHAIN_BIN keys show -a $(jq -r .genesis[0].name "$KEYS_CONFIG") --keyring-backend="test") "$COINS" --keyring-backend="test"
|
||||
|
||||
# Add faucet key to the keyring and self delegate initial coins
|
||||
echo "Adding key...." $(jq -r ".faucet[0].name" "$KEYS_CONFIG")
|
||||
jq -r ".faucet[0].mnemonic" "$KEYS_CONFIG" | $CHAIN_BIN keys add $(jq -r ".faucet[0].name" "$KEYS_CONFIG") --recover --keyring-backend="test"
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" add-genesis-account $($CHAIN_BIN keys show -a $(jq -r .faucet[0].name "$KEYS_CONFIG") --keyring-backend="test") "$COINS" --keyring-backend="test"
|
||||
|
||||
# Add test keys to the keyring and self delegate initial coins
|
||||
echo "Adding key...." $(jq -r ".keys[0].name" "$KEYS_CONFIG")
|
||||
jq -r ".keys[0].mnemonic" "$KEYS_CONFIG" | $CHAIN_BIN keys add $(jq -r ".keys[0].name" "$KEYS_CONFIG") --recover --keyring-backend="test"
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" add-genesis-account $($CHAIN_BIN keys show -a $(jq -r .keys[0].name "$KEYS_CONFIG") --keyring-backend="test") "$COINS" --keyring-backend="test"
|
||||
|
||||
if [[ $FAUCET_ENABLED == "false" && $NUM_RELAYERS -gt "-1" ]]; then
|
||||
## Add relayers keys and delegate tokens
|
||||
for i in $(seq 0 "$NUM_RELAYERS"); do
|
||||
# Add relayer key and delegate tokens
|
||||
RELAYER_KEY_NAME="$(jq -r ".relayers[$i].name" "$KEYS_CONFIG")"
|
||||
echo "Adding relayer key.... $RELAYER_KEY_NAME"
|
||||
jq -r ".relayers[$i].mnemonic" "$KEYS_CONFIG" | $CHAIN_BIN keys add "$RELAYER_KEY_NAME" --recover --keyring-backend="test"
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" add-genesis-account $($CHAIN_BIN keys show -a "$RELAYER_KEY_NAME" --keyring-backend="test") "$COINS" --keyring-backend="test"
|
||||
# Add relayer-cli key and delegate tokens
|
||||
RELAYER_CLI_KEY_NAME="$(jq -r ".relayers_cli[$i].name" "$KEYS_CONFIG")"
|
||||
echo "Adding relayer-cli key.... $RELAYER_CLI_KEY_NAME"
|
||||
jq -r ".relayers_cli[$i].mnemonic" "$KEYS_CONFIG" | $CHAIN_BIN keys add "$RELAYER_CLI_KEY_NAME" --recover --keyring-backend="test"
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" add-genesis-account $($CHAIN_BIN keys show -a "$RELAYER_CLI_KEY_NAME" --keyring-backend="test") "$COINS" --keyring-backend="test"
|
||||
done
|
||||
# Check if binary has genesis subcommand
|
||||
CHAIN_GENESIS_CMD=""
|
||||
if $CHAIN_BIN 2>&1 | grep -q "genesis-related subcommands"; then
|
||||
CHAIN_GENESIS_CMD="genesis"
|
||||
fi
|
||||
|
||||
## if faucet not enabled then add validator and relayer with index as keys and into gentx
|
||||
if [[ $FAUCET_ENABLED == "false" && $NUM_VALIDATORS -gt "1" ]]; then
|
||||
## Add validators key and delegate tokens
|
||||
for i in $(seq 0 "$NUM_VALIDATORS"); do
|
||||
VAL_KEY_NAME="$(jq -r '.validators[0].name' "$KEYS_CONFIG")-$i"
|
||||
echo "Adding validator key.... $VAL_KEY_NAME"
|
||||
jq -r ".validators[0].mnemonic" "$KEYS_CONFIG" | $CHAIN_BIN keys add "$VAL_KEY_NAME" --index "$i" --recover --keyring-backend="test"
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" add-genesis-account $($CHAIN_BIN keys show -a "$VAL_KEY_NAME" --keyring-backend="test") "$COINS" --keyring-backend="test"
|
||||
done
|
||||
log_info "Creating genesis for Sonr network: $CHAIN_ID"
|
||||
|
||||
# Initialize chain
|
||||
local genesis_mnemonic
|
||||
genesis_mnemonic=$(jq -r ".genesis[0].mnemonic" "$KEYS_CONFIG")
|
||||
echo "$genesis_mnemonic" | $CHAIN_BIN init "$CHAIN_ID" --chain-id "$CHAIN_ID" --default-denom "$DENOM" --recover
|
||||
|
||||
# Add genesis accounts
|
||||
log_info "Adding genesis accounts..."
|
||||
|
||||
# Genesis key
|
||||
local genesis_key_name
|
||||
genesis_key_name=$(jq -r ".genesis[0].name" "$KEYS_CONFIG")
|
||||
import_mnemonic "$genesis_key_name" "$genesis_mnemonic"
|
||||
fund_key "$genesis_key_name" "$BASE_COINS"
|
||||
|
||||
# Faucet key
|
||||
local faucet_key_name
|
||||
faucet_key_name=$(jq -r ".faucet[0].name" "$KEYS_CONFIG")
|
||||
local faucet_mnemonic
|
||||
faucet_mnemonic=$(jq -r ".faucet[0].mnemonic" "$KEYS_CONFIG")
|
||||
import_mnemonic "$faucet_key_name" "$faucet_mnemonic"
|
||||
fund_key "$faucet_key_name" "$BASE_COINS"
|
||||
|
||||
# Test key
|
||||
local test_key_name
|
||||
test_key_name=$(jq -r ".keys[0].name" "$KEYS_CONFIG")
|
||||
local test_mnemonic
|
||||
test_mnemonic=$(jq -r ".keys[0].mnemonic" "$KEYS_CONFIG")
|
||||
import_mnemonic "$test_key_name" "$test_mnemonic"
|
||||
fund_key "$test_key_name" "$BASE_COINS"
|
||||
|
||||
# Add relayer keys if faucet is disabled
|
||||
if [[ "$FAUCET_ENABLED" == "false" && "$NUM_RELAYERS" -gt 0 ]]; then
|
||||
for i in $(seq 0 "$NUM_RELAYERS"); do
|
||||
local relayer_key_name
|
||||
relayer_key_name=$(jq -r ".relayers[$i].name" "$KEYS_CONFIG")
|
||||
local relayer_mnemonic
|
||||
relayer_mnemonic=$(jq -r ".relayers[$i].mnemonic" "$KEYS_CONFIG")
|
||||
import_mnemonic "$relayer_key_name" "$relayer_mnemonic"
|
||||
fund_key "$relayer_key_name" "$BASE_COINS"
|
||||
|
||||
local relayer_cli_key_name
|
||||
relayer_cli_key_name=$(jq -r ".relayers_cli[$i].name" "$KEYS_CONFIG")
|
||||
local relayer_cli_mnemonic
|
||||
relayer_cli_mnemonic=$(jq -r ".relayers_cli[$i].mnemonic" "$KEYS_CONFIG")
|
||||
import_mnemonic "$relayer_cli_key_name" "$relayer_cli_mnemonic"
|
||||
fund_key "$relayer_cli_key_name" "$BASE_COINS"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Creating gentx..."
|
||||
COIN=$(echo "$COINS" | cut -d ',' -f1)
|
||||
# Use full validator amount to meet minimum delegation requirement (274890886240)
|
||||
# Match the working init-testnet.sh: 1000000000000000000000snr = 1000000000000000000000000000usnr
|
||||
VALIDATOR_AMOUNT="1000000000000000000000000000$DENOM"
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" gentx $(jq -r ".genesis[0].name" "$KEYS_CONFIG") "$VALIDATOR_AMOUNT" --keyring-backend="test" --chain-id "$CHAIN_ID" --gas-prices="0$DENOM"
|
||||
# Add additional validator keys if needed
|
||||
if [[ "$FAUCET_ENABLED" == "false" && "$NUM_VALIDATORS" -gt 1 ]]; then
|
||||
for i in $(seq 1 "$NUM_VALIDATORS"); do
|
||||
local val_key_name="${genesis_key_name}-${i}"
|
||||
local val_mnemonic
|
||||
val_mnemonic=$(jq -r ".validators[0].mnemonic" "$KEYS_CONFIG")
|
||||
import_mnemonic "$val_key_name" "$val_mnemonic"
|
||||
fund_key "$val_key_name" "$BASE_COINS"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Output of gentx"
|
||||
cat "$CHAIN_DIR"/config/gentx/*.json | jq
|
||||
# Create genesis transaction
|
||||
log_info "Creating genesis transaction..."
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" gentx "$genesis_key_name" "$VALIDATOR_AMOUNT" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--chain-id "$CHAIN_ID" \
|
||||
--gas-prices "0${DENOM}"
|
||||
|
||||
echo "Running collect-gentxs"
|
||||
log_info "Genesis transaction output:"
|
||||
cat "$CHAIN_DIR/config/gentx"/*.json | jq
|
||||
|
||||
# Collect genesis transactions
|
||||
log_info "Collecting genesis transactions..."
|
||||
$CHAIN_BIN "$CHAIN_GENESIS_CMD" collect-gentxs
|
||||
|
||||
ls "$CHAIN_DIR"/config
|
||||
|
||||
# Generate VRF keypair
|
||||
echo ""
|
||||
echo "Generating VRF keypair..."
|
||||
if ! generate_vrf_key "${CHAIN_DIR}"; then
|
||||
echo "Warning: VRF key generation failed, but continuing..."
|
||||
echo "Note: Multi-validator encryption features may not work without VRF keys"
|
||||
log_info "Generating VRF keypair..."
|
||||
if ! generate_vrf_key "$CHAIN_DIR"; then
|
||||
log_warn "VRF key generation failed, but continuing..."
|
||||
log_warn "Note: Multi-validator encryption features may not work without VRF keys"
|
||||
fi
|
||||
|
||||
log_success "Genesis creation completed"
|
||||
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/create-ics.sh - Create ICS proposal for Sonr network
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper libraries
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/lib/env.sh"
|
||||
source "${SCRIPT_DIR}/lib/keys.sh"
|
||||
source "${SCRIPT_DIR}/lib/tx.sh"
|
||||
|
||||
# Initialize environment
|
||||
init_env
|
||||
|
||||
# Set defaults for ICS setup
|
||||
KEY_NAME="${KEY_NAME:-ics-setup}"
|
||||
STAKE_AMOUNT="10000000${DENOM}"
|
||||
MAX_RETRIES="${MAX_RETRIES:-3}"
|
||||
RETRY_INTERVAL="${RETRY_INTERVAL:-30}"
|
||||
|
||||
# Validate required parameters
|
||||
if [[ -z "${PROPOSAL_FILE:-}" ]]; then
|
||||
log_error "PROPOSAL_FILE environment variable is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ensure_file "$PROPOSAL_FILE"
|
||||
|
||||
log_info "Setting up ICS proposal with key '$KEY_NAME'"
|
||||
|
||||
# Import key from keys config if available
|
||||
if [[ -f "${KEYS_CONFIG:-}" ]]; then
|
||||
local key_mnemonic
|
||||
key_mnemonic=$(jq -r ".keys[0].mnemonic" "$KEYS_CONFIG" 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "$key_mnemonic" && "$key_mnemonic" != "null" ]]; then
|
||||
import_mnemonic "$KEY_NAME" "$key_mnemonic"
|
||||
else
|
||||
log_warn "No valid mnemonic found in $KEYS_CONFIG, using existing key or create one manually"
|
||||
fi
|
||||
else
|
||||
log_warn "KEYS_CONFIG not set, ensure key '$KEY_NAME' exists"
|
||||
fi
|
||||
|
||||
# Ensure key exists
|
||||
ensure_key "$KEY_NAME"
|
||||
|
||||
# Get validator address and stake tokens
|
||||
local validator_address
|
||||
validator_address=$(get_validator_address)
|
||||
|
||||
stake_tokens "$KEY_NAME" "$validator_address" "$STAKE_AMOUNT"
|
||||
|
||||
# Determine proposal command (legacy vs new)
|
||||
local submit_cmd="submit-proposal"
|
||||
if $CHAIN_BIN tx gov --help 2>/dev/null | grep -q "submit-legacy-proposal"; then
|
||||
submit_cmd="submit-legacy-proposal"
|
||||
fi
|
||||
|
||||
log_info "Using proposal command: $submit_cmd"
|
||||
|
||||
# Submit proposal
|
||||
local tx_hash
|
||||
tx_hash=$(submit_proposal "$KEY_NAME" "$PROPOSAL_FILE" "consumer-addition")
|
||||
|
||||
# Extract proposal ID from transaction
|
||||
local proposal_id
|
||||
proposal_id=$(query_chain tx "$tx_hash" | jq -r '.logs[0].events[] | select(.type=="submit_proposal").attributes[] | select(.key=="proposal_id").value // empty')
|
||||
|
||||
if [[ -z "$proposal_id" || "$proposal_id" == "null" ]]; then
|
||||
log_error "Failed to extract proposal ID from transaction"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Proposal ID: $proposal_id"
|
||||
|
||||
# Vote on proposal
|
||||
vote_proposal "$KEY_NAME" "$proposal_id" "yes"
|
||||
|
||||
# Wait for proposal to pass
|
||||
wait_for_proposal "$proposal_id" "$MAX_RETRIES" "$RETRY_INTERVAL"
|
||||
|
||||
log_success "ICS proposal setup completed successfully"
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/create-validator.sh - Create a validator for Sonr network
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper libraries
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/lib/env.sh"
|
||||
source "${SCRIPT_DIR}/lib/keys.sh"
|
||||
source "${SCRIPT_DIR}/lib/tx.sh"
|
||||
|
||||
# Initialize environment
|
||||
init_env
|
||||
|
||||
# Ensure chain directory exists
|
||||
ensure_chain_dir
|
||||
|
||||
# Set defaults for validator creation
|
||||
VAL_NAME="${VAL_NAME:-$CHAIN_ID-validator}"
|
||||
VALIDATOR_AMOUNT="5000000000${DENOM}"
|
||||
|
||||
log_info "Creating validator '$VAL_NAME' for Sonr network"
|
||||
|
||||
# Wait for node to sync
|
||||
wait_for_sync 10
|
||||
|
||||
# Get Cosmos SDK version to determine validator creation format
|
||||
set +e
|
||||
cosmos_sdk_version=$($CHAIN_BIN version --long | sed -n 's/cosmos_sdk_version: \(.*\)/\1/p')
|
||||
set -e
|
||||
|
||||
log_info "Cosmos SDK version: $cosmos_sdk_version"
|
||||
|
||||
# Create validator based on SDK version
|
||||
if [[ "$cosmos_sdk_version" > "v0.50.0" ]]; then
|
||||
log_info "Using Cosmos SDK v0.50+ validator creation format"
|
||||
|
||||
# Create validator JSON for v0.50+
|
||||
local validator_json
|
||||
validator_json=$(cat <<EOF
|
||||
{
|
||||
"pubkey": "$($CHAIN_BIN tendermint show-validator $NODE_ARGS)",
|
||||
"amount": "$VALIDATOR_AMOUNT",
|
||||
"moniker": "$VAL_NAME",
|
||||
"commission-rate": "0.1",
|
||||
"commission-max-rate": "0.2",
|
||||
"commission-max-change-rate": "0.01",
|
||||
"min-self-delegation": "1000000"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
echo "$validator_json" > /tmp/validator.json
|
||||
|
||||
# Submit validator creation transaction
|
||||
submit_tx "$VAL_NAME" staking create-validator /tmp/validator.json
|
||||
|
||||
rm -f /tmp/validator.json
|
||||
else
|
||||
log_info "Using legacy validator creation format"
|
||||
|
||||
# Check if min-self-delegation parameter is supported
|
||||
local args=""
|
||||
if $CHAIN_BIN tx staking create-validator --help 2>/dev/null | grep -q "min-self-delegation"; then
|
||||
args="--min-self-delegation=1000000"
|
||||
fi
|
||||
|
||||
# Submit validator creation transaction with legacy format
|
||||
submit_tx "$VAL_NAME" staking create-validator \
|
||||
--pubkey="$($CHAIN_BIN tendermint show-validator $NODE_ARGS)" \
|
||||
--moniker "$VAL_NAME" \
|
||||
--amount "$VALIDATOR_AMOUNT" \
|
||||
--commission-rate="0.10" \
|
||||
--commission-max-rate="0.20" \
|
||||
--commission-max-change-rate="0.01" \
|
||||
$args
|
||||
fi
|
||||
|
||||
log_success "Validator '$VAL_NAME' created successfully"
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
REGISTRY_URL="$1"
|
||||
CHAIN_1="$2"
|
||||
CHAIN_2="$3"
|
||||
|
||||
set -eux
|
||||
|
||||
function connection_id() {
|
||||
CONNECTION_ID=$(curl -s $REGISTRY_URL/ibc/$CHAIN_1/$CHAIN_2 | jq -r ".chain_1.connection_id")
|
||||
echo $CONNECTION_ID
|
||||
}
|
||||
|
||||
echo "Try to get connection id, if failed, wait for 2 seconds and try again"
|
||||
max_tries=20
|
||||
while [[ max_tries -gt 0 ]]
|
||||
do
|
||||
id=$(connection_id)
|
||||
if [[ -n "$id" ]]; then
|
||||
echo "Found connection id: $id"
|
||||
exit 0
|
||||
fi
|
||||
echo "Failed to get connection id. Sleeping for 2 secs. Tries left $max_tries"
|
||||
((max_tries--))
|
||||
sleep 10
|
||||
done
|
||||
@@ -0,0 +1,121 @@
|
||||
# Sonr Script Library
|
||||
|
||||
This directory contains modular helper scripts for Sonr blockchain operations. These helpers provide reusable functions for common tasks like environment setup, configuration management, key handling, and transaction operations.
|
||||
|
||||
## Library Structure
|
||||
|
||||
### `env.sh` - Environment Management
|
||||
Centralizes default environment variables and provides utility functions for logging, validation, and system checks.
|
||||
|
||||
**Key Functions:**
|
||||
- `init_env()` - Initialize environment with required tools and cleanup
|
||||
- `log_info()`, `log_warn()`, `log_error()`, `log_success()` - Colored logging
|
||||
- `require_cmd()`, `ensure_file()`, `ensure_binary()` - Validation helpers
|
||||
- `is_docker()` - Check if running in Docker container
|
||||
|
||||
**Environment Variables:**
|
||||
- `DENOM=usnr` - Default denomination
|
||||
- `CHAIN_BIN=snrd` - Binary name
|
||||
- `CHAIN_DIR=~/.sonr` - Chain data directory
|
||||
- `CHAIN_ID=sonrtest_1-1` - Default chain ID
|
||||
|
||||
### `jq_patch.sh` - JSON Operations
|
||||
Provides safe JSON patching operations using `jq` with temporary files and validation.
|
||||
|
||||
**Key Functions:**
|
||||
- `patch_json(file, jq_expr)` - Apply jq expression to file
|
||||
- `set_json_string()`, `set_json_number()`, `set_json_bool()` - Type-safe setters
|
||||
- `json_path_exists()`, `get_json_value()` - Query helpers
|
||||
- `validate_json()` - JSON validation
|
||||
|
||||
### `config.sh` - Configuration Management
|
||||
Handles TOML configuration files for Cosmos SDK nodes using `crudini` or `sed` fallbacks.
|
||||
|
||||
**Key Functions:**
|
||||
- `configure_node()` - Complete node configuration with ports and settings
|
||||
- `enable_rpc()`, `enable_rest()`, `enable_grpc()` - Enable services
|
||||
- `set_consensus_timeouts()`, `set_min_gas_prices()` - Parameter setters
|
||||
- `set_toml_value()` - Generic TOML value setter
|
||||
|
||||
### `keys.sh` - Key Management
|
||||
Provides functions for importing, managing, and using cryptographic keys.
|
||||
|
||||
**Key Functions:**
|
||||
- `import_mnemonic()` - Import key from mnemonic phrase
|
||||
- `ensure_key()`, `get_key_address()` - Key validation and retrieval
|
||||
- `fund_key()`, `delegate_to_validator()` - Account operations
|
||||
- `wait_for_sync()` - Node synchronization waiting
|
||||
|
||||
### `tx.sh` - Transaction Operations
|
||||
Handles blockchain transactions with error handling and retry logic.
|
||||
|
||||
**Key Functions:**
|
||||
- `submit_tx()` - Submit transaction with gas and error handling
|
||||
- `query_chain()` - Query blockchain state
|
||||
- `submit_proposal()`, `vote_proposal()` - Governance operations
|
||||
- `stake_tokens()`, `get_balance()` - Staking operations
|
||||
|
||||
### `genesis.sh` - Genesis File Operations
|
||||
Specialized functions for genesis file creation and modification.
|
||||
|
||||
**Key Functions:**
|
||||
- `generate_vrf_key()` - Generate VRF keypair for network
|
||||
- `update_genesis_params()` - Apply Sonr-specific genesis parameters
|
||||
- `add_constitution()` - Add constitution to governance
|
||||
- `validate_genesis()` - Genesis file validation
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Environment Setup
|
||||
```bash
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/lib/env.sh"
|
||||
source "${SCRIPT_DIR}/lib/config.sh"
|
||||
|
||||
init_env
|
||||
ensure_chain_dir
|
||||
configure_node "$CHAIN_DIR" --rpc-port 26657 --rest-port 1317
|
||||
```
|
||||
|
||||
### Key Management
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source "scripts/lib/keys.sh"
|
||||
import_mnemonic "mykey" "word1 word2 word3..." "eth_secp256k1"
|
||||
fund_key "mykey" "1000000usnr"
|
||||
```
|
||||
|
||||
### Genesis Creation
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source "scripts/lib/genesis.sh"
|
||||
update_genesis_params
|
||||
add_constitution
|
||||
generate_vrf_key "$CHAIN_DIR"
|
||||
```
|
||||
|
||||
## Integration Guidelines
|
||||
|
||||
1. **Always source required libraries** at the top of scripts
|
||||
2. **Call `init_env()`** early to set up logging and validation
|
||||
3. **Use consistent error handling** with the provided logging functions
|
||||
4. **Validate inputs** using `ensure_*` functions before operations
|
||||
5. **Handle Docker vs local execution** in wrapper functions
|
||||
6. **Use descriptive log messages** for user feedback
|
||||
|
||||
## Error Handling
|
||||
|
||||
All functions use consistent error handling:
|
||||
- Functions return 0 on success, 1 on failure
|
||||
- Use `log_error()` for user-visible errors
|
||||
- Use `log_warn()` for non-fatal issues
|
||||
- Cleanup temporary files automatically via `trap`
|
||||
|
||||
## Docker Compatibility
|
||||
|
||||
All functions support both local and Docker execution modes:
|
||||
- Use `is_docker()` to detect environment
|
||||
- Use `run_binary()` wrapper for command execution
|
||||
- Mount volumes correctly for Docker containers
|
||||
- Handle TTY and interactive mode appropriately
|
||||
@@ -0,0 +1,341 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/lib/config.sh - Configuration file utilities for TOML and other formats
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source environment and JSON helpers
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/env.sh"
|
||||
source "${SCRIPT_DIR}/jq_patch.sh"
|
||||
|
||||
# Check if crudini is available for TOML operations
|
||||
CRUDINI_AVAILABLE=false
|
||||
if command -v crudini >/dev/null 2>&1; then
|
||||
CRUDINI_AVAILABLE=true
|
||||
fi
|
||||
|
||||
# Set TOML value using crudini if available, fallback to sed
|
||||
# Usage: set_toml_value <file> <section> <key> <value>
|
||||
set_toml_value() {
|
||||
local file="$1"
|
||||
local section="$2"
|
||||
local key="$3"
|
||||
local value="$4"
|
||||
|
||||
ensure_file "$file"
|
||||
|
||||
if [[ "$CRUDINI_AVAILABLE" == "true" ]]; then
|
||||
if crudini --set "$file" "$section" "$key" "$value" 2>/dev/null; then
|
||||
log_success "Set $section.$key = $value in $file"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to sed for simple cases
|
||||
log_warn "Using sed fallback for TOML update (install crudini for better support)"
|
||||
|
||||
# Escape special characters in value
|
||||
local escaped_value
|
||||
escaped_value=$(printf '%s\n' "$value" | sed 's/[[\.*^$()+?{|]/\\&/g')
|
||||
|
||||
# Try to find and replace the line
|
||||
if sed -i "s|^\s*$key\s*=.*|$key = \"$escaped_value\"|g" "$file"; then
|
||||
log_success "Set $key = $value in $file (using sed)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_error "Failed to set $section.$key in $file"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Enable RPC server
|
||||
# Usage: enable_rpc <config_file> [port]
|
||||
enable_rpc() {
|
||||
local config_file="$1"
|
||||
local port="${2:-26657}"
|
||||
|
||||
ensure_file "$config_file"
|
||||
|
||||
log_info "Enabling RPC server on port $port"
|
||||
|
||||
# Update laddr
|
||||
set_toml_value "$config_file" "" "laddr" "tcp://0.0.0.0:$port"
|
||||
|
||||
# Enable CORS
|
||||
set_toml_value "$config_file" "" "cors_allowed_origins" '["*"]'
|
||||
}
|
||||
|
||||
# Enable REST API server
|
||||
# Usage: enable_rest <app_config_file> [port]
|
||||
enable_rest() {
|
||||
local app_config_file="$1"
|
||||
local port="${2:-1317}"
|
||||
|
||||
ensure_file "$app_config_file"
|
||||
|
||||
log_info "Enabling REST API server on port $port"
|
||||
|
||||
# Update address
|
||||
set_toml_value "$app_config_file" "api" "address" "tcp://0.0.0.0:$port"
|
||||
|
||||
# Enable API
|
||||
set_toml_value "$app_config_file" "api" "enable" "true"
|
||||
|
||||
# Enable unsafe CORS
|
||||
set_toml_value "$app_config_file" "api" "enabled-unsafe-cors" "true"
|
||||
}
|
||||
|
||||
# Enable gRPC server
|
||||
# Usage: enable_grpc <app_config_file> [port]
|
||||
enable_grpc() {
|
||||
local app_config_file="$1"
|
||||
local port="${2:-9090}"
|
||||
|
||||
ensure_file "$app_config_file"
|
||||
|
||||
log_info "Enabling gRPC server on port $port"
|
||||
|
||||
# Update address
|
||||
set_toml_value "$app_config_file" "grpc" "address" "0.0.0.0:$port"
|
||||
}
|
||||
|
||||
# Enable gRPC-Web server
|
||||
# Usage: enable_grpc_web <app_config_file> [port]
|
||||
enable_grpc_web() {
|
||||
local app_config_file="$1"
|
||||
local port="${2:-9091}"
|
||||
|
||||
ensure_file "$app_config_file"
|
||||
|
||||
log_info "Enabling gRPC-Web server on port $port"
|
||||
|
||||
# Update address
|
||||
set_toml_value "$app_config_file" "grpc-web" "address" "0.0.0.0:$port"
|
||||
}
|
||||
|
||||
# Enable JSON-RPC
|
||||
# Usage: enable_json_rpc <app_config_file> [port] [ws_port]
|
||||
enable_json_rpc() {
|
||||
local app_config_file="$1"
|
||||
local port="${2:-8545}"
|
||||
local ws_port="${3:-8546}"
|
||||
|
||||
ensure_file "$app_config_file"
|
||||
|
||||
log_info "Enabling JSON-RPC on port $port (WebSocket: $ws_port)"
|
||||
|
||||
# Enable JSON-RPC
|
||||
set_toml_value "$app_config_file" "json-rpc" "enable" "true"
|
||||
|
||||
# Set address
|
||||
set_toml_value "$app_config_file" "json-rpc" "address" "0.0.0.0:$port"
|
||||
|
||||
# Set WebSocket address
|
||||
set_toml_value "$app_config_file" "json-rpc" "ws-address" "0.0.0.0:$ws_port"
|
||||
|
||||
# Enable APIs
|
||||
set_toml_value "$app_config_file" "json-rpc" "api" "eth,txpool,personal,net,debug,web3"
|
||||
}
|
||||
|
||||
# Enable Rosetta API
|
||||
# Usage: enable_rosetta <app_config_file> [port]
|
||||
enable_rosetta() {
|
||||
local app_config_file="$1"
|
||||
local port="${2:-8080}"
|
||||
|
||||
ensure_file "$app_config_file"
|
||||
|
||||
log_info "Enabling Rosetta API on port $port"
|
||||
|
||||
# Update address
|
||||
set_toml_value "$app_config_file" "rosetta" "address" "0.0.0.0:$port"
|
||||
}
|
||||
|
||||
# Set consensus timeouts
|
||||
# Usage: set_consensus_timeouts <config_file> [propose] [prevote] [precommit] [commit]
|
||||
set_consensus_timeouts() {
|
||||
local config_file="$1"
|
||||
local timeout_propose="${2:-5s}"
|
||||
local timeout_prevote="${3:-1s}"
|
||||
local timeout_precommit="${4:-1s}"
|
||||
local timeout_commit="${5:-5s}"
|
||||
|
||||
ensure_file "$config_file"
|
||||
|
||||
log_info "Setting consensus timeouts: propose=$timeout_propose, prevote=$timeout_prevote, precommit=$timeout_precommit, commit=$timeout_commit"
|
||||
|
||||
set_toml_value "$config_file" "consensus" "timeout_propose" "$timeout_propose"
|
||||
set_toml_value "$config_file" "consensus" "timeout_prevote" "$timeout_prevote"
|
||||
set_toml_value "$config_file" "consensus" "timeout_precommit" "$timeout_precommit"
|
||||
set_toml_value "$config_file" "consensus" "timeout_commit" "$timeout_commit"
|
||||
}
|
||||
|
||||
# Set pruning strategy
|
||||
# Usage: set_pruning <app_config_file> [strategy]
|
||||
set_pruning() {
|
||||
local app_config_file="$1"
|
||||
local strategy="${2:-default}"
|
||||
|
||||
ensure_file "$app_config_file"
|
||||
|
||||
log_info "Setting pruning strategy to $strategy"
|
||||
|
||||
set_toml_value "$app_config_file" "pruning" "strategy" "$strategy"
|
||||
}
|
||||
|
||||
# Set minimum gas prices
|
||||
# Usage: set_min_gas_prices <app_config_file> [price]
|
||||
set_min_gas_prices() {
|
||||
local app_config_file="$1"
|
||||
local price="${2:-0${DENOM}}"
|
||||
|
||||
ensure_file "$app_config_file"
|
||||
|
||||
log_info "Setting minimum gas prices to $price"
|
||||
|
||||
set_toml_value "$app_config_file" "minimum-gas-prices" "minimum-gas-prices" "$price"
|
||||
}
|
||||
|
||||
# Enable metrics
|
||||
# Usage: enable_metrics <config_file> [retention_time]
|
||||
enable_metrics() {
|
||||
local config_file="$1"
|
||||
local retention_time="${2:-3600}"
|
||||
|
||||
ensure_file "$config_file"
|
||||
|
||||
log_info "Enabling metrics with retention time ${retention_time}s"
|
||||
|
||||
# Enable prometheus in config.toml
|
||||
set_toml_value "$config_file" "instrumentation" "prometheus" "true"
|
||||
|
||||
# Set retention time in app.toml
|
||||
if [[ -f "$config_file" ]]; then
|
||||
set_toml_value "$config_file" "telemetry" "prometheus-retention-time" "$retention_time"
|
||||
fi
|
||||
}
|
||||
|
||||
# Set keyring backend
|
||||
# Usage: set_keyring_backend <client_config_file> [backend]
|
||||
set_keyring_backend() {
|
||||
local client_config_file="$1"
|
||||
local backend="${2:-test}"
|
||||
|
||||
ensure_file "$client_config_file"
|
||||
|
||||
log_info "Setting keyring backend to $backend"
|
||||
|
||||
set_toml_value "$client_config_file" "keyring-backend" "keyring-backend" "$backend"
|
||||
}
|
||||
|
||||
# Set chain ID in client config
|
||||
# Usage: set_client_chain_id <client_config_file> [chain_id]
|
||||
set_client_chain_id() {
|
||||
local client_config_file="$1"
|
||||
local chain_id="${2:-$CHAIN_ID}"
|
||||
|
||||
ensure_file "$client_config_file"
|
||||
|
||||
log_info "Setting client chain ID to $chain_id"
|
||||
|
||||
set_toml_value "$client_config_file" "chain-id" "chain-id" "$chain_id"
|
||||
}
|
||||
|
||||
# Set client output format
|
||||
# Usage: set_client_output <client_config_file> [format]
|
||||
set_client_output() {
|
||||
local client_config_file="$1"
|
||||
local format="${2:-json}"
|
||||
|
||||
ensure_file "$client_config_file"
|
||||
|
||||
log_info "Setting client output format to $format"
|
||||
|
||||
set_toml_value "$client_config_file" "output" "output" "$format"
|
||||
}
|
||||
|
||||
# Configure full node settings
|
||||
# Usage: configure_node <config_dir> [options...]
|
||||
configure_node() {
|
||||
local config_dir="$1"
|
||||
shift
|
||||
|
||||
ensure_chain_dir
|
||||
|
||||
local config_toml="$config_dir/config/config.toml"
|
||||
local app_toml="$config_dir/config/app.toml"
|
||||
local client_toml="$config_dir/config/client.toml"
|
||||
|
||||
log_info "Configuring node in $config_dir"
|
||||
|
||||
# Apply configurations based on arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--rpc-port)
|
||||
enable_rpc "$config_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--rest-port)
|
||||
enable_rest "$app_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--grpc-port)
|
||||
enable_grpc "$app_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--grpc-web-port)
|
||||
enable_grpc_web "$app_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--json-rpc-port)
|
||||
enable_json_rpc "$app_toml" "$2" "$3"
|
||||
shift 3
|
||||
;;
|
||||
--rosetta-port)
|
||||
enable_rosetta "$app_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--consensus-timeouts)
|
||||
set_consensus_timeouts "$config_toml" "$2" "$3" "$4" "$5"
|
||||
shift 5
|
||||
;;
|
||||
--pruning)
|
||||
set_pruning "$app_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--min-gas-prices)
|
||||
set_min_gas_prices "$app_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--metrics)
|
||||
enable_metrics "$config_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--keyring-backend)
|
||||
set_keyring_backend "$client_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--chain-id)
|
||||
set_client_chain_id "$client_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
--output-format)
|
||||
set_client_output "$client_toml" "$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown configuration option: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_success "Node configuration completed"
|
||||
}
|
||||
|
||||
# Export functions
|
||||
export -f set_toml_value enable_rpc enable_rest enable_grpc enable_grpc_web
|
||||
export -f enable_json_rpc enable_rosetta set_consensus_timeouts set_pruning
|
||||
export -f set_min_gas_prices enable_metrics set_keyring_backend set_client_chain_id
|
||||
export -f set_client_output configure_node
|
||||
@@ -0,0 +1,141 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/lib/env.sh - Environment defaults and utility functions for Sonr scripts
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Default environment variables for Sonr
|
||||
export DENOM="${DENOM:=usnr}"
|
||||
export CHAIN_BIN="${CHAIN_BIN:=snrd}"
|
||||
export CHAIN_DIR="${CHAIN_DIR:=$HOME/.sonr}"
|
||||
export CHAIN_ID="${CHAIN_ID:=sonrtest_1-1}"
|
||||
export KEYRING_BACKEND="${KEYRING_BACKEND:=test}"
|
||||
export NODE_URL="${NODE_URL:=http://0.0.0.0:26657}"
|
||||
export GAS="${GAS:=auto}"
|
||||
export GAS_ADJUSTMENT="${GAS_ADJUSTMENT:=1.5}"
|
||||
|
||||
# Colors for logging
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $*"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $*"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $*"
|
||||
}
|
||||
|
||||
# Utility functions
|
||||
require_cmd() {
|
||||
local cmd="$1"
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
log_error "Required command '$cmd' not found. Please install it."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
join_path() {
|
||||
local base="$1"
|
||||
local path="$2"
|
||||
echo "$base/$path" | sed 's#//#/#g'
|
||||
}
|
||||
|
||||
# Check if running in Docker
|
||||
is_docker() {
|
||||
[[ -f /.dockerenv ]] || [[ -n "${DOCKER_CONTAINER:-}" ]]
|
||||
}
|
||||
|
||||
# Get absolute path
|
||||
abs_path() {
|
||||
local path="$1"
|
||||
if [[ -d "$path" ]]; then
|
||||
cd "$path" && pwd
|
||||
else
|
||||
cd "$(dirname "$path")" && echo "$(pwd)/$(basename "$path")"
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate chain directory exists
|
||||
ensure_chain_dir() {
|
||||
if [[ ! -d "$CHAIN_DIR" ]]; then
|
||||
log_error "Chain directory does not exist: $CHAIN_DIR"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate binary exists
|
||||
ensure_binary() {
|
||||
if ! command -v "$CHAIN_BIN" >/dev/null 2>&1; then
|
||||
log_error "Binary '$CHAIN_BIN' not found in PATH"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if file exists
|
||||
ensure_file() {
|
||||
local file="$1"
|
||||
if [[ ! -f "$file" ]]; then
|
||||
log_error "Required file not found: $file"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Retry function for operations that might fail
|
||||
retry() {
|
||||
local max_attempts="$1"
|
||||
local delay="$2"
|
||||
local cmd="$3"
|
||||
shift 3
|
||||
|
||||
local attempt=1
|
||||
while [[ $attempt -le $max_attempts ]]; do
|
||||
log_info "Attempt $attempt/$max_attempts: $cmd $*"
|
||||
if "$cmd" "$@"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ $attempt -lt $max_attempts ]]; then
|
||||
log_warn "Command failed, retrying in ${delay}s..."
|
||||
sleep "$delay"
|
||||
fi
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
log_error "Command failed after $max_attempts attempts: $cmd $*"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Initialize environment
|
||||
init_env() {
|
||||
require_cmd jq
|
||||
ensure_binary
|
||||
|
||||
# Set up cleanup trap
|
||||
trap cleanup EXIT
|
||||
|
||||
log_info "Environment initialized for Sonr chain: $CHAIN_ID"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
# Remove temporary files if they exist
|
||||
rm -f /tmp/genesis.json /tmp/config.toml /tmp/app.toml /tmp/client.toml
|
||||
}
|
||||
|
||||
# Export functions for use in other scripts
|
||||
export -f log_info log_warn log_error log_success
|
||||
export -f require_cmd join_path is_docker abs_path
|
||||
export -f ensure_chain_dir ensure_binary ensure_file
|
||||
export -f retry init_env cleanup
|
||||
@@ -0,0 +1,210 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/lib/genesis.sh - Genesis file utilities for Sonr scripts
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source environment and JSON helpers
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/env.sh"
|
||||
source "${SCRIPT_DIR}/jq_patch.sh"
|
||||
|
||||
# Generate VRF keypair for the network
|
||||
# Usage: generate_vrf_key [chain_dir]
|
||||
generate_vrf_key() {
|
||||
local chain_dir="${1:-$CHAIN_DIR}"
|
||||
|
||||
ensure_chain_dir
|
||||
|
||||
local genesis_file="$chain_dir/config/genesis.json"
|
||||
ensure_file "$genesis_file"
|
||||
|
||||
local chain_id
|
||||
chain_id=$(get_json_value "$genesis_file" '.chain_id')
|
||||
|
||||
if [[ -z "$chain_id" || "$chain_id" == "null" ]]; then
|
||||
log_error "Failed to extract chain-id from genesis file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Generating VRF keypair for network: $chain_id"
|
||||
|
||||
# Create deterministic entropy from chain-id using SHA256
|
||||
local entropy_seed
|
||||
entropy_seed=$(echo -n "$chain_id" | sha256sum | cut -d' ' -f1)
|
||||
|
||||
# Generate 64 bytes of deterministic randomness
|
||||
local seed_part1="$entropy_seed"
|
||||
local seed_part2
|
||||
seed_part2=$(echo -n "$entropy_seed" | sha256sum | cut -d' ' -f1)
|
||||
|
||||
# Combine to create 64 bytes of hex data
|
||||
local vrf_key_hex="${seed_part1}${seed_part2}"
|
||||
|
||||
# Ensure we have exactly 128 hex characters (64 bytes)
|
||||
if [[ ${#vrf_key_hex} -ne 128 ]]; then
|
||||
log_error "Generated VRF key has incorrect size: ${#vrf_key_hex}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Path to store VRF secret key
|
||||
local vrf_key_path="$chain_dir/vrf_secret.key"
|
||||
|
||||
# Ensure directory exists
|
||||
mkdir -p "$chain_dir"
|
||||
|
||||
# Convert hex to binary and write to file
|
||||
echo -n "$vrf_key_hex" | xxd -r -p > "$vrf_key_path"
|
||||
|
||||
# Set restrictive permissions (owner read/write only)
|
||||
chmod 0600 "$vrf_key_path"
|
||||
|
||||
# Validate file was created with correct size (64 bytes)
|
||||
local file_size
|
||||
file_size=$(wc -c < "$vrf_key_path")
|
||||
|
||||
if [[ $file_size -ne 64 ]]; then
|
||||
log_error "VRF key file has incorrect size: ${file_size} bytes"
|
||||
rm -f "$vrf_key_path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "VRF keypair generated for network: $chain_id"
|
||||
log_success "VRF secret key stored securely: $vrf_key_path"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Update genesis with Sonr-specific parameters
|
||||
# Usage: update_genesis_params [genesis_file]
|
||||
update_genesis_params() {
|
||||
local genesis_file="${1:-$CHAIN_DIR/config/genesis.json}"
|
||||
|
||||
ensure_file "$genesis_file"
|
||||
|
||||
log_info "Updating genesis parameters for Sonr"
|
||||
|
||||
# Update stake denomination
|
||||
set_json_string "$genesis_file" 'app_state.staking.params.bond_denom' "$DENOM"
|
||||
|
||||
# Update mint denomination
|
||||
set_json_string "$genesis_file" 'app_state.mint.params.mint_denom' "$DENOM"
|
||||
|
||||
# Update crisis fee
|
||||
set_json_object "$genesis_file" 'app_state.crisis.constant_fee' "{\"denom\":\"$DENOM\",\"amount\":\"1000\"}"
|
||||
|
||||
# Update minimum commission rate
|
||||
set_json_string "$genesis_file" 'app_state.staking.params.min_commission_rate' "0.050000000000000000"
|
||||
|
||||
# Update block max gas
|
||||
set_json_string "$genesis_file" 'consensus.params.block.max_gas' "100000000000"
|
||||
|
||||
# Update unbonding time
|
||||
set_json_string "$genesis_file" 'app_state.staking.params.unbonding_time' "300s"
|
||||
|
||||
# Update downtime jail duration
|
||||
set_json_string "$genesis_file" 'app_state.slashing.params.downtime_jail_duration' "60s"
|
||||
|
||||
# Update governance parameters for SDK v0.47+
|
||||
if json_path_exists "$genesis_file" '.app_state.gov.params'; then
|
||||
set_json_string "$genesis_file" 'app_state.gov.params.max_deposit_period' "30s"
|
||||
set_json_string "$genesis_file" 'app_state.gov.params.min_deposit[0].amount' "10"
|
||||
set_json_string "$genesis_file" 'app_state.gov.params.voting_period' "30s"
|
||||
set_json_string "$genesis_file" 'app_state.gov.params.quorum' "0.000000000000000000"
|
||||
set_json_string "$genesis_file" 'app_state.gov.params.threshold' "0.000000000000000000"
|
||||
set_json_string "$genesis_file" 'app_state.gov.params.veto_threshold' "0.000000000000000000"
|
||||
fi
|
||||
|
||||
# Update EVM parameters if present
|
||||
if json_path_exists "$genesis_file" '.app_state.evm'; then
|
||||
set_json_string "$genesis_file" 'app_state.evm.params.evm_denom' "$DENOM"
|
||||
set_json_object "$genesis_file" 'app_state.evm.params.active_static_precompiles' '["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805"]'
|
||||
fi
|
||||
|
||||
# Update ERC20 parameters if present
|
||||
if json_path_exists "$genesis_file" '.app_state.erc20'; then
|
||||
set_json_object "$genesis_file" 'app_state.erc20.params.native_precompiles' '["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]'
|
||||
set_json_object "$genesis_file" 'app_state.erc20.token_pairs' '[{"contract_owner":1,"erc20_address":"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE","denom":"'"$DENOM"'","enabled":true}]'
|
||||
fi
|
||||
|
||||
# Update feemarket parameters if present
|
||||
if json_path_exists "$genesis_file" '.app_state.feemarket'; then
|
||||
set_json_bool "$genesis_file" 'app_state.feemarket.params.no_base_fee' true
|
||||
set_json_string "$genesis_file" 'app_state.feemarket.params.base_fee' "0.000000000000000000"
|
||||
fi
|
||||
|
||||
# Update tokenfactory parameters if present
|
||||
if json_path_exists "$genesis_file" '.app_state.tokenfactory'; then
|
||||
set_json_object "$genesis_file" 'app_state.tokenfactory.params.denom_creation_fee' '[]'
|
||||
set_json_number "$genesis_file" 'app_state.tokenfactory.params.denom_creation_gas_consume' 100000
|
||||
fi
|
||||
|
||||
# Update ABCI parameters if present
|
||||
if json_path_exists "$genesis_file" '.consensus.params.abci'; then
|
||||
set_json_string "$genesis_file" 'consensus.params.abci.vote_extensions_enable_height' "1"
|
||||
fi
|
||||
|
||||
log_success "Genesis parameters updated for Sonr"
|
||||
}
|
||||
|
||||
# Add constitution to governance if CONSTITUTION.md exists
|
||||
# Usage: add_constitution [genesis_file] [constitution_file]
|
||||
add_constitution() {
|
||||
local genesis_file="${1:-$CHAIN_DIR/config/genesis.json}"
|
||||
local constitution_file="${2:-CONSTITUTION.md}"
|
||||
|
||||
ensure_file "$genesis_file"
|
||||
|
||||
# Look for CONSTITUTION.md in the git root directory
|
||||
local script_dir
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local git_root
|
||||
git_root="$(cd "${script_dir}/.." && pwd)"
|
||||
local constitution_path="$git_root/$constitution_file"
|
||||
|
||||
if [[ ! -f "$constitution_path" ]]; then
|
||||
log_warn "Constitution file not found: $constitution_path"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Adding constitution from: $constitution_path"
|
||||
|
||||
local constitution_content
|
||||
constitution_content=$(cat "$constitution_path" | jq -Rs .)
|
||||
|
||||
set_json_object "$genesis_file" 'app_state.gov.constitution' "$constitution_content"
|
||||
|
||||
log_success "Constitution added to governance"
|
||||
}
|
||||
|
||||
# Validate genesis file
|
||||
# Usage: validate_genesis [genesis_file]
|
||||
validate_genesis() {
|
||||
local genesis_file="${1:-$CHAIN_DIR/config/genesis.json}"
|
||||
|
||||
ensure_file "$genesis_file"
|
||||
|
||||
log_info "Validating genesis file..."
|
||||
|
||||
# Validate JSON
|
||||
validate_json "$genesis_file"
|
||||
|
||||
# Check required fields
|
||||
local chain_id
|
||||
chain_id=$(get_json_value "$genesis_file" '.chain_id')
|
||||
if [[ -z "$chain_id" || "$chain_id" == "null" ]]; then
|
||||
log_error "Genesis file missing chain_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check app_state exists
|
||||
if ! json_path_exists "$genesis_file" '.app_state'; then
|
||||
log_error "Genesis file missing app_state"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "Genesis file validation passed"
|
||||
}
|
||||
|
||||
# Export functions
|
||||
export -f generate_vrf_key update_genesis_params add_constitution validate_genesis
|
||||
@@ -0,0 +1,154 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/lib/jq_patch.sh - JSON patching utilities for genesis and config files
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source environment helpers
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/env.sh"
|
||||
|
||||
# Patch JSON file with jq expression and save to temp file then move back
|
||||
# Usage: patch_json <file> <jq_expression>
|
||||
patch_json() {
|
||||
local file="$1"
|
||||
local jq_expr="$2"
|
||||
|
||||
ensure_file "$file"
|
||||
|
||||
log_info "Patching $file with: $jq_expr"
|
||||
|
||||
# Create temp file in same directory to avoid cross-filesystem issues
|
||||
local temp_file
|
||||
temp_file="$(dirname "$file")/.tmp.$(basename "$file").$$"
|
||||
|
||||
if ! jq -r "$jq_expr" "$file" > "$temp_file" 2>/dev/null; then
|
||||
rm -f "$temp_file"
|
||||
log_error "Failed to patch JSON file: $file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mv "$temp_file" "$file"
|
||||
log_success "Successfully patched $file"
|
||||
}
|
||||
|
||||
# Ensure array contains specific value
|
||||
# Usage: ensure_array_contains <file> <path> <value>
|
||||
ensure_array_contains() {
|
||||
local file="$1"
|
||||
local path="$2"
|
||||
local value="$3"
|
||||
|
||||
ensure_file "$file"
|
||||
|
||||
local current_value
|
||||
current_value=$(jq -r "$path // []" "$file")
|
||||
|
||||
# Check if value already exists
|
||||
if [[ "$current_value" == *"\"$value\""* ]]; then
|
||||
log_info "Value '$value' already exists in $path"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Add value to array
|
||||
local jq_expr
|
||||
jq_expr=".${path} += [\"$value\"]"
|
||||
|
||||
patch_json "$file" "$jq_expr"
|
||||
}
|
||||
|
||||
# Set string value at path
|
||||
# Usage: set_json_string <file> <path> <value>
|
||||
set_json_string() {
|
||||
local file="$1"
|
||||
local path="$2"
|
||||
local value="$3"
|
||||
|
||||
local jq_expr
|
||||
jq_expr=".${path} = \"$value\""
|
||||
|
||||
patch_json "$file" "$jq_expr"
|
||||
}
|
||||
|
||||
# Set numeric value at path
|
||||
# Usage: set_json_number <file> <path> <value>
|
||||
set_json_number() {
|
||||
local file="$1"
|
||||
local path="$2"
|
||||
local value="$3"
|
||||
|
||||
local jq_expr
|
||||
jq_expr=".${path} = $value"
|
||||
|
||||
patch_json "$file" "$jq_expr"
|
||||
}
|
||||
|
||||
# Set boolean value at path
|
||||
# Usage: set_json_bool <file> <path> <value>
|
||||
set_json_bool() {
|
||||
local file="$1"
|
||||
local path="$2"
|
||||
local value="$3"
|
||||
|
||||
local jq_expr
|
||||
jq_expr=".${path} = $value"
|
||||
|
||||
patch_json "$file" "$jq_expr"
|
||||
}
|
||||
|
||||
# Set object value at path
|
||||
# Usage: set_json_object <file> <path> <json_object>
|
||||
set_json_object() {
|
||||
local file="$1"
|
||||
local path="$2"
|
||||
local json_object="$3"
|
||||
|
||||
local jq_expr
|
||||
jq_expr=".${path} = $json_object"
|
||||
|
||||
patch_json "$file" "$jq_expr"
|
||||
}
|
||||
|
||||
# Check if path exists and is not null
|
||||
# Usage: json_path_exists <file> <path>
|
||||
json_path_exists() {
|
||||
local file="$1"
|
||||
local path="$2"
|
||||
|
||||
ensure_file "$file"
|
||||
|
||||
local result
|
||||
result=$(jq -r "$path // empty" "$file" 2>/dev/null)
|
||||
|
||||
[[ -n "$result" && "$result" != "null" ]]
|
||||
}
|
||||
|
||||
# Get value at path
|
||||
# Usage: get_json_value <file> <path>
|
||||
get_json_value() {
|
||||
local file="$1"
|
||||
local path="$2"
|
||||
|
||||
ensure_file "$file"
|
||||
|
||||
jq -r "$path" "$file"
|
||||
}
|
||||
|
||||
# Validate JSON file
|
||||
# Usage: validate_json <file>
|
||||
validate_json() {
|
||||
local file="$1"
|
||||
|
||||
ensure_file "$file"
|
||||
|
||||
if ! jq empty "$file" >/dev/null 2>&1; then
|
||||
log_error "Invalid JSON in file: $file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "JSON validation passed for $file"
|
||||
}
|
||||
|
||||
# Export functions
|
||||
export -f patch_json ensure_array_contains set_json_string set_json_number
|
||||
export -f set_json_bool set_json_object json_path_exists get_json_value validate_json
|
||||
@@ -0,0 +1,211 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/lib/keys.sh - Key management utilities for Sonr scripts
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source environment helpers
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/env.sh"
|
||||
|
||||
# Import mnemonic and add key to keyring
|
||||
# Usage: import_mnemonic <key_name> <mnemonic> [algo]
|
||||
import_mnemonic() {
|
||||
local key_name="$1"
|
||||
local mnemonic="$2"
|
||||
local algo="${3:-eth_secp256k1}"
|
||||
|
||||
log_info "Importing key '$key_name'"
|
||||
|
||||
if [[ -z "$mnemonic" ]]; then
|
||||
log_error "Mnemonic cannot be empty"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Use Docker wrapper if needed
|
||||
if is_docker; then
|
||||
echo "$mnemonic" | $CHAIN_BIN keys add "$key_name" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--algo "$algo" \
|
||||
--recover
|
||||
else
|
||||
echo "$mnemonic" | $CHAIN_BIN keys add "$key_name" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--algo "$algo" \
|
||||
--home "$CHAIN_DIR" \
|
||||
--recover
|
||||
fi
|
||||
|
||||
log_success "Key '$key_name' imported successfully"
|
||||
}
|
||||
|
||||
# Ensure key exists in keyring
|
||||
# Usage: ensure_key <key_name>
|
||||
ensure_key() {
|
||||
local key_name="$1"
|
||||
|
||||
if ! $CHAIN_BIN keys show "$key_name" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--home "$CHAIN_DIR" \
|
||||
--output json >/dev/null 2>&1; then
|
||||
|
||||
log_error "Key '$key_name' not found in keyring"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Key '$key_name' exists in keyring"
|
||||
}
|
||||
|
||||
# Get key address
|
||||
# Usage: get_key_address <key_name>
|
||||
get_key_address() {
|
||||
local key_name="$1"
|
||||
|
||||
ensure_key "$key_name"
|
||||
|
||||
local address
|
||||
address=$($CHAIN_BIN keys show "$key_name" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--home "$CHAIN_DIR" \
|
||||
--output json | jq -r '.address')
|
||||
|
||||
if [[ -z "$address" || "$address" == "null" ]]; then
|
||||
log_error "Failed to get address for key '$key_name'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$address"
|
||||
}
|
||||
|
||||
# Fund key with tokens from genesis
|
||||
# Usage: fund_key <key_name> <amount>
|
||||
fund_key() {
|
||||
local key_name="$1"
|
||||
local amount="$2"
|
||||
|
||||
ensure_key "$key_name"
|
||||
|
||||
local address
|
||||
address=$(get_key_address "$key_name")
|
||||
|
||||
log_info "Funding key '$key_name' ($address) with $amount"
|
||||
|
||||
if is_docker; then
|
||||
$CHAIN_BIN genesis add-genesis-account "$address" "$amount" \
|
||||
--keyring-backend "$KEYRING_BACKEND"
|
||||
else
|
||||
$CHAIN_BIN genesis add-genesis-account "$address" "$amount" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--home "$CHAIN_DIR"
|
||||
fi
|
||||
|
||||
log_success "Funded key '$key_name' with $amount"
|
||||
}
|
||||
|
||||
# Delegate tokens to validator
|
||||
# Usage: delegate_to_validator <delegator_key> <validator_address> <amount>
|
||||
delegate_to_validator() {
|
||||
local delegator_key="$1"
|
||||
local validator_address="$2"
|
||||
local amount="$3"
|
||||
|
||||
ensure_key "$delegator_key"
|
||||
|
||||
log_info "Delegating $amount from '$delegator_key' to validator $validator_address"
|
||||
|
||||
$CHAIN_BIN tx staking delegate "$validator_address" "$amount" \
|
||||
--from "$delegator_key" \
|
||||
--chain-id "$CHAIN_ID" \
|
||||
--node "$NODE_URL" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--gas "$GAS" \
|
||||
--gas-adjustment "$GAS_ADJUSTMENT" \
|
||||
--yes
|
||||
|
||||
log_success "Delegation completed"
|
||||
}
|
||||
|
||||
# Create validator with key
|
||||
# Usage: create_validator <key_name> <moniker> <amount> [options...]
|
||||
create_validator() {
|
||||
local key_name="$1"
|
||||
local moniker="$2"
|
||||
local amount="$3"
|
||||
shift 3
|
||||
|
||||
ensure_key "$key_name"
|
||||
|
||||
local validator_address
|
||||
validator_address=$(get_key_address "$key_name")
|
||||
|
||||
log_info "Creating validator '$moniker' with key '$key_name'"
|
||||
|
||||
# Build validator JSON
|
||||
local validator_json
|
||||
validator_json=$(cat <<EOF
|
||||
{
|
||||
"pubkey": "$($CHAIN_BIN tendermint show-validator)",
|
||||
"amount": "$amount",
|
||||
"moniker": "$moniker",
|
||||
"commission-rate": "0.1",
|
||||
"commission-max-rate": "0.2",
|
||||
"commission-max-change-rate": "0.01",
|
||||
"min-self-delegation": "1000000"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
echo "$validator_json" > /tmp/validator.json
|
||||
|
||||
$CHAIN_BIN tx staking create-validator /tmp/validator.json \
|
||||
--from "$key_name" \
|
||||
--chain-id "$CHAIN_ID" \
|
||||
--node "$NODE_URL" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--gas "$GAS" \
|
||||
--gas-adjustment "$GAS_ADJUSTMENT" \
|
||||
--yes
|
||||
|
||||
rm -f /tmp/validator.json
|
||||
|
||||
log_success "Validator '$moniker' created successfully"
|
||||
}
|
||||
|
||||
# Wait for node to sync
|
||||
# Usage: wait_for_sync [max_tries]
|
||||
wait_for_sync() {
|
||||
local max_tries="${1:-10}"
|
||||
|
||||
log_info "Waiting for node to sync..."
|
||||
|
||||
local tries=0
|
||||
while [[ $tries -lt $max_tries ]]; do
|
||||
if $CHAIN_BIN status \
|
||||
--node "$NODE_URL" \
|
||||
--output json 2>/dev/null | jq -e '.SyncInfo.catching_up == false' >/dev/null 2>&1; then
|
||||
|
||||
log_success "Node is synced"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Still syncing... ($((tries + 1))/$max_tries)"
|
||||
sleep 30
|
||||
((tries++))
|
||||
done
|
||||
|
||||
log_error "Node failed to sync after $max_tries attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# List keys in keyring
|
||||
# Usage: list_keys
|
||||
list_keys() {
|
||||
$CHAIN_BIN keys list \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--home "$CHAIN_DIR" \
|
||||
--output json | jq
|
||||
}
|
||||
|
||||
# Export functions
|
||||
export -f import_mnemonic ensure_key get_key_address fund_key
|
||||
export -f delegate_to_validator create_validator wait_for_sync list_keys
|
||||
@@ -0,0 +1,228 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/lib/tx.sh - Transaction utilities for Sonr scripts
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source environment and key helpers
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/env.sh"
|
||||
source "${SCRIPT_DIR}/keys.sh"
|
||||
|
||||
# Submit transaction with automatic gas and error handling
|
||||
# Usage: submit_tx <from_key> <command...>
|
||||
submit_tx() {
|
||||
local from_key="$1"
|
||||
shift
|
||||
|
||||
ensure_key "$from_key"
|
||||
|
||||
log_info "Submitting transaction from '$from_key': $*"
|
||||
|
||||
local tx_result
|
||||
tx_result=$($CHAIN_BIN tx "$@" \
|
||||
--from "$from_key" \
|
||||
--chain-id "$CHAIN_ID" \
|
||||
--node "$NODE_URL" \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--gas "$GAS" \
|
||||
--gas-adjustment "$GAS_ADJUSTMENT" \
|
||||
--output json \
|
||||
--yes 2>&1)
|
||||
|
||||
# Check for transaction hash
|
||||
local tx_hash
|
||||
tx_hash=$(echo "$tx_result" | jq -r '.txhash // empty')
|
||||
|
||||
if [[ -n "$tx_hash" && "$tx_hash" != "null" ]]; then
|
||||
log_success "Transaction submitted: $tx_hash"
|
||||
|
||||
# Wait for confirmation
|
||||
sleep 5
|
||||
|
||||
# Query transaction result
|
||||
local tx_query
|
||||
tx_query=$($CHAIN_BIN query tx "$tx_hash" \
|
||||
--node "$NODE_URL" \
|
||||
--output json 2>/dev/null)
|
||||
|
||||
local tx_code
|
||||
tx_code=$(echo "$tx_query" | jq -r '.code // 0')
|
||||
|
||||
if [[ "$tx_code" == "0" ]]; then
|
||||
log_success "Transaction confirmed successfully"
|
||||
echo "$tx_hash"
|
||||
return 0
|
||||
else
|
||||
local tx_log
|
||||
tx_log=$(echo "$tx_query" | jq -r '.raw_log // "Unknown error"')
|
||||
log_error "Transaction failed (code $tx_code): $tx_log"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_error "Transaction submission failed: $tx_result"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Query with error handling
|
||||
# Usage: query_chain <command...>
|
||||
query_chain() {
|
||||
log_info "Querying chain: $*"
|
||||
|
||||
local result
|
||||
result=$($CHAIN_BIN query "$@" \
|
||||
--node "$NODE_URL" \
|
||||
--output json 2>/dev/null)
|
||||
|
||||
if [[ -z "$result" || "$result" == "null" ]]; then
|
||||
log_error "Query failed or returned null"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Get validator address (first available)
|
||||
# Usage: get_validator_address
|
||||
get_validator_address() {
|
||||
log_info "Getting validator address..."
|
||||
|
||||
local validators
|
||||
validators=$(query_chain staking validators)
|
||||
|
||||
local validator_address
|
||||
validator_address=$(echo "$validators" | jq -r '.validators[0].operator_address // empty')
|
||||
|
||||
if [[ -z "$validator_address" || "$validator_address" == "null" ]]; then
|
||||
log_error "No validators found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "Using validator: $validator_address"
|
||||
echo "$validator_address"
|
||||
}
|
||||
|
||||
# Submit governance proposal
|
||||
# Usage: submit_proposal <from_key> <proposal_file> [proposal_type]
|
||||
submit_proposal() {
|
||||
local from_key="$1"
|
||||
local proposal_file="$2"
|
||||
local proposal_type="${3:-}"
|
||||
|
||||
ensure_file "$proposal_file"
|
||||
ensure_key "$from_key"
|
||||
|
||||
log_info "Submitting governance proposal from '$from_key'"
|
||||
|
||||
local submit_cmd="submit-proposal"
|
||||
if [[ -n "$proposal_type" ]]; then
|
||||
submit_cmd="$submit_cmd $proposal_type"
|
||||
fi
|
||||
|
||||
# Check if legacy proposal command is needed
|
||||
if ! $CHAIN_BIN tx gov submit-proposal --help 2>/dev/null | grep -q "submit-proposal"; then
|
||||
submit_cmd="submit-legacy-proposal"
|
||||
fi
|
||||
|
||||
submit_tx "$from_key" gov "$submit_cmd" "$proposal_file"
|
||||
}
|
||||
|
||||
# Vote on governance proposal
|
||||
# Usage: vote_proposal <from_key> <proposal_id> <vote_option>
|
||||
vote_proposal() {
|
||||
local from_key="$1"
|
||||
local proposal_id="$2"
|
||||
local vote_option="${3:-yes}"
|
||||
|
||||
ensure_key "$from_key"
|
||||
|
||||
log_info "Voting '$vote_option' on proposal $proposal_id from '$from_key'"
|
||||
|
||||
submit_tx "$from_key" gov vote "$proposal_id" "$vote_option"
|
||||
}
|
||||
|
||||
# Wait for proposal to pass
|
||||
# Usage: wait_for_proposal <proposal_id> [max_tries] [interval]
|
||||
wait_for_proposal() {
|
||||
local proposal_id="$1"
|
||||
local max_tries="${2:-3}"
|
||||
local interval="${3:-30}"
|
||||
|
||||
log_info "Waiting for proposal $proposal_id to pass..."
|
||||
|
||||
local tries=0
|
||||
while [[ $tries -lt $max_tries ]]; do
|
||||
local status
|
||||
status=$(query_chain gov proposal "$proposal_id" | jq -r '.status // "unknown"')
|
||||
|
||||
case "$status" in
|
||||
"PROPOSAL_STATUS_PASSED")
|
||||
log_success "Proposal $proposal_id has passed"
|
||||
return 0
|
||||
;;
|
||||
"PROPOSAL_STATUS_REJECTED")
|
||||
log_error "Proposal $proposal_id was rejected"
|
||||
return 1
|
||||
;;
|
||||
"PROPOSAL_STATUS_FAILED")
|
||||
log_error "Proposal $proposal_id failed"
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
log_info "Proposal status: $status ($((tries + 1))/$max_tries)"
|
||||
sleep "$interval"
|
||||
((tries++))
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_error "Proposal $proposal_id did not pass after $max_tries attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Stake tokens to validator
|
||||
# Usage: stake_tokens <from_key> <validator_address> <amount>
|
||||
stake_tokens() {
|
||||
local from_key="$1"
|
||||
local validator_address="$2"
|
||||
local amount="$3"
|
||||
|
||||
ensure_key "$from_key"
|
||||
|
||||
log_info "Staking $amount from '$from_key' to $validator_address"
|
||||
|
||||
submit_tx "$from_key" staking delegate "$validator_address" "$amount"
|
||||
}
|
||||
|
||||
# Query account balance
|
||||
# Usage: get_balance <address> [denom]
|
||||
get_balance() {
|
||||
local address="$1"
|
||||
local denom="${2:-$DENOM}"
|
||||
|
||||
log_info "Getting balance for $address (denom: $denom)"
|
||||
|
||||
local balance
|
||||
balance=$(query_chain bank balances "$address" | jq -r ".balances[] | select(.denom == \"$denom\") | .amount // \"0\"")
|
||||
|
||||
echo "$balance"
|
||||
}
|
||||
|
||||
# Send tokens
|
||||
# Usage: send_tokens <from_key> <to_address> <amount>
|
||||
send_tokens() {
|
||||
local from_key="$1"
|
||||
local to_address="$2"
|
||||
local amount="$3"
|
||||
|
||||
ensure_key "$from_key"
|
||||
|
||||
log_info "Sending $amount from '$from_key' to $to_address"
|
||||
|
||||
submit_tx "$from_key" bank send "$from_key" "$to_address" "$amount"
|
||||
}
|
||||
|
||||
# Export functions
|
||||
export -f submit_tx query_chain get_validator_address submit_proposal
|
||||
export -f vote_proposal wait_for_proposal stake_tokens get_balance send_tokens
|
||||
+123
-257
@@ -5,156 +5,76 @@
|
||||
# CHAIN_ID="localchain_9000-1" HOME_DIR="~/.sonr" BLOCK_TIME="1000ms" CLEAN=true sh scripts/test_node.sh
|
||||
# CHAIN_ID="localchain_9000-2" HOME_DIR="~/.sonr" CLEAN=true RPC=36657 REST=2317 PROFF=6061 P2P=36656 GRPC=8090 GRPC_WEB=8091 ROSETTA=8081 BLOCK_TIME="500ms" sh scripts/test_node.sh
|
||||
|
||||
set -eu
|
||||
set -euo pipefail
|
||||
|
||||
export KEY="acc0"
|
||||
export KEY2="acc1"
|
||||
# Source helper libraries
|
||||
# Get the directory of this script reliably
|
||||
SCRIPT_DIR="/usr/local/lib/sonr-scripts"
|
||||
source "${SCRIPT_DIR}/env.sh"
|
||||
source "${SCRIPT_DIR}/config.sh"
|
||||
source "${SCRIPT_DIR}/keys.sh"
|
||||
source "${SCRIPT_DIR}/genesis.sh"
|
||||
|
||||
export CHAIN_ID=${CHAIN_ID:-"sonrtest_1-1"}
|
||||
export MONIKER="localvalidator"
|
||||
export KEYALGO="eth_secp256k1"
|
||||
export KEYRING=${KEYRING:-"test"}
|
||||
export HOME_DIR=$(eval echo "${HOME_DIR:-"~/.sonr"}")
|
||||
export BINARY=${BINARY:-snrd}
|
||||
export DENOM=${DENOM:-usnr}
|
||||
# Initialize environment
|
||||
init_env
|
||||
|
||||
export CLEAN=${CLEAN:-"false"}
|
||||
export RPC=${RPC:-"26657"}
|
||||
export REST=${REST:-"1317"}
|
||||
export PROFF=${PROFF:-"6060"}
|
||||
export P2P=${P2P:-"26656"}
|
||||
export GRPC=${GRPC:-"9090"}
|
||||
export GRPC_WEB=${GRPC_WEB:-"9091"}
|
||||
export ROSETTA=${ROSETTA:-"8080"}
|
||||
export JSON_RPC=${JSON_RPC:-"8545"}
|
||||
export JSON_RPC_WS=${JSON_RPC_WS:-"8546"}
|
||||
export BLOCK_TIME=${BLOCK_TIME:-"5s"}
|
||||
# Set defaults for test node
|
||||
export KEY="${KEY:-acc0}"
|
||||
export KEY2="${KEY2:-acc1}"
|
||||
export MONIKER="${MONIKER:-localvalidator}"
|
||||
export KEYALGO="${KEYALGO:-eth_secp256k1}"
|
||||
|
||||
# Configurable Mnemomics
|
||||
export SONR_MNEMONIC_1=${SONR_MNEMONIC_1:-"decorate bright ozone fork gallery riot bus exhaust worth way bone indoor calm squirrel merry zero scheme cotton until shop any excess stage laundry"}
|
||||
export SONR_MNEMONIC_2=${SONR_MNEMONIC_2:-"wealth flavor believe regret funny network recall kiss grape useless pepper cram hint member few certain unveil rather brick bargain curious require crowd raise"}
|
||||
# Configurable ports
|
||||
export RPC="${RPC:-26657}"
|
||||
export REST="${REST:-1317}"
|
||||
export PROFF="${PROFF:-6060}"
|
||||
export P2P="${P2P:-26656}"
|
||||
export GRPC="${GRPC:-9090}"
|
||||
export GRPC_WEB="${GRPC_WEB:-9091}"
|
||||
export ROSETTA="${ROSETTA:-8080}"
|
||||
export JSON_RPC="${JSON_RPC:-8545}"
|
||||
export JSON_RPC_WS="${JSON_RPC_WS:-8546}"
|
||||
export BLOCK_TIME="${BLOCK_TIME:-5s}"
|
||||
|
||||
# Configurable mnemonics
|
||||
export SONR_MNEMONIC_1="${SONR_MNEMONIC_1:-decorate bright ozone fork gallery riot bus exhaust worth way bone indoor calm squirrel merry zero scheme cotton until shop any excess stage laundry}"
|
||||
export SONR_MNEMONIC_2="${SONR_MNEMONIC_2:-wealth flavor believe regret funny network recall kiss grape useless pepper cram hint member few certain unveil rather brick bargain curious require crowd raise}"
|
||||
|
||||
# Docker and installation options
|
||||
export FORCE_DOCKER="${FORCE_DOCKER:-false}"
|
||||
export SKIP_INSTALL="${SKIP_INSTALL:-false}"
|
||||
export CLEAN="${CLEAN:-false}"
|
||||
export DOCKER_DETACHED="${DOCKER_DETACHED:-false}"
|
||||
|
||||
# Check if binary exists, if not use Docker (or force Docker if requested)
|
||||
export FORCE_DOCKER=${FORCE_DOCKER:-"false"}
|
||||
export SKIP_INSTALL=${SKIP_INSTALL:-"false"}
|
||||
USE_DOCKER=false
|
||||
if [[ "${FORCE_DOCKER}" == "true" ]] || [[ -z $(which "${BINARY}") ]]; then
|
||||
if [[ "${FORCE_DOCKER}" == "true" ]] || ! command -v "$CHAIN_BIN" >/dev/null 2>&1; then
|
||||
# Check if Docker is available and use it
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
if [[ "${FORCE_DOCKER}" == "true" ]]; then
|
||||
echo "Force Docker mode enabled, using Docker image onsonr/snrd:latest..."
|
||||
log_info "Force Docker mode enabled, using Docker image onsonr/snrd:latest"
|
||||
else
|
||||
echo "Binary ${BINARY} not found locally, checking for Docker image onsonr/snrd:latest..."
|
||||
log_info "Binary $CHAIN_BIN not found locally, checking for Docker image onsonr/snrd:latest"
|
||||
fi
|
||||
if docker image inspect onsonr/snrd:latest >/dev/null 2>&1; then
|
||||
echo "Using Docker image onsonr/snrd:latest"
|
||||
log_info "Using Docker image onsonr/snrd:latest"
|
||||
USE_DOCKER=true
|
||||
else
|
||||
echo "Docker image onsonr/snrd:latest not found. Pulling image..."
|
||||
log_info "Docker image onsonr/snrd:latest not found. Pulling image..."
|
||||
docker pull onsonr/snrd:latest || {
|
||||
echo "Failed to pull onsonr/snrd:latest. Please ensure Docker is running and you have internet access."
|
||||
log_error "Failed to pull onsonr/snrd:latest. Please ensure Docker is running and you have internet access."
|
||||
exit 1
|
||||
}
|
||||
USE_DOCKER=true
|
||||
fi
|
||||
else
|
||||
echo "Binary ${BINARY} not found. Please either:"
|
||||
echo " 1. Install ${BINARY} with 'make install'"
|
||||
echo " 2. Install Docker to use the containerized version"
|
||||
log_error "Binary $CHAIN_BIN not found. Please either:"
|
||||
log_error " 1. Install $CHAIN_BIN with 'make install'"
|
||||
log_error " 2. Install Docker to use the containerized version"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Final check if not using Docker
|
||||
if [[ "${USE_DOCKER}" == "false" ]]; then
|
||||
command -v "${BINARY}" >/dev/null 2>&1 || {
|
||||
echo >&2 "${BINARY} command not found. Ensure this is setup / properly installed in your GOPATH (make install)."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
command -v jq >/dev/null 2>&1 || {
|
||||
echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# generate_vrf_key generates a VRF keypair and stores it securely
|
||||
# Mirrors the Go implementation in app/commands/enhance_init.go
|
||||
generate_vrf_key() {
|
||||
local home_dir="$1"
|
||||
local use_docker="${2:-false}"
|
||||
|
||||
# Validate parameters
|
||||
if [[ -z "${home_dir}" ]]; then
|
||||
echo "Error: HOME_DIR parameter is required" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Path to genesis file
|
||||
local genesis_file="${home_dir}/config/genesis.json"
|
||||
|
||||
# Check if genesis file exists
|
||||
if [[ ! -f "${genesis_file}" ]]; then
|
||||
echo "Error: Genesis file not found at ${genesis_file}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract chain-id from genesis file
|
||||
local chain_id
|
||||
chain_id=$(jq -r '.chain_id' "${genesis_file}" 2>/dev/null)
|
||||
|
||||
if [[ -z "${chain_id}" || "${chain_id}" == "null" ]]; then
|
||||
echo "Error: Failed to extract chain-id from genesis file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Generating VRF keypair for network: ${chain_id}"
|
||||
|
||||
# Create deterministic entropy from chain-id using SHA256
|
||||
local entropy_seed
|
||||
entropy_seed=$(echo -n "${chain_id}" | sha256sum | cut -d' ' -f1)
|
||||
|
||||
# Generate 64 bytes of deterministic randomness
|
||||
local seed_part1="${entropy_seed}"
|
||||
local seed_part2
|
||||
seed_part2=$(echo -n "${entropy_seed}" | sha256sum | cut -d' ' -f1)
|
||||
|
||||
# Combine to create 64 bytes of hex data
|
||||
local vrf_key_hex="${seed_part1}${seed_part2}"
|
||||
|
||||
# Ensure we have exactly 128 hex characters (64 bytes)
|
||||
if [[ ${#vrf_key_hex} -ne 128 ]]; then
|
||||
echo "Error: Generated VRF key has incorrect size: ${#vrf_key_hex}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Path to store VRF secret key
|
||||
local vrf_key_path="${home_dir}/vrf_secret.key"
|
||||
|
||||
# Ensure directory exists
|
||||
mkdir -p "${home_dir}"
|
||||
|
||||
# Convert hex to binary and write to file
|
||||
echo -n "${vrf_key_hex}" | xxd -r -p > "${vrf_key_path}"
|
||||
|
||||
# Set restrictive permissions (owner read/write only)
|
||||
chmod 0600 "${vrf_key_path}"
|
||||
|
||||
# Validate file was created with correct size (64 bytes)
|
||||
local file_size
|
||||
file_size=$(wc -c < "${vrf_key_path}")
|
||||
|
||||
if [[ ${file_size} -ne 64 ]]; then
|
||||
echo "Error: VRF key file has incorrect size: ${file_size} bytes" >&2
|
||||
rm -f "${vrf_key_path}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "✓ VRF keypair generated for network: ${chain_id}"
|
||||
echo "✓ VRF secret key stored securely: ${vrf_key_path}"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Create wrapper function for binary execution
|
||||
run_binary() {
|
||||
if [[ "${USE_DOCKER}" == "true" ]]; then
|
||||
@@ -172,10 +92,11 @@ run_binary() {
|
||||
onsonr/snrd:latest \
|
||||
snrd --home /root/.sonr "$@"
|
||||
else
|
||||
${BINARY} "$@"
|
||||
${CHAIN_BIN} "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Set client configuration
|
||||
set_config() {
|
||||
run_binary config set client chain-id "${CHAIN_ID}"
|
||||
run_binary config set client keyring-backend "${KEYRING}"
|
||||
@@ -185,100 +106,49 @@ set_config
|
||||
from_scratch() {
|
||||
# Fresh install on current branch (skip if using Docker or SKIP_INSTALL is true)
|
||||
if [[ "${USE_DOCKER}" == "false" ]] && [[ "${SKIP_INSTALL}" == "false" ]]; then
|
||||
log_info "Installing $CHAIN_BIN..."
|
||||
make install
|
||||
fi
|
||||
|
||||
# remove existing daemon files.
|
||||
# Remove existing daemon files
|
||||
if [[ ${#HOME_DIR} -le 2 ]]; then
|
||||
echo "HOME_DIR must be more than 2 characters long"
|
||||
return
|
||||
log_error "HOME_DIR must be more than 2 characters long"
|
||||
return 1
|
||||
fi
|
||||
rm -rf "${HOME_DIR}" && echo "Removed ${HOME_DIR}"
|
||||
rm -rf "${HOME_DIR}"
|
||||
log_info "Removed existing chain directory: ${HOME_DIR}"
|
||||
|
||||
# reset values if not set already after whipe
|
||||
# Reset configuration
|
||||
set_config
|
||||
|
||||
add_key() {
|
||||
key=$1
|
||||
mnemonic=$2
|
||||
if [[ "${USE_DOCKER}" == "true" ]]; then
|
||||
# For Docker, we need to pass the mnemonic differently
|
||||
mkdir -p "${HOME_DIR}"
|
||||
echo "${mnemonic}" | docker run --rm -i \
|
||||
-v "${HOME_DIR}:/root/.sonr" \
|
||||
--network host \
|
||||
onsonr/snrd:latest \
|
||||
snrd --home /root/.sonr keys add "${key}" --keyring-backend "${KEYRING}" --algo "${KEYALGO}" --recover
|
||||
else
|
||||
echo "${mnemonic}" | ${BINARY} keys add "${key}" --keyring-backend "${KEYRING}" --algo "${KEYALGO}" --home "${HOME_DIR}" --recover
|
||||
fi
|
||||
}
|
||||
|
||||
# idx140fehngcrxvhdt84x729p3f0qmkmea8n570lrg
|
||||
add_key "${KEY}" "${SONR_MNEMONIC_1}"
|
||||
|
||||
# idx1r6yue0vuyj9m7xw78npspt9drq2tmtvgcrf7sr
|
||||
add_key "${KEY2}" "${SONR_MNEMONIC_2}"
|
||||
# Add test keys
|
||||
log_info "Adding test keys..."
|
||||
import_mnemonic "${KEY}" "${SONR_MNEMONIC_1}" "$KEYALGO"
|
||||
import_mnemonic "${KEY2}" "${SONR_MNEMONIC_2}" "$KEYALGO"
|
||||
|
||||
# Initialize chain
|
||||
log_info "Initializing chain with moniker: $MONIKER"
|
||||
if [[ "${USE_DOCKER}" == "true" ]]; then
|
||||
# For Docker init, we need to handle it specially
|
||||
docker run --rm \
|
||||
-v "${HOME_DIR}:/root/.sonr" \
|
||||
--network host \
|
||||
onsonr/snrd:latest \
|
||||
snrd --home /root/.sonr init "${MONIKER}" --chain-id "${CHAIN_ID}" --default-denom "${DENOM}"
|
||||
else
|
||||
${BINARY} init "${MONIKER}" --chain-id "${CHAIN_ID}" --default-denom "${DENOM}" --home "${HOME_DIR}"
|
||||
${CHAIN_BIN} init "${MONIKER}" --chain-id "${CHAIN_ID}" --default-denom "${DENOM}" --home "${HOME_DIR}"
|
||||
fi
|
||||
|
||||
update_test_genesis() {
|
||||
cat "${HOME_DIR}"/config/genesis.json | jq "$1" >"${HOME_DIR}"/config/tmp_genesis.json && mv "${HOME_DIR}"/config/tmp_genesis.json "${HOME_DIR}"/config/genesis.json
|
||||
}
|
||||
# Update genesis parameters
|
||||
log_info "Updating genesis parameters..."
|
||||
update_genesis_params
|
||||
|
||||
# === CORE MODULES ===
|
||||
# Add constitution if available
|
||||
add_constitution
|
||||
|
||||
# Block
|
||||
update_test_genesis '.consensus_params["block"]["max_gas"]="100000000"'
|
||||
# Set up genesis accounts and transactions
|
||||
local BASE_GENESIS_ALLOCATIONS="100000000000000000000000000${DENOM},100000000test"
|
||||
|
||||
# Gov
|
||||
update_test_genesis $(printf '.app_state["gov"]["params"]["min_deposit"]=[{"denom":"%s","amount":"1000000"}]' "${DENOM}")
|
||||
update_test_genesis '.app_state["gov"]["params"]["voting_period"]="30s"'
|
||||
update_test_genesis '.app_state["gov"]["params"]["expedited_voting_period"]="15s"'
|
||||
|
||||
# Add CONSTITUTION.md to governance if it exists
|
||||
if [ -f "CONSTITUTION.md" ]; then
|
||||
CONSTITUTION_CONTENT=$(cat CONSTITUTION.md | jq -Rs .)
|
||||
update_test_genesis ".app_state[\"gov\"][\"constitution\"]=$CONSTITUTION_CONTENT"
|
||||
fi
|
||||
|
||||
update_test_genesis $(printf '.app_state["evm"]["params"]["evm_denom"]="%s"' "${DENOM}")
|
||||
update_test_genesis '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805"]'
|
||||
update_test_genesis '.app_state["erc20"]["params"]["native_precompiles"]=["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' # https://eips.ethereum.org/EIPS/eip-7528
|
||||
update_test_genesis $(printf '.app_state["erc20"]["token_pairs"]=[{contract_owner:1,erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",denom:"%s",enabled:true}]' "${DENOM}")
|
||||
update_test_genesis '.app_state["feemarket"]["params"]["no_base_fee"]=true'
|
||||
update_test_genesis '.app_state["feemarket"]["params"]["base_fee"]="0.000000000000000000"'
|
||||
|
||||
# staking
|
||||
update_test_genesis $(printf '.app_state["staking"]["params"]["bond_denom"]="%s"' "${DENOM}")
|
||||
update_test_genesis '.app_state["staking"]["params"]["min_commission_rate"]="0.050000000000000000"'
|
||||
|
||||
# mint
|
||||
update_test_genesis $(printf '.app_state["mint"]["params"]["mint_denom"]="%s"' "${DENOM}")
|
||||
|
||||
# crisis
|
||||
update_test_genesis $(printf '.app_state["crisis"]["constant_fee"]={"denom":"%s","amount":"1000"}' "${DENOM}")
|
||||
|
||||
## abci
|
||||
update_test_genesis '.consensus["params"]["abci"]["vote_extensions_enable_height"]="1"'
|
||||
|
||||
# === CUSTOM MODULES ===
|
||||
# tokenfactory
|
||||
update_test_genesis '.app_state["tokenfactory"]["params"]["denom_creation_fee"]=[]'
|
||||
update_test_genesis '.app_state["tokenfactory"]["params"]["denom_creation_gas_consume"]=100000'
|
||||
|
||||
BASE_GENESIS_ALLOCATIONS="100000000000000000000000000${DENOM},100000000test"
|
||||
|
||||
# Allocate genesis accounts
|
||||
log_info "Adding genesis accounts..."
|
||||
if [[ "${USE_DOCKER}" == "true" ]]; then
|
||||
docker run --rm \
|
||||
-v "${HOME_DIR}:/root/.sonr" \
|
||||
@@ -307,85 +177,78 @@ from_scratch() {
|
||||
onsonr/snrd:latest \
|
||||
snrd --home /root/.sonr genesis validate-genesis
|
||||
else
|
||||
${BINARY} genesis add-genesis-account "${KEY}" "${BASE_GENESIS_ALLOCATIONS}" --keyring-backend "${KEYRING}" --home "${HOME_DIR}" --append
|
||||
${BINARY} genesis add-genesis-account "${KEY2}" "${BASE_GENESIS_ALLOCATIONS}" --keyring-backend "${KEYRING}" --home "${HOME_DIR}" --append
|
||||
${CHAIN_BIN} genesis add-genesis-account "${KEY}" "${BASE_GENESIS_ALLOCATIONS}" --keyring-backend "${KEYRING}" --home "${HOME_DIR}" --append
|
||||
${CHAIN_BIN} genesis add-genesis-account "${KEY2}" "${BASE_GENESIS_ALLOCATIONS}" --keyring-backend "${KEYRING}" --home "${HOME_DIR}" --append
|
||||
# Sign genesis transaction
|
||||
${BINARY} genesis gentx "${KEY}" 1000000000000000000000"${DENOM}" --gas-prices 0"${DENOM}" --keyring-backend "${KEYRING}" --chain-id "${CHAIN_ID}" --home "${HOME_DIR}"
|
||||
${BINARY} genesis collect-gentxs --home "${HOME_DIR}"
|
||||
${BINARY} genesis validate-genesis --home "${HOME_DIR}"
|
||||
fi
|
||||
err=$?
|
||||
if [[ ${err} -ne 0 ]]; then
|
||||
echo "Failed to validate genesis"
|
||||
return
|
||||
${CHAIN_BIN} genesis gentx "${KEY}" 1000000000000000000000"${DENOM}" --gas-prices 0"${DENOM}" --keyring-backend "${KEYRING}" --chain-id "${CHAIN_ID}" --home "${HOME_DIR}"
|
||||
${CHAIN_BIN} genesis collect-gentxs --home "${HOME_DIR}"
|
||||
${CHAIN_BIN} genesis validate-genesis --home "${HOME_DIR}"
|
||||
fi
|
||||
|
||||
log_success "Genesis setup completed"
|
||||
}
|
||||
|
||||
# check if CLEAN is not set to false
|
||||
# Check if CLEAN is not set to false
|
||||
if [[ ${CLEAN} != "false" ]]; then
|
||||
echo "Starting from a clean state"
|
||||
log_info "Starting from a clean state"
|
||||
from_scratch
|
||||
|
||||
# Generate VRF keypair (must be done after genesis file is created)
|
||||
echo ""
|
||||
echo "Generating VRF keypair..."
|
||||
if ! generate_vrf_key "${HOME_DIR}" "${USE_DOCKER}"; then
|
||||
echo "Warning: VRF key generation failed, but continuing..."
|
||||
echo "Note: Multi-validator encryption features may not work without VRF keys"
|
||||
log_info "Generating VRF keypair..."
|
||||
if ! generate_vrf_key "${HOME_DIR}"; then
|
||||
log_warn "VRF key generation failed, but continuing..."
|
||||
log_warn "Note: Multi-validator encryption features may not work without VRF keys"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Starting node..."
|
||||
log_info "Configuring node ports and settings..."
|
||||
|
||||
# Opens the RPC endpoint to outside connections
|
||||
sed -i -e 's/laddr = "tcp:\/\/127.0.0.1:26657"/laddr = "tcp:\/\/0.0.0.0:'"${RPC}"'"/g' "${HOME_DIR}"/config/config.toml
|
||||
sed -i -e 's/cors_allowed_origins = \[\]/cors_allowed_origins = \["*"\]/g' "${HOME_DIR}"/config/config.toml
|
||||
# Configure node with all the specified ports and settings
|
||||
configure_node "$HOME_DIR" \
|
||||
--rpc-port "$RPC" \
|
||||
--rest-port "$REST" \
|
||||
--grpc-port "$GRPC" \
|
||||
--grpc-web-port "$GRPC_WEB" \
|
||||
--json-rpc-port "$JSON_RPC" \
|
||||
--rosetta-port "$ROSETTA" \
|
||||
--min-gas-prices "0${DENOM}" \
|
||||
--pruning nothing
|
||||
|
||||
# REST endpoint
|
||||
sed -i -e 's/address = "tcp:\/\/localhost:1317"/address = "tcp:\/\/0.0.0.0:'"${REST}"'"/g' "${HOME_DIR}"/config/app.toml
|
||||
sed -i -e 's/enable = false/enable = true/g' "${HOME_DIR}"/config/app.toml
|
||||
sed -i -e 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' "${HOME_DIR}"/config/app.toml
|
||||
# Set consensus timeouts
|
||||
set_consensus_timeouts "$HOME_DIR/config/config.toml" "5s" "1s" "1s" "$BLOCK_TIME"
|
||||
|
||||
# peer exchange
|
||||
sed -i -e 's/pprof_laddr = "localhost:6060"/pprof_laddr = "localhost:'"${PROFF}"'"/g' "${HOME_DIR}"/config/config.toml
|
||||
sed -i -e 's/laddr = "tcp:\/\/0.0.0.0:26656"/laddr = "tcp:\/\/0.0.0.0:'"${P2P}"'"/g' "${HOME_DIR}"/config/config.toml
|
||||
# Enable CORS for RPC
|
||||
set_toml_value "$HOME_DIR/config/config.toml" "" "cors_allowed_origins" '["*"]'
|
||||
|
||||
# GRPC
|
||||
sed -i -e 's/address = "localhost:9090"/address = "0.0.0.0:'"${GRPC}"'"/g' "${HOME_DIR}"/config/app.toml
|
||||
sed -i -e 's/address = "localhost:9091"/address = "0.0.0.0:'"${GRPC_WEB}"'"/g' "${HOME_DIR}"/config/app.toml
|
||||
# Set pprof address
|
||||
set_toml_value "$HOME_DIR/config/config.toml" "" "pprof_laddr" "localhost:${PROFF}"
|
||||
|
||||
# Rosetta Api
|
||||
sed -i -e 's/address = ":8080"/address = "0.0.0.0:'"${ROSETTA}"'"/g' "${HOME_DIR}"/config/app.toml
|
||||
# Set P2P address
|
||||
set_toml_value "$HOME_DIR/config/config.toml" "p2p" "laddr" "tcp://0.0.0.0:${P2P}"
|
||||
|
||||
# JSON-RPC
|
||||
sed -i -e '/\[json-rpc\]/,/^\[/ s/enable = false/enable = true/' "${HOME_DIR}"/config/app.toml
|
||||
sed -i -e '/\[json-rpc\]/,/^\[/ s/address = "127.0.0.1:8545"/address = "0.0.0.0:'"${JSON_RPC}"'"/' "${HOME_DIR}"/config/app.toml
|
||||
sed -i -e '/\[json-rpc\]/,/^\[/ s/ws-address = "127.0.0.1:8546"/ws-address = "0.0.0.0:'"${JSON_RPC_WS}"'"/' "${HOME_DIR}"/config/app.toml
|
||||
|
||||
# Faster blocks
|
||||
sed -i -e 's/timeout_commit = "5s"/timeout_commit = "'"${BLOCK_TIME}"'"/g' "${HOME_DIR}"/config/config.toml
|
||||
log_info "Starting node..."
|
||||
|
||||
# Start the node (with or without Docker)
|
||||
if [[ "${USE_DOCKER}" == "true" ]]; then
|
||||
echo "Starting node using Docker..."
|
||||
log_info "Starting node using Docker..."
|
||||
|
||||
# Check for detached mode via environment variable or prompt
|
||||
DETACHED_MODE=""
|
||||
if [[ "${DOCKER_DETACHED}" == "true" ]]; then
|
||||
DETACHED_MODE="-d"
|
||||
echo "Running in detached mode. Use 'docker logs -f sonr-testnode' to view logs."
|
||||
echo "Stop with: docker stop sonr-testnode"
|
||||
log_info "Running in detached mode. Use 'docker logs -f sonr-testnode' to view logs."
|
||||
log_info "Stop with: docker stop sonr-testnode"
|
||||
elif [ -t 0 ]; then
|
||||
echo ""
|
||||
echo "Would you like to run the node in detached mode (background)? [y/N]"
|
||||
log_info ""
|
||||
log_info "Would you like to run the node in detached mode (background)? [y/N]"
|
||||
read -r -n 1 DETACH_RESPONSE
|
||||
echo ""
|
||||
log_info ""
|
||||
if [[ "$DETACH_RESPONSE" =~ ^[Yy]$ ]]; then
|
||||
DETACHED_MODE="-d"
|
||||
echo "Running in detached mode. Use 'docker logs -f sonr-testnode' to view logs."
|
||||
echo "Stop with: docker stop sonr-testnode"
|
||||
log_info "Running in detached mode. Use 'docker logs -f sonr-testnode' to view logs."
|
||||
log_info "Stop with: docker stop sonr-testnode"
|
||||
else
|
||||
echo "Running in foreground mode. Use Ctrl+C to stop."
|
||||
log_info "Running in foreground mode. Use Ctrl+C to stop."
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -404,15 +267,18 @@ if [[ "${USE_DOCKER}" == "true" ]]; then
|
||||
|
||||
# If running detached, show status
|
||||
if [ -n "$DETACHED_MODE" ]; then
|
||||
echo ""
|
||||
echo "✅ Node started in background"
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " View logs: docker logs -f sonr-testnode"
|
||||
echo " Stop node: docker stop sonr-testnode"
|
||||
echo " Node status: curl http://localhost:${RPC}/status | jq '.result.sync_info'"
|
||||
echo ""
|
||||
log_info ""
|
||||
log_success "Node started in background"
|
||||
log_info ""
|
||||
log_info "Useful commands:"
|
||||
log_info " View logs: docker logs -f sonr-testnode"
|
||||
log_info " Stop node: docker stop sonr-testnode"
|
||||
log_info " Node status: curl http://localhost:${RPC}/status | jq '.result.sync_info'"
|
||||
log_info ""
|
||||
fi
|
||||
else
|
||||
${BINARY} start --pruning=nothing --minimum-gas-prices=0"${DENOM}" --rpc.laddr="tcp://0.0.0.0:${RPC}" --home "${HOME_DIR}" --json-rpc.api=eth,txpool,personal,net,debug,web3 --json-rpc.address="0.0.0.0:${JSON_RPC}" --json-rpc.ws-address="0.0.0.0:${JSON_RPC_WS}" --chain-id="${CHAIN_ID}"
|
||||
log_info "Starting node locally..."
|
||||
${CHAIN_BIN} start --pruning=nothing --minimum-gas-prices=0"${DENOM}" --rpc.laddr="tcp://0.0.0.0:${RPC}" --home "${HOME_DIR}" --json-rpc.api=eth,txpool,personal,net,debug,web3 --json-rpc.address="0.0.0.0:${JSON_RPC}" --json-rpc.ws-address="0.0.0.0:${JSON_RPC_WS}" --chain-id="${CHAIN_ID}"
|
||||
fi
|
||||
|
||||
log_success "Node startup completed"
|
||||
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/testnet-setup.sh - Initialize Sonr testnet nodes for Docker deployment
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper libraries
|
||||
SCRIPT_DIR="/usr/local/lib/sonr-scripts"
|
||||
source "${SCRIPT_DIR}/env.sh"
|
||||
source "${SCRIPT_DIR}/config.sh"
|
||||
source "${SCRIPT_DIR}/keys.sh"
|
||||
source "${SCRIPT_DIR}/genesis.sh"
|
||||
|
||||
# Initialize environment
|
||||
init_env
|
||||
|
||||
# Set defaults for testnet
|
||||
NODE_TYPE="${NODE_TYPE:-validator}" # validator, sentry
|
||||
MONIKER="${MONIKER:-validator}"
|
||||
VALIDATOR_NAME="${VALIDATOR_NAME:-$MONIKER}"
|
||||
CHAIN_ID="${CHAIN_ID:-sonrtest_1-1}"
|
||||
HOME_DIR="${HOME_DIR:-/root/.sonr}"
|
||||
|
||||
log_info "Setting up Sonr testnet node: $NODE_TYPE ($VALIDATOR_NAME)"
|
||||
|
||||
# Ensure chain directory exists
|
||||
ensure_chain_dir
|
||||
|
||||
# Update genesis parameters
|
||||
log_info "Updating genesis parameters..."
|
||||
update_genesis_params
|
||||
|
||||
# Add constitution if available
|
||||
add_constitution
|
||||
|
||||
# Configure node
|
||||
log_info "Configuring node..."
|
||||
configure_node "$CHAIN_DIR" \
|
||||
--rpc-port 26657 \
|
||||
--rest-port 1317 \
|
||||
--grpc-port 9090 \
|
||||
--grpc-web-port 9091 \
|
||||
--json-rpc-port 8545 8546 \
|
||||
--rosetta-port 8080 \
|
||||
--min-gas-prices "0${DENOM}" \
|
||||
--pruning nothing \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--chain-id "$CHAIN_ID" \
|
||||
--output-format json
|
||||
|
||||
# Set consensus timeouts for faster blocks
|
||||
set_consensus_timeouts "$CHAIN_DIR/config/config.toml" "5s" "1s" "1s" "1s"
|
||||
|
||||
# Enable CORS for RPC
|
||||
set_toml_value "$CHAIN_DIR/config/config.toml" "" "cors_allowed_origins" '["*"]'
|
||||
|
||||
# Set pprof address
|
||||
set_toml_value "$CHAIN_DIR/config/config.toml" "" "pprof_laddr" "localhost:6060"
|
||||
|
||||
# Set P2P address
|
||||
set_toml_value "$CHAIN_DIR/config/config.toml" "p2p" "laddr" "tcp://0.0.0.0:26656"
|
||||
|
||||
# Generate VRF keypair
|
||||
log_info "Generating VRF keypair..."
|
||||
if ! generate_vrf_key "$CHAIN_DIR"; then
|
||||
log_warn "VRF key generation failed, but continuing..."
|
||||
log_warn "Note: Multi-validator encryption features may not work without VRF keys"
|
||||
fi
|
||||
|
||||
# Create validator if this is a validator node
|
||||
if [[ "$NODE_TYPE" == "validator" ]]; then
|
||||
log_info "Creating validator..."
|
||||
|
||||
# Wait for node to sync (in case it's connecting to other nodes)
|
||||
if [[ "${WAIT_FOR_SYNC:-false}" == "true" ]]; then
|
||||
wait_for_sync 10
|
||||
fi
|
||||
|
||||
# Create validator (this would need proper key setup)
|
||||
log_info "Validator creation requires manual key setup and gentx creation"
|
||||
log_info "Run: snrd genesis gentx <validator-key> <amount> --chain-id $CHAIN_ID"
|
||||
fi
|
||||
|
||||
log_success "Testnet setup completed for $NODE_TYPE node: $VALIDATOR_NAME"
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
ADDRESS="$1"
|
||||
DENOM="$2"
|
||||
FAUCET_URL="$3"
|
||||
FAUCET_ENABLED="$4"
|
||||
|
||||
set -eux
|
||||
|
||||
function transfer_token() {
|
||||
status_code=$(curl --header "Content-Type: application/json" \
|
||||
--request POST --write-out %{http_code} --silent --output /dev/null \
|
||||
--data '{"denom":"'"$DENOM"'","address":"'"$ADDRESS"'"}' \
|
||||
$FAUCET_URL)
|
||||
echo $status_code
|
||||
}
|
||||
|
||||
if [[ $FAUCET_ENABLED == "false" ]];
|
||||
then
|
||||
echo "Faucet not enabled... skipping transfer token from faucet"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Try to send tokens, if failed, wait for 5 seconds and try again"
|
||||
max_tries=5
|
||||
while [[ max_tries -gt 0 ]]
|
||||
do
|
||||
status_code=$(transfer_token)
|
||||
if [[ "$status_code" -eq 200 ]]; then
|
||||
echo "Successfully sent tokens"
|
||||
exit 0
|
||||
fi
|
||||
echo "Failed to send tokens. Sleeping for 2 secs. Tries left $max_tries"
|
||||
((max_tries--))
|
||||
sleep 2
|
||||
done
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
# scripts/update-config.sh - Update configuration files for Sonr node
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper libraries
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/lib/env.sh"
|
||||
source "${SCRIPT_DIR}/lib/config.sh"
|
||||
|
||||
# Initialize environment
|
||||
init_env
|
||||
|
||||
# Ensure chain directory exists
|
||||
ensure_chain_dir
|
||||
|
||||
log_info "Updating configuration files for Sonr node"
|
||||
|
||||
# Configure node with standard settings
|
||||
configure_node "$CHAIN_DIR" \
|
||||
--rpc-port 26657 \
|
||||
--rest-port 1317 \
|
||||
--grpc-port 9090 \
|
||||
--grpc-web-port 9091 \
|
||||
--json-rpc-port 8545 8546 \
|
||||
--rosetta-port 8080 \
|
||||
--min-gas-prices "0${DENOM}" \
|
||||
--pruning default \
|
||||
--keyring-backend "$KEYRING_BACKEND" \
|
||||
--chain-id "$CHAIN_ID" \
|
||||
--output-format json
|
||||
|
||||
# Enable metrics if requested
|
||||
if [[ "${METRICS:-false}" == "true" ]]; then
|
||||
enable_metrics "$CHAIN_DIR/config/config.toml" 3600
|
||||
fi
|
||||
|
||||
# Set consensus timeouts if provided
|
||||
if [[ -n "${TIMEOUT_PROPOSE:-}" ]]; then
|
||||
set_consensus_timeouts "$CHAIN_DIR/config/config.toml" \
|
||||
"$TIMEOUT_PROPOSE" \
|
||||
"${TIMEOUT_PREVOTE:-1s}" \
|
||||
"${TIMEOUT_PRECOMMIT:-1s}" \
|
||||
"${TIMEOUT_COMMIT:-5s}"
|
||||
fi
|
||||
|
||||
log_success "Configuration update completed"
|
||||
+23
-121
@@ -1,130 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
DENOM="${DENOM:=usnr}"
|
||||
CHAIN_BIN="${CHAIN_BIN:=snrd}"
|
||||
CHAIN_DIR="${CHAIN_DIR:=$HOME/.sonr}"
|
||||
# scripts/update-genesis.sh - Update genesis.json with Sonr-specific parameters
|
||||
|
||||
set -eux
|
||||
set -euo pipefail
|
||||
|
||||
ls "$CHAIN_DIR"/config
|
||||
|
||||
echo "Update genesis.json file with updated local params"
|
||||
sed -i -e "s/\"stake\"/\"$DENOM\"/g" "$CHAIN_DIR"/config/genesis.json
|
||||
sed -i "s/\"time_iota_ms\": \".*\"/\"time_iota_ms\": \"$TIME_IOTA_MS\"/" "$CHAIN_DIR"/config/genesis.json
|
||||
|
||||
echo "Update max gas param"
|
||||
jq -r '.consensus.params.block.max_gas |= "100000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
|
||||
echo "Update staking unbonding time and slashing jail time"
|
||||
jq -r '.app_state.staking.params.unbonding_time |= "300s"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.slashing.params.downtime_jail_duration |= "60s"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
|
||||
# overrides for older sdk versions, before 0.47
|
||||
function gov_overrides_sdk_v46() {
|
||||
jq -r '.app_state.gov.deposit_params.max_deposit_period |= "30s"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.deposit_params.min_deposit[0].amount |= "10"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.voting_params.voting_period |= "30s"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.tally_params.quorum |= "0.000000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.tally_params.threshold |= "0.000000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.tally_params.veto_threshold |= "0.000000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
}
|
||||
|
||||
# overrides for newer sdk versions, post 0.47
|
||||
function gov_overrides_sdk_v47() {
|
||||
jq -r '.app_state.gov.params.max_deposit_period |= "30s"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.params.min_deposit[0].amount |= "10"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.params.voting_period |= "30s"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.params.quorum |= "0.000000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.params.threshold |= "0.000000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.gov.params.veto_threshold |= "0.000000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
}
|
||||
|
||||
# EVM and feemarket configuration
|
||||
if [ "$(jq -r '.app_state.evm' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r ".app_state.evm.params.evm_denom |= \"$DENOM\"" "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.evm.params.active_static_precompiles |= ["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805"]' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
if [ "$(jq -r '.app_state.erc20' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r '.app_state.erc20.params.native_precompiles |= ["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r ".app_state.erc20.token_pairs |= [{\"contract_owner\":1,\"erc20_address\":\"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\",\"denom\":\"$DENOM\",\"enabled\":true}]" "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
if [ "$(jq -r '.app_state.feemarket.params' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r '.app_state.feemarket.params.no_base_fee |= true' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.feemarket.params.base_fee |= "0.000000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
# Staking and mint configuration
|
||||
if [ "$(jq -r '.app_state.staking' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r ".app_state.staking.params.bond_denom |= \"$DENOM\"" "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.staking.params.min_commission_rate |= "0.050000000000000000"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
if [ "$(jq -r '.app_state.mint' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r ".app_state.mint.params.mint_denom |= \"$DENOM\"" "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
if [ "$(jq -r '.app_state.crisis' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r ".app_state.crisis.constant_fee |= {\"denom\":\"$DENOM\",\"amount\":\"1000\"}" "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
# Token factory configuration
|
||||
if [ "$(jq -r '.app_state.tokenfactory' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r '.app_state.tokenfactory.params.denom_creation_fee |= []' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
jq -r '.app_state.tokenfactory.params.denom_creation_gas_consume |= 100000' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
# ABCI configuration
|
||||
if [ "$(jq -r '.consensus.params.abci' "$CHAIN_DIR"/config/genesis.json)" != "null" ]; then
|
||||
jq -r '.consensus.params.abci.vote_extensions_enable_height |= "1"' "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
|
||||
# Add CONSTITUTION.md to governance if it exists
|
||||
# Look for CONSTITUTION.md in the git root directory (parent of scripts directory)
|
||||
# Source helper libraries
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
GIT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
CONSTITUTION_FILE="${GIT_ROOT}/CONSTITUTION.md"
|
||||
source "${SCRIPT_DIR}/lib/env.sh"
|
||||
source "${SCRIPT_DIR}/lib/genesis.sh"
|
||||
|
||||
if [ -f "$CONSTITUTION_FILE" ]; then
|
||||
echo "Adding CONSTITUTION.md to governance module from: $CONSTITUTION_FILE"
|
||||
CONSTITUTION_CONTENT=$(cat "$CONSTITUTION_FILE" | jq -Rs .)
|
||||
jq -r ".app_state.gov.constitution = $CONSTITUTION_CONTENT" "$CHAIN_DIR"/config/genesis.json >/tmp/genesis.json
|
||||
mv /tmp/genesis.json "$CHAIN_DIR"/config/genesis.json
|
||||
fi
|
||||
# Initialize environment
|
||||
init_env
|
||||
|
||||
if [ "$(jq -r '.app_state.gov.params' "$CHAIN_DIR"/config/genesis.json)" == "null" ]; then
|
||||
gov_overrides_sdk_v46
|
||||
else
|
||||
gov_overrides_sdk_v47
|
||||
fi
|
||||
# Ensure chain directory exists
|
||||
ensure_chain_dir
|
||||
|
||||
log_info "Updating genesis.json file with Sonr parameters"
|
||||
|
||||
# Update genesis parameters using helper functions
|
||||
update_genesis_params
|
||||
|
||||
# Add constitution if available
|
||||
add_constitution
|
||||
|
||||
# Validate genesis file
|
||||
validate_genesis
|
||||
|
||||
# Show node ID
|
||||
$CHAIN_BIN tendermint show-node-id
|
||||
|
||||
log_success "Genesis update completed"
|
||||
|
||||
Reference in New Issue
Block a user