Chain ID Cometbft version Sidecar version Custom Port
gardia-2 4.7.1 1.2.3 182

Setup validator name

Replace YOUR_MONIKER_GOES_HERE with your validator name

MONIKER="YOUR_MONIKER_GOES_HERE"

Install dependencies

Update system and install build tools

sudo apt -q update
sudo apt -qy install curl git jq lz4 build-essential
sudo apt -qy upgrade

Install Go

sudo rm -rf /usr/local/go
curl -Ls https://go.dev/dl/go1.23.2.linux-amd64.tar.gz | sudo tar -xzf - -C /usr/local
eval $(echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee /etc/profile.d/golang.sh)
eval $(echo 'export PATH=$PATH:$HOME/go/bin' | tee -a $HOME/.profile)

Download binaries

# Download project binaries
mkdir -p $HOME/.zrchain/cosmovisor/genesis/bin
wget -O $HOME/.zrchain/cosmovisor/genesis/bin/zenrockd https://releases.gardia.zenrocklabs.io/zenrockd-4.7.1
chmod +x $HOME/.zrchain/cosmovisor/genesis/bin/zenrockd

# Create application symlinks
sudo ln -s $HOME/.zrchain/cosmovisor/genesis $HOME/.zrchain/cosmovisor/current -f
sudo ln -s $HOME/.zrchain/cosmovisor/current/bin/zenrockd /usr/local/bin/zenrockd -f

Install Cosmovisor and create a service

# Download and install Cosmovisor
go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@v1.6.0

# Create service
sudo tee /etc/systemd/system/zenrock-testnet.service > /dev/null << EOF
[Unit]
Description=zenrock node service
After=network-online.target

[Service]
User=$USER
ExecStart=$(which cosmovisor) run start
Restart=on-failure
RestartSec=10
LimitNOFILE=65535
Environment="DAEMON_HOME=$HOME/.zrchain"
Environment="DAEMON_NAME=zenrockd"
Environment="UNSAFE_SKIP_BACKUP=true"
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:$HOME/.zrchain/cosmovisor/current/bin"

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable zenrock-testnet.service

Set node configuration

# Set node configuration
zenrockd config set client chain-id gardia-2
zenrockd config set client keyring-backend test
zenrockd config set client node tcp://localhost:18257

Initialize the node

# Initialize the node
zenrockd init $MONIKER --chain-id gardia-2

# Download genesis and addrbook
curl -Ls https://snapshots.kjnodes.com/zenrock-testnet/genesis.json > $HOME/.zrchain/config/genesis.json
curl -Ls https://snapshots.kjnodes.com/zenrock-testnet/addrbook.json > $HOME/.zrchain/config/addrbook.json

# Add seeds
sed -i -e "s|^seeds *=.*|seeds = \"3f472746f46493309650e5a033076689996c8881@zenrock-testnet.rpc.kjnodes.com:18259\"|" $HOME/.zrchain/config/config.toml

# Set minimum gas price
sed -i -e "s|^minimum-gas-prices *=.*|minimum-gas-prices = \"0urock\"|" $HOME/.zrchain/config/app.toml

# Set pruning
sed -i \
  -e 's|^pruning *=.*|pruning = "custom"|' \
  -e 's|^pruning-keep-recent *=.*|pruning-keep-recent = "100"|' \
  -e 's|^pruning-keep-every *=.*|pruning-keep-every = "0"|' \
  -e 's|^pruning-interval *=.*|pruning-interval = "19"|' \
  $HOME/.zrchain/config/app.toml

# Set custom ports
sed -i -e "s%^proxy_app = \"tcp://127.0.0.1:26658\"%proxy_app = \"tcp://127.0.0.1:18258\"%; s%^laddr = \"tcp://127.0.0.1:26657\"%laddr = \"tcp://127.0.0.1:18257\"%; s%^pprof_laddr = \"localhost:6060\"%pprof_laddr = \"localhost:18260\"%; s%^laddr = \"tcp://0.0.0.0:26656\"%laddr = \"tcp://0.0.0.0:18256\"%; s%^prometheus_listen_addr = \":26660\"%prometheus_listen_addr = \":18266\"%" $HOME/.zrchain/config/config.toml
sed -i -e "s%^address = \"tcp://0.0.0.0:1317\"%address = \"tcp://0.0.0.0:18217\"%; s%^address = \":8080\"%address = \":18280\"%; s%^address = \"0.0.0.0:9090\"%address = \"0.0.0.0:18290\"%; s%^address = \"0.0.0.0:9091\"%address = \"0.0.0.0:18291\"%; s%:8545%:18245%; s%:8546%:18246%; s%:6065%:18265%" $HOME/.zrchain/config/app.toml

Download latest chain snapshot

curl -L https://snapshots.kjnodes.com/zenrock-testnet/snapshot_latest.tar.lz4 | tar -Ilz4 -xf - -C $HOME/.zrchain
[[ -f $HOME/.zrchain/data/upgrade-info.json ]] && cp $HOME/.zrchain/data/upgrade-info.json $HOME/.zrchain/cosmovisor/genesis/upgrade-info.json

