Run a Stake Pool Part III — Register Guided mode

Part III — Register

Keys, the stake address, the pool. Every transaction the same way:

  1. Start hereThe picture, the dangers, how BRIAN runs it4 steps
  2. IInstallMachines, a hardened Ubuntu, the node5 steps
  3. IIConfigureChain, topology, offline machine, service5 steps
  4. IIIRegisterKeys, stake address, the pool5 steps
  5. IVRunKES, rewards, votes, upgrades8 steps
  6. VTipsPayments, files, swap, checklist4 steps

III-1 Payment and stake keys

The wallet that pays the deposits and receives the rewards.

  1. 1Buildsynced nodetx.raw
  2. 2Signair-gapped machinetx.signed
  3. 3Submitsynced nodeon chain
Build online, sign offline, submit online.
Air-gapped machine
cd ~/cold-keys
cardano-cli latest address key-gen \
  --verification-key-file payment.vkey \
  --signing-key-file payment.skey
cardano-cli latest stake-address key-gen \
  --verification-key-file stake.vkey \
  --signing-key-file stake.skey
cardano-cli latest address build \
  --payment-verification-key-file payment.vkey \
  --stake-verification-key-file stake.vkey \
  --mainnet \
  --out-file payment.addr
cardano-cli latest stake-address build \
  --stake-verification-key-file stake.vkey \
  --mainnet \
  --out-file stake.addr

Copy payment.addr, stake.addr and the .vkey files to a node. Send a small test amount, then at least 505 ADA plus your pledge:

Block producer or relay
cardano-cli latest query utxo --address $(cat payment.addr) --output-json

Check The UTxO list shows your amount. Compare the address character by character with the one on the air-gapped machine.

Next: Register the stake address →

III-2 Register the stake address

2 ADA deposit — build, sign, submit.

Block producer or relay
cardano-cli latest query protocol-parameters --out-file protocol.json
cardano-cli latest stake-address registration-certificate \
  --stake-verification-key-file stake.vkey \
  --key-reg-deposit-amt $(jq '.stakeAddressDeposit' protocol.json) \
  --out-file stake.cert
cardano-cli latest transaction build \
  --tx-in $(cardano-cli latest query utxo --address $(cat payment.addr) --output-json | jq -r 'keys[0]') \
  --change-address $(cat payment.addr) \
  --certificate-file stake.cert \
  --witness-override 2 \
  --out-file tx.raw
Air-gapped machine
cardano-cli latest transaction sign \
  --tx-body-file tx.raw \
  --signing-key-file payment.skey \
  --signing-key-file stake.skey \
  --mainnet \
  --out-file tx.signed
Block producer or relay
cardano-cli latest transaction submit --tx-file tx.signed

Note keys[0] spends the first UTxO. Too small? Name another one in --tx-in.

Check Transaction successfully submitted; a few minutes later query stake-address-info --address $(cat stake.addr) lists the address.

Next: Pool keys and the operational certificate →

III-3 Pool keys and the operational certificate

Cold keys stay offline; the block producer gets three files.

Air-gapped machinenever online · 2 encrypted backups
  • cold.skey
  • cold.counter
  • payment.skey
  • stake.skey
Block producerread-only for the node
  • kes.skey90 days
  • vrf.skeyalso in backup
  • node.cert
Publicsafe anywhere
  • *.vkey
  • payment.addr
  • stake.addr
  • pool ID
  • tx.raw · tx.signed
Where each key lives.
Air-gapped machine
cd ~/cold-keys
cardano-cli latest node key-gen \
  --cold-verification-key-file cold.vkey \
  --cold-signing-key-file cold.skey \
  --operational-certificate-issue-counter-file cold.counter
cardano-cli latest node key-gen-VRF \
  --verification-key-file vrf.vkey \
  --signing-key-file vrf.skey
cardano-cli latest node key-gen-KES \
  --verification-key-file kes.vkey \
  --signing-key-file kes.skey

The current KES period:

Block producer or relay
slotsPerKESPeriod=$(jq -r '.slotsPerKESPeriod' /etc/cardano/shelley-genesis.json)
slotNo=$(cardano-cli latest query tip | jq -r '.slot')
echo $(( slotNo / slotsPerKESPeriod ))
Air-gapped machine
cardano-cli latest node issue-op-cert \
  --kes-verification-key-file kes.vkey \
  --cold-signing-key-file cold.skey \
  --operational-certificate-issue-counter-file cold.counter \
  --kes-period <kes-period> \
  --out-file node.cert

Copy kes.skey, vrf.skey, node.cert to the block producer:

Block producer
sudo mkdir -p /var/lib/cardano/keys
sudo install -o cardano -g cardano -m 400 kes.skey vrf.skey node.cert /var/lib/cardano/keys/
shred -u kes.skey vrf.skey
sudo systemctl daemon-reload && sudo systemctl restart cardano-node
Next: Register the pool →

III-4 Register the pool

Metadata, two certificates, the 500 ADA deposit.

Publish poolMetaData.json at a URL of at most 64 characters (homepage or GitHub Pages). Ticker: 3 to 5 characters.

File
{
  "name": "Your Pool Name",
  "description": "What your pool stands for",
  "ticker": "TICK",
  "homepage": "https://yourpool.example"
}
Block producer or relay
cardano-cli latest stake-pool metadata-hash \
  --pool-metadata-file <(curl -s -L https://yourpool.example/poolMetaData.json) \
  --out-file poolMetaDataHash.txt
jq '.minPoolCost, .stakePoolDeposit' protocol.json

With poolMetaDataHash.txt on the air-gapped machine — amounts in lovelace (1 ₳ = 1,000,000): 1,000 ₳ pledge, 170 ₳ fixed cost, 1 % margin, three relays:

Air-gapped machine
cardano-cli latest stake-pool registration-certificate \
  --cold-verification-key-file cold.vkey \
  --vrf-verification-key-file vrf.vkey \
  --pool-pledge 1000000000 \
  --pool-cost 170000000 \
  --pool-margin 0.01 \
  --pool-reward-account-verification-key-file stake.vkey \
  --pool-owner-stake-verification-key-file stake.vkey \
  --single-host-pool-relay relay1.yourpool.example --pool-relay-port 6000 \
  --single-host-pool-relay relay2.yourpool.example --pool-relay-port 6000 \
  --single-host-pool-relay relay3.yourpool.example --pool-relay-port 6000 \
  --metadata-url https://yourpool.example/poolMetaData.json \
  --metadata-hash $(cat poolMetaDataHash.txt) \
  --mainnet \
  --out-file pool.cert
cardano-cli latest stake-address stake-delegation-certificate \
  --stake-verification-key-file stake.vkey \
  --cold-verification-key-file cold.vkey \
  --out-file deleg.cert
Block producer or relay
cardano-cli latest transaction build \
  --tx-in $(cardano-cli latest query utxo --address $(cat payment.addr) --output-json | jq -r 'keys[0]') \
  --change-address $(cat payment.addr) \
  --certificate-file pool.cert \
  --certificate-file deleg.cert \
  --witness-override 3 \
  --out-file tx.raw
Air-gapped machine
cardano-cli latest 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
Block producer or relay
cardano-cli latest transaction submit --tx-file tx.signed

Caution Relay names in the certificate, never the block producer. Keep the pledge in the owner wallet — below it, the pool earns nothing that epoch.

Next: Check the registration →

III-5 Check the registration

Your pool ID and its stake.

Air-gapped machine
cardano-cli latest stake-pool id --cold-verification-key-file cold.vkey --output-format bech32 > stakepoolid.txt
cat stakepoolid.txt
Block producer or relay
cardano-cli latest query stake-snapshot --stake-pool-id $(cat stakepoolid.txt)

Check The ID starting with pool1 shows up on cexplorer.io and adastat.net. Stake counts after two epoch boundaries.

Sources and license

Text, pictures and order are BRIAN's. Commands for system setup, the firewall, Mithril and the service file are adapted from the Cardano Developer Portal; every cardano-cli command was written for and run against cardano-cli 11.2.3. The node's own documentation always takes precedence.

Developer Portal license (MIT) — Copyright (c) 2021 Cardano Foundation

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.