Difference between revisions of "Set up a Cardano staking pool"

From Organic Design wiki
m (Relay Quickstart: Added line to make reboot script executable.)
m (Relay Quickstart: Added man-db into install packages.)
Line 126: Line 126:
 
# packages
 
# packages
 
apt-get update
 
apt-get update
apt-get install -y jq curl libtool git automake build-essential bc -y
+
apt-get install -y jq curl libtool git automake build-essential bc man-db -y
  
 
# Libsodium
 
# Libsodium

Revision as of 19:52, 25 February 2021

Cone.png This article or section is a stub. Stubs are articles that have not yet received substantial attention from the authors. They are short or insufficient pieces of information and require additions to further increase the article's usefulness. The project values stubs as useful first steps toward complete articles.


The official documentation for setting up a node and configuring it as a stake pool on the mainnet is mostly very clear and complete. I was able to get my node compiled, installed and running pretty easily. But configuring the node to run as a stake pool is more complicated and the documentation seems to have some missing bits, so I'm documenting here just the specific parts that I had trouble with.

Prerequisites

You will need to have two servers and one offline machine, all running the node, so the first part of the procedure for compiling, installing and running is done on all three of the machines.

Procedure

First ensure that cardano-node is installed on the pool server, the relay server and a local machine (didn't have much luck with docker images).

Install cardano-addresses on the local machine.

Create a file called generate-keys.sh on the local machine with these contents (Note, the first line generates a phrase - remove it if you want to use an existing one.):

# Remove this line if you want to use an existing phrase stored in phrase.prv
cardano-address recovery-phrase generate > phrase.prv

# generate root keys
cat phrase.prv | cardano-address key from-recovery-phrase Shelley > rootkey.prv

cat rootkey.prv | cardano-address key public --with-chain-code > rootkey.pub
cat rootkey.prv | cardano-address key child 1852H/1815H/0H/0/0 > addr.prv
cat addr.prv | cardano-address key public --with-chain-code | cardano-address address payment --network-tag mainnet > payment.addr
cat rootkey.prv | cardano-address key child 1852H/1815H/0H/2/0 > stake.prv
cat stake.prv | cardano-address key public --with-chain-code | cardano-address address stake --network-tag mainnet > stake.addr


# Create payment and stake vkey/skey files

cardano-cli key convert-cardano-address-key --signing-key-file stake.prv --shelley-stake-key --out-file ShelleyStake.skey
cardano-cli key convert-cardano-address-key --signing-key-file addr.prv --shelley-payment-key --out-file ShelleyPayment.skey

cardano-cli key verification-key --signing-key-file ShelleyStake.skey --verification-key-file Ext_ShelleyStake.vkey
cardano-cli key verification-key --signing-key-file ShelleyPayment.skey --verification-key-file Ext_ShelleyPayment.vkey

cardano-cli key non-extended-key --extended-verification-key-file Ext_ShelleyStake.vkey --verification-key-file ShelleyStake.vkey
cardano-cli key non-extended-key --extended-verification-key-file Ext_ShelleyPayment.vkey --verification-key-file ShelleyPayment.vkey

cardano-cli stake-address build --stake-verification-key-file ShelleyStake.vkey --out-file ShelleyStake.addr --mainnet
cardano-cli address build --payment-verification-key-file ShelleyPayment.vkey  --stake-verification-key-file ShelleyStake.vkey --out-file ShelleyPayment.addr --mainnet

# Nicer formatting
mkdir out

cp ShelleyPayment.addr out/payment.addr
cp ShelleyPayment.skey out/payment.skey
cp ShelleyPayment.vkey out/payment.vkey

cp ShelleyStake.addr out/stake.addr
cp ShelleyStake.skey out/stake.skey
cp ShelleyStake.vkey out/stake.vkey

Once you have that script ready disconnect from the internet and insert a fresh usb create a directory on it called wallet-keys and go into that directory in the terminal and run the script (script will work in your current working directory).
The script will have generated the keys you want int the out/ directory, copy the two .addr files onto your machine since these are not secret, and remove the drive.

On the server run:

cardano-cli query protocol-parameters \
  --mainnet \
  --out-file protocol.json


Send the keyDeposit amount (2 Ada at time of writing) as defined in the protocol.json and 1.5 Ada (1 for minimum wallet amount and 0.5 for transaction fees) to the payment address contained in payment.addr that you copied of the usb.

You should then continue as per the documentation page 4 but on step 5 generate the pool keys offline on the usb. Note: you will need to run any queries on the server (which has the node running) and formulate the transactions locally - disconnecting from the net, generating certs and signing transactions - then copy the transaction to the server to get fee size and actually send the transaction.

Skip step 6. Key Evolving Signature and KES period as it is redundant because it is just reiterating over the commands done in step 5.

Note on step 8 you can add the pledge balance to the address at a later time but your node will not produce blocks until the pledge is met. Note: for some reason the pre-calculated fee is different than what it should be - you just have to fail and use the fee that it says you should have used. If you want to use DNS use --single-host-pool-relay instead of --pool-relay-ipv4.

Once you hit step 9. Start your nodes copy kes.skey and vrf.skey from the offline usb to the computer and upload them to the server when you reconnect.

I recommend to write some startup scripts (for the block producing server, the relay and Prometheus) that log to a file like this:

#!/bin/sh
nohup /root/.local/bin/cardano-node run \
--topology /root/config/mainnet-topology.json \
--database-path /root/data \
--socket-path /root/data/node.socket \
--host-addr <IP> \
--port <PORT> \
--config /root/config/mainnet-config.json \
--shelley-kes-key /root/keys/kes.skey \
--shelley-vrf-key /root/keys/vrf.skey \
>> /root/debug.log

And a corresponding systemd service:

# /etc/systemd/system/cardano.service
########################################
[Unit]
Description=Starts the cardano node.

[Service]
Type=simple
ExecStart=/root/start.sh
Restart=on-failure
RestartSec=3
KillMode=SIGINT
RestartKillSignal=SIGINT

[Install]
WantedBy=multi-user.target

Start with service cardano start

I would recommend changing minSeverity in mainnet-config.json to Warning for efficiency and log readability.

Testnet Procedure

Everything went smoothly until I got to Register stake address on the blockchain. The main issue is that you need to have some balance in your payment.addr address, and the previous step of creating a sample transaction is not optional, things in that step such as protocol.json and the output hash are referred to in this step.

The Key Evolving Signature and KES period section is redundant because it is done already in the Generate your stake pool keys section, but it is explained better in the later one.

The Configure topology files for block-producing and relay nodes section requires that we have a relay node IP address.

Relay Quickstart

Copy the binaries to the relay in /root/.local/bin/.

cd ~

# packages
apt-get update
apt-get install -y jq curl libtool git automake build-essential bc man-db -y

# Libsodium
mkdir src
cd src
git clone https://github.com/input-output-hk/libsodium
cd libsodium
git checkout 66f017f1
./autogen.sh
./configure
make
make install
cd ~

# setup paths
echo "export PATH=\"/root/.local/bin:/root/.local/bin/cardano-node:/root/.local/bin/cardano-cli:$PATH\"" >> .bashrc
echo "export CARDANO_NODE_SOCKET_PATH=/root/data/node.socket" >> .bashrc
echo "export LD_LIBRARY_PATH=\"/usr/local/lib:$LD_LIBRARY_PATH\"" >> .bashrc
echo "export PKG_CONFIG_PATH=\"/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH\"" >> .bashrc
source .bashrc

# get config
mkdir config
cd config
wget https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/mainnet-config.json
wget https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/mainnet-byron-genesis.json
wget https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/mainnet-shelley-genesis.json
wget https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/mainnet-topology.json
cd ~

# topology updater
mkdir scripts
cd scripts
wget https://raw.githubusercontent.com/cardano-community/guild-operators/alpha/scripts/cnode-helper-scripts/env
wget https://raw.githubusercontent.com/cardano-community/guild-operators/alpha/scripts/cnode-helper-scripts/topologyUpdater.sh
wget https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/gLiveView.sh

chmod +x topologyUpdater.sh
chmod +x gLiveView.sh
cd ~

# startup script
echo "#!/bin/sh

export PATH=\"/root/.local/bin:/root/.local/bin/cardano-node:/root/.local/bin/cardano-cli:$PATH\"
export CARDANO_NODE_SOCKET_PATH=/root/data/node.socket
export LD_LIBRARY_PATH=\"/usr/local/lib:$LD_LIBRARY_PATH\"
export PKG_CONFIG_PATH=\"/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH\"

cardano-node run \
--topology /root/config/mainnet-topology.json \
--database-path /root/data \
--socket-path /root/data/node.socket \
--host-addr 0.0.0.0 \
--port 3002 \
--config /root/config/mainnet-config.json \
>> /root/debug.log" > /root/start.sh

chmod +x start.sh

# Restart script
echo "#!/bin/sh

/bin/systemctl restart cardano.service" > /root/reboot-relay.sh

chmod +x /root/reboot-relay.sh

# systemd script
echo "
# /etc/systemd/system/cardano.service
########################################
[Unit]
Description=Starts the cardano node.

[Service]
Type=simple
ExecStart=/root/start.sh
Restart=on-failure
RestartSec=3
KillMode=SIGINT
RestartKillSignal=SIGINT

[Install]
WantedBy=multi-user.target" >> /etc/systemd/system/cardano.service

Remember to edit the Prometheus IP in /root/config/mainnet-config.json to 0.0.0.0
Add relays to /root/config/mainet-topology.json
Edit your static IP address in /root/start.sh

Edit the /root/scripts/env file to have the following configuration:

CCLI="/root/.local/bin/cardano-cli"
CNODE_PORT=3002
CONFIG="/root/config/mainnet-config.json"
TOPOLOGY="/root/config/mainnet-topology.json"

Edit the /root/scripts/topologyUpdater.sh file to include your block producing node's ip in CUSTOM_PEERS (Don't change the CNODE_HOSTNAME variable to an ip address.) Also set BATCH_AUTO_UPDATE=Y
Test the topology updater script runs by running it: /root/scripts/topologyUpdater.sh
Add it as a cron job crontab -e

