The setup script below will require using 3 signers, and any number of full nodes.
Source: https://github.com/strangelove-ventures/horcrux
Official installation instructions: https://github.com/strangelove-ventures/horcrux/blob/main/docs/migrating.md
You'll be tempted to use AWS EC2 instances for this. Don't. We tried c6a.xl, c6i.xl, and t3a.xl, and all of them would run at ~20% or so usage (with ~25 networks connected, including tesnets) until suddenly they'd hit 100% CPU and disk usage and cause blocks to be missed. Don't get woken up multiple nights in a row - just go straight to bare metal. Horcrux is designed such that it can sit on the same servers as the nodes and still be secure.
When installing horcrux they recommend using the prebuilt binaries from the releases page. Pick the release corresponding to the tendermint dependancy for the go.mod of your chain binary. You should be able to get this with {binary} version --long.
If you don't want to do that work, the following instructions should work on any network updated since 2019.
Install like so:
wget https://github.com/strangelove-ventures/horcrux/releases/download/v2.0.0/horcrux_2.0.0_linux_amd64.tar.gz && \
tar -xzf horcrux_2.0.0_linux_amd64.tar.gz && sudo mv horcrux /usr/bin/horcrux && \
rm horcrux_2.0.0_linux_amd64.tar.gz README.md LICENSE.md
This will make it so signer 1 can scp the shared key to the other signers. This specific process will depend on what provider you use and your settings. We do not allow password login, so ssh keys must be copied manually. If you do allow password login, you can simply do an ssh-copy-id user@ip-of-cosigner
.
- create an ssh key: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
- copy ssh pubkey
cat ~/.ssh/id_ed25519.pub
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIcc77gKDU2ttbXv81oN2Mq6pqP9p/Cc6nf+//d+ddee ubuntu@my-ip
You'll need to manually copy signer 1's ssh pubkey.
# 1. open file
nano ~/.ssh/authorized_keys
# 2. create new line
# 3. paste in pubkey
# 4. save and close file
Copy the script from below. From EACH of your signers:
# 1. Open install_horcrux.sh
nano install_horcrux.sh
# 2. Paste in script, save, and exit
ctrl+v, ctrl+x, y
# 3. Make script executable
chmod +x install_horcrux.sh
Copy the priv_validator_key.json to ~/key.json on horcrux signer 1.
Install_horcrux.sh will do the following:
- create the .horcrux dir if it does not exist
- create config for signer
- create the horcrux service file
You MUST run the script on signers 2 and 3 before signer 1 in order to correctly split up the key.
If it's horcrux signer 1, it'll also take the priv_validator_key.json and split it up.
The dir will be as follows:
ubuntu@horcrux1:~$ tree .horcrux/
.horcrux/
├── akash
│ ├── config.yaml
│ ├── raft
│ │ ├── logs.dat
│ │ ├── snapshots
│ │ └── stable.dat
│ ├── share.json
│ └── state
│ ├── akashnet-2_priv_validator_state.json
│ └── akashnet-2_share_sign_state.json
├── bitcanna
│ ├── config.yaml
│ ├── raft
│ │ ├── logs.dat
│ │ ├── snapshots
│ │ └── stable.dat
│ ├── share.json
│ └── state
│ ├── bitcanna-1_priv_validator_state.json
│ └── bitcanna-1_share_sign_state.json
Helpful link for getting chain-ids: https://cosmos.directory/
./install_horcrux.sh <user> <node string> <chain_id> <network> <signer_1_ip> <signer_2_ip> <signer_3_ip> <signer_port> <signer_number> <path/to/key.json IF SIGNER 1>
# ./install_horcrux.sh ubuntu "tcp://131.148.169.128:26659,tcp://35.148.51.219:26659" dig-1 dig 1.25.215.77 14.214.21.26 3.138.24.17 2222 1 key.json
#! /bin/bash
USER=$1
SENTRIES=$2
CHAIN_ID=$3
NETWORK=$4
SIGNER_1_IP=$5
SIGNER_2_IP=$6
SIGNER_3_IP=$7
SIGNER_PORT=$8
SIGNER_NODE=$9
KEY=${10}
PORT=${11}
SIGNER_1="tcp://${SIGNER_1_IP}:${SIGNER_PORT}"
SIGNER_2="tcp://${SIGNER_2_IP}:${SIGNER_PORT}"
SIGNER_3="tcp://${SIGNER_3_IP}:${SIGNER_PORT}"
HOME="/home/${USER}/.horcrux/${NETWORK}"
HORCRUX_DIR="/home/${USER}/.horcrux"
[ ! -d "$HORCRUX_DIR" ] && mkdir ${HORCRUX_DIR} && echo "[INFO] Creating .horcrux dir under ${HORCRUX_DIR}"
if [ $SIGNER_NODE -eq 1 ]
then
echo "[INFO] Creating config for signer 1"
horcrux config init ${CHAIN_ID} ${SENTRIES} -c -p "${SIGNER_2}|2,${SIGNER_3}|3" -l "${SIGNER_1}" -t 2 --timeout 1500ms --home ${HOME}
elif [ $SIGNER_NODE -eq 2 ]
then
echo "[INFO] Creating config for signer 2"
horcrux config init ${CHAIN_ID} ${SENTRIES} -c -p "${SIGNER_1}|1,${SIGNER_3}|3" -l "${SIGNER_2}" -t 2 --timeout 1500ms --home ${HOME}
elif [ $SIGNER_NODE -eq 3 ]
then
echo "[INFO] Creating config for signer 3"
horcrux config init ${CHAIN_ID} ${SENTRIES} -c -p "${SIGNER_1}|1,${SIGNER_2}|2" -l "${SIGNER_3}" -t 2 --timeout 1500ms --home ${HOME}
else
echo "[ERROR] ERROR"
exit
fi
if [ ! -z "$KEY" ] && [ $SIGNER_NODE -eq 1 ]
then
echo "[INFO] priv_validator_key.json supplied, splitting..."
horcrux create-shares $KEY 2 3
echo "[INFO] Deleting key..."
rm ./$KEY
echo "[INFO] Moving Node ${SIGNER_NODE} signer share to ${HOME}/share.json"
mv private_share_1.json ${HOME}/share.json
echo "[INFO] Moving private_share_2.json to ${USER}@${SIGNER_2_IP}:.horcrux/${NETWORK}/share.json"
scp -P ${PORT} private_share_2.json ${USER}@${SIGNER_2_IP}:.horcrux/${NETWORK}/share.json && rm private_share_2.json
echo "[INFO] Moving private_share_3.json to ${USER}@${SIGNER_3_IP}:.horcrux/${NETWORK}/share.json"
scp -P ${PORT} private_share_3.json ${USER}@${SIGNER_3_IP}:.horcrux/${NETWORK}/share.json && rm private_share_3.json
fi
SERVICE_FILE=/etc/systemd/system/horcrux_${NETWORK}.service
echo "[INFO] Writing ${SERVICE_FILE}..."
sudo tee ${SERVICE_FILE} > /dev/null <<EOF
[Unit]
Description=${NETWORK} Horcrux Signer Node ${SIGNER_NODE}
After=network.target
[Service]
Type=simple
User=${USER}
WorkingDirectory=/home/${USER}
ExecStart=/usr/bin/horcrux cosigner start --home ${HOME}
Restart=on-failure
RestartSec=3
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload && sudo systemctl enable horcrux_${NETWORK}
echo "[INFO] Run sudo systemctl restart horcrux_${NETWORK} && sudo journalctl -fu horcrux_${NETWORK} to start the signer"