Start service and check the logs

sudo systemctl start zenrock-testnet.service && sudo journalctl -u zenrock-testnet.service -f --no-hostname -o cat

Validator setup

To set up a validator, follow the steps below. Official validator setup instructions can be found at https://github.com/zenrocklabs/zenrock-validators.

Step 1: Create a wallet

First of all we will need to create wallet for our validator. You have two options for that.

Option 1 - Create new wallet

zenrockd keys add wallet

Option 2 - Recover existing wallet

zenrockd keys add wallet --recover

Save the mnemonic output as this is the only way to recover your validator wallet in case you lose it!

To list your wallets use command below

zenrockd keys list

Step 2: Fund a wallet

To create validator you have to top up previously created wallet with tokens.

To check wallet balance use command below

zenrockd q bank balances $(zenrockd keys show wallet -a)

Step 3: Create validator

Ensure that you have updated the validator details to match your own.

zenrockd tx validation create-validator <(cat <<EOF
{
  "pubkey": $(zenrockd comet show-validator),
  "amount": "1000000urock",
  "moniker": "YOUR_MONIKER_NAME",
  "identity": "YOUR_KEYBASE_ID",
  "website": "YOUR_WEBSITE_URL",
  "security": "YOUR_SECURITY_EMAIL",
  "details": "YOUR_DETAILS",
  "commission-rate": "0.05",
  "commission-max-rate": "0.20",
  "commission-max-change-rate": "0.05",
  "min-self-delegation": "1"
}
EOF
) \
--chain-id gardia-2 \
--from wallet \
--gas-adjustment 1.4 \
--gas auto \
--gas-prices 0urock \
-y

Save the $HOME/.zrchain/config/priv_validator_key.json file as this is the only way to recover your validator signing key in case you lose it!

Sidecar setup

The validator sidecar service allows validators to vote on oracle data during the consensus process in CometBFT, ensuring that oracle values are secured by the same economic security as the blockchain through a super-majority consensus mechanism.

Learn more about Validation Module.

Step 1: Clone zenrock-validators repository

cd $HOME
rm -rf zenrock-validators
git clone https://github.com/zenrocklabs/zenrock-validators

Step 2: Generate keys

# Set key password
read -p "Enter password for the keys: " key_pass

# Create sidecar directories
mkdir -p $HOME/.zrchain/sidecar/bin
mkdir -p $HOME/.zrchain/sidecar/keys


# Build ecdsa binary
cd $HOME/zenrock-validators/utils/keygen/ecdsa && go build

# Build bls binary
cd $HOME/zenrock-validators/utils/keygen/bls && go build

# Generate ecdsa key
ecdsa_output_file=$HOME/.zrchain/sidecar/keys/ecdsa.key.json
ecdsa_creation=$($HOME/zenrock-validators/utils/keygen/ecdsa/ecdsa --password $key_pass -output-file $ecdsa_output_file)
ecdsa_address=$(echo "$ecdsa_creation" | grep "Public address" | cut -d: -f2)

# Generate bls key
bls_output_file=$HOME/.zrchain/sidecar/keys/bls.key.json
$HOME/zenrock-validators/utils/keygen/bls/bls --password $key_pass -output-file $bls_output_file

# Output
echo "ecdsa address: $ecdsa_address"

Step 3: Top up your wallet address

Please fund your wallet addresses with Holesky $ETH before proceeding further.

Step 4: Set operator configuration

Ensure that you have configured TESTNET_HOLESKY_ENDPOINT, MAINNET_ENDPOINT, ETH_RPC_URL, ETH_WS_URL with your specific values. You can use Quicknode.com to get api keys.

# Declare variables
EIGEN_OPERATOR_CONFIG="$HOME/.zrchain/sidecar/eigen_operator_config.yaml"
TESTNET_HOLESKY_ENDPOINT="YOUR_TESTNET_HOLESKY_ENDPOINT"
MAINNET_ENDPOINT="YOUR_ETH_MAINNET_ENDPOINT"
OPERATOR_VALIDATOR_ADDRESS_TBD=$(zenrockd keys show wallet --bech val -a)
OPERATOR_ADDRESS_TBU=$ecdsa_address
ETH_RPC_URL="YOUR_TESTNET_HOLESKY_RPC"
ETH_WS_URL="YOUR_TESTNET_HOLESKY_WS"
ECDSA_KEY_PATH=$ecdsa_output_file
BLS_KEY_PATH=$bls_output_file

# Copy initial configuration files
cp $HOME/zenrock-validators/configs/eigen_operator_config.yaml $HOME/.zrchain/sidecar/
cp $HOME/zenrock-validators/configs/config.yaml $HOME/.zrchain/sidecar/

# Replace variables in config.yaml
sed -i "s|EIGEN_OPERATOR_CONFIG|$EIGEN_OPERATOR_CONFIG|g" "$HOME/.zrchain/sidecar/config.yaml"
sed -i "s|TESTNET_HOLESKY_ENDPOINT|$TESTNET_HOLESKY_ENDPOINT|g" "$HOME/.zrchain/sidecar/config.yaml"
sed -i "s|MAINNET_ENDPOINT|$MAINNET_ENDPOINT|g" "$HOME/.zrchain/sidecar/config.yaml"