0 * * * * /root/scripts/topologyUpdater.sh >> /root/debug-topology-updater.log
30 0 * * * /root/reboot-relay.sh >> /root/debug.log

Note change the second 0 on the reboot-relay script to what hour of the day you want it to run - best space out the relay restarts as far as possible from the other relays, we run it on the half hour so that topology updater does not try to query it when it is restarting.
You will need wait until the second time it can execute the topology updater (1 hour after the first time) for it to update the providers.


Run /root/scripts/gLiveView.sh to get information on how the relay is running.

Stopping

The Cardano node should always be stoped with the SIGINT signal (e.g. kill -SIGINT <PROCESS>) otherwise it might not shutdown cleanly, it is designed to recover after a messy shutdown but next startup might be 30-40 minutes instead of the usual 5 minutes.

Updating Pool Registration

Pool registrations can be updated by simply sending a new pool registration certificate - no need to de-register! Just follow the same process but don't worry about the pool deposit or adding a delegation certificate.

Delegation (Offline)

If you want to delegate to a pool without being required to be online first ensure that you have access to your payment/stake keys (see script under procedure).

Generate your stake address registration certificate and your delegation certificate:

cardano-cli stake-address registration-certificate \
	--stake-verification-key-file stake.vkey \
	--out-file stake.cert

# Delegate to PUDIM! (or use the pool id of the pool you wish to delegate to)
cardano-cli stake-address delegation-certificate \
	--stake-verification-key-file stake.vkey \
	--stake-pool-id pool1ujcu3myfg9wwvdyh2ks653954lamtufy3lefjs73jrr327q53j4 \
	--out-file delegation.cert

Then generate a raw transaction to calculate fees:

cardano-cli transaction build-raw \
	--tx-in <TxHash>#<TxIx> \
	--tx-out <PAYMENT ADDRESS>+0 \
	--invalid-hereafter 0 \
	--fee 0 \
	--out-file tx.raw \
	--certificate-file stake.cert \
	--certificate-file delegation.cert

Upload tx.raw to an online machine that has cardano-node running to calculate fees.
Once you know how much fees will be calculate your change using BALANCE - KEYDEPOSIT - FEES (see procedure if you don't know what pool deposit is - probably 2 Ada).
The build the transaction for real - note the order of certificate is important!

cardano-cli transaction build-raw \
	--tx-in <TxHash>#<TxIx> \
	--tx-out <PAYMENT ADDRESS>+<CHANGE> \
	--invalid-hereafter <SLOT NO> \
	--fee <FEE> \
	--out-file tx.raw \
	--certificate-file stake.cert \
	--certificate-file delegation.cert

Sign it:

cardano-cli transaction sign \
	--tx-body-file tx.raw \
	--signing-key-file payment.skey \
	--signing-key-file stake.skey \
	--mainnet \
	--out-file tx.signed

Upload the signed transaction tx.signed to your online machine and send it!

cardano-cli transaction submit \
	--tx-file tx.signed \
	--mainnet

De-registering Certificates

To register the stake key you create a registration certificate which requires a key deposit, to get that deposit back follow the same steps as registering a certificate but use deregistration-certificate instead of registration-certificate and add the key deposit to the change address.

Prometheus

The documentation has pretty good information on how to get this running but I had to change the ip (under Prometheus) in mainnet-config.json to 0.0.0.0.

You need to set the data directory otherwise it defaults to ~/data what cardano-node is using --storage.tsdb.path /root/prometheus/data

My prometheus.yml config uses this config:

scrape_configs:
  - job_name: 'cardano' # To scrape data from the block producing node
    scrape_interval: 5s
    static_configs:
      - targets: ['<Block Producing Node IP>:12798']

  - job_name: 'relay' # To scrape data from the relay node
    scrape_interval: 5s
    static_configs:
      - targets: ['<Relay Node IP>:12798']

  - job_name: 'node' # To scrape data from a node exporter to monitor your linux host metrics.
    scrape_interval: 5s
    static_configs:
      - targets: ['<Block Producing Node IP>:9100']

Debugging

Era Mismatch

If you get errors running some commands saying there is an era mismatch like the following:

Shelley command failed: query utxo  Error: A query from a certain era was applied to a ledger from a different era: EraMismatch {ledgerEraName = "Allegra", otherEraName = "Shelley"}

This is because the ledger is on the "Allegra" soft fork while the cli is running "Shelley", you need to either update the cli and/or add a parameter to the command specifying the era like so:

cardano-cli query utxo \
	--address $(cat payment.addr) \
	--mainnet \
	--allegra-era

Cardano Node Socket

If you have issues with cli commands referencing the cardano node socket, first ensure that the node is running (it can take a minute to generate the node.socket file in the database, then ensure the environment variable has been set.

export CARDANO_NODE_SOCKET_PATH=path/to/db/node.socket

Transactions

If your transaction fails due to a input-output mismatch, you need to check that the inputs (--tx-in) values sum to the output values (--tx-out) plus the fee's (--fee).

If your transaction fails due to output too small, you need to check that all the outputs (including change addresses) have the minimum value as set in the "minUTxOValue" parameter in the genesis block config (1000000 Lovelace or 1 Ada at the time of writing).

Floating IP/DNS

Floating IP's for some reason will not work with cardano-node so if you want the flexibility of floating IP's use DNS instead (with --single-host-pool-relay).

Staking from a paper wallet

todo... I'll document this properly after I've done it myself

The idea is to first temporarily install a Daedalus on an offline live booted Linux and then restore a paper wallet into it with the 24 word backup phrase. Then we should be able to interact with the running wallet's associated node from the CLI to create and sign a delegation transaction. That transaction can then be broadcast to the network using any online Cardano node. This Shelley exercise explains the process of CLI delegation.

First you'll need to find the port that your Daedalus is running on:

ps x | grep cardano-node

Then you'll need to create the key files:

cardano-cli shelley address key-gen \
--verification-key-file payment.vkey \
--signing-key-file payment.skey \
--host-addr 127.0.0.1 \
--port PORT

Todo: We need to use a registered stake address that we have the keys for.

Create a delegation certificate, here the pool is the characters after the 5820 in the cborHex of the target pool's cold.vkey file.

cardano-cli shelley stake-address delegation-certificate \
--stake-verification-key-file stake.vkey \
--cold-verification-key-hash POOL \
--out-file delegation.cert \
--host-addr 127.0.0.1 \
--port PORT


Draft the transaction:

cardano-cli shelley transaction build-raw \
--tx-in <UTXO>#<TxIx> \
--tx-out $(cat payment.addr)+0 \
--ttl 0 \
--fee 0 \
--out-file tx.draft \
--certificate-file delegation.cert


Calculate the fees:

cardano-cli shelley transaction calculate-min-fee \
--tx-body-file tx.draft \
--tx-in-count 1 \
--tx-out-count 1 \
--mainnet \
--witness-count 1 \
--byron-witness-count 0 \
--protocol-params-file protocol.json


Build the transaction:

cardano-cli shelley transaction build-raw \
--tx-in <UTXO>#<TxIx> \
--tx-out $(cat payment.addr)+<CHANGE IN LOVELACE> \
--ttl <TTL> \
--fee <FEE> \
--out-file tx.raw \
--certificate-file pool-registration.cert \
--certificate-file delegation.cert


Sign the transaction:

cardano-cli shelley transaction sign \
--tx-body-file tx.raw \
--signing-key-file payment.skey \
--signing-key-file stake.skey \
--signing-key-file cold.skey \
--mainnet \
--out-file tx.signed


Submit the transaction:

cardano-cli shelley transaction submit --tx-file tx.signed --mainnet

Resources

See also