# Replace variables in eigen_operator_config.yaml
sed -i "s|OPERATOR_VALIDATOR_ADDRESS_TBD|$OPERATOR_VALIDATOR_ADDRESS_TBD|g" "$HOME/.zrchain/sidecar/eigen_operator_config.yaml"
sed -i "s|OPERATOR_ADDRESS_TBU|$OPERATOR_ADDRESS_TBU|g" "$HOME/.zrchain/sidecar/eigen_operator_config.yaml"
sed -i "s|ETH_RPC_URL|$ETH_RPC_URL|g" "$HOME/.zrchain/sidecar/eigen_operator_config.yaml"
sed -i "s|ETH_WS_URL|$ETH_WS_URL|g" "$HOME/.zrchain/sidecar/eigen_operator_config.yaml"
sed -i "s|ECDSA_KEY_PATH|$ECDSA_KEY_PATH|g" "$HOME/.zrchain/sidecar/eigen_operator_config.yaml"
sed -i "s|BLS_KEY_PATH|$BLS_KEY_PATH|g" "$HOME/.zrchain/sidecar/eigen_operator_config.yaml"

Step 5: Download sidecar binary

wget -O $HOME/.zrchain/sidecar/bin/validator_sidecar https://releases.gardia.zenrocklabs.io/validator_sidecar-1.2.3
chmod +x $HOME/.zrchain/sidecar/bin/validator_sidecar

Step 6: Create and run sidecar service

Create service

sudo tee /etc/systemd/system/zenrock-testnet-sidecar.service > /dev/null <<EOF
[Unit]
Description=Validator Sidecar
After=network-online.target

[Service]
User=$USER
ExecStart=$HOME/.zrchain/sidecar/bin/validator_sidecar
Restart=on-failure
RestartSec=30
LimitNOFILE=65535
Environment="OPERATOR_BLS_KEY_PASSWORD=$key_pass"
Environment="OPERATOR_ECDSA_KEY_PASSWORD=$key_pass"
Environment="SIDECAR_CONFIG_FILE=$HOME/.zrchain/sidecar/config.yaml"

[Install]
WantedBy=multi-user.target
EOF

Enable and start service

sudo systemctl daemon-reload
sudo systemctl enable zenrock-testnet-sidecar.service
sudo systemctl start zenrock-testnet-sidecar.service

Step 7: Check the service logs

To check service logs use command below:

journalctl -fu zenrock-testnet-sidecar.service -o cat

Successfull Log examples:

{"level":"info","ts":1727294139.4385705,"caller":"operator/operator.go:250","msg":"Operator info","operatorId":[144,89,34,19,95,158,123,120,47,228,59,114,85,73,150,39,84,119,143,77,154,173,85,210,132,206,213,195,7,190,250,142],"operatorAddr":"0x68e305548619Ce71D562b851ff1adfb7e5369DB3","operatorG1Pubkey":"E([20150260775620749168755223143919346367674724303860875751315024817211815113340,5713528518001336848987890055463332760351549074437348780451495739349376234320])","operatorG2Pubkey":"E([9400781597017099172228313635710883835447541071342639102400258381712924127278+17588199816725806065286885136698384247231626887315665039610705603333445204237*u,21507870890336379219932542686750816691453493327464905543429790078496913285917+3341052853010856303076683482759015503204225193006075252832111461015148222443*u])"}
2024/09/25 19:55:39 initialized operator
2024/09/25 19:55:39 starting operator
{"level":"info","ts":1727294139.4387212,"caller":"operator/operator.go:262","msg":"Starting operator."}
{"level":"info","ts":1727294139.438742,"caller":"nodeapi/nodeapi.go:104","msg":"Starting node api server at address 0.0.0.0:9191"}
{"level":"info","ts":1727294139.4388723,"caller":"metrics/eigenmetrics.go:81","msg":"Starting metrics server at port 0.0.0.0:9292"}
{"level":"info","ts":1727294139.4389389,"caller":"nodeapi/nodeapi.go:238","msg":"node api server running","addr":"0.0.0.0:9191"}
{"level":"info","ts":1727294139.5475569,"caller":"chainio/avs_subscriber.go:63","msg":"Subscribed to new TaskManager tasks"}
2024/09/25 19:55:45 Received AVS contract state for  block 2407883
2024/09/25 19:55:45 Received prices: ETH/USD 2583.166191, ROCK/USD 0.000000
2024/09/25 19:56:00 Received prices: ETH/USD 2583.166191, ROCK/USD 0.000000
2024/09/25 19:56:00 Received AVS contract state for  block 2407884
2024/09/25 19:56:15 Received prices: ETH/USD 2583.166191, ROCK/USD 0.000000
2024/09/25 19:56:15 Received AVS contract state for  block 2407885

Step 8: Backup operator config and keys

To back up your sidecar configuration and keys, ensure you have a copy of the $HOME/.zrchain/sidecar directory.