Generating Keys for the Block-producing Node
The block-producer node requires you to create 3 keys as defined in the Shelley ledger specs:
stake pool cold key (node.cert)
stake pool hot key (kes.skey)
stake pool VRF key (vrf.skey)
First, make a KES key pair.
cd $NODE_HOME
cardano-cli conway node key-gen-KES \
--verification-key-file kes.vkey \
--signing-key-file kes.skey
🔥 Cold keys must be generated and stored on your air-gapped offline machine. The cold keys are the files stored in $HOME/cold-keys.
Make a directory to store your cold keys
mkdir $HOME/cold-keys
pushd $HOME/cold-keys
Make a set of cold keys and create the cold counter file.
cardano-cli conway node key-gen \
--cold-verification-key-file node.vkey \
--cold-signing-key-file $HOME/cold-keys/node.skey \
--operational-certificate-issue-counter node.counter
Be sure to back up your all your keys to another secure storage device. Make multiple copies.
Determine the number of slots per KES period from the genesis file.
pushd +1
slotsPerKESPeriod=$(cat $NODE_HOME/shelley-genesis.json | jq -r '.slotsPerKESPeriod')
echo slotsPerKESPeriod: ${slotsPerKESPeriod}
Before continuing, your node must be fully synchronized to the blockchain. Otherwise, you won't calculate the latest KES period. Your node is synchronized when the epoch and slot# is equal to that found on a block explorer such as https://pooltool.io/
slotNo=$(cardano-cli conway query tip --mainnet | jq -r '.slot')
echo slotNo: ${slotNo}
Find the kesPeriod by dividing the slot tip number by the slotsPerKESPeriod.
kesPeriod=$((${slotNo} / ${slotsPerKESPeriod}))
echo kesPeriod: ${kesPeriod}
startKesPeriod=${kesPeriod}
echo startKesPeriod: ${startKesPeriod}
With this calculation, you can generate a operational certificate for your pool.
Copy kes.vkey to your cold environment.
Change the <startKesPeriod> value accordingly.
cardano-cli conway node issue-op-cert \
--kes-verification-key-file kes.vkey \
--cold-signing-key-file $HOME/cold-keys/node.skey \
--operational-certificate-issue-counter $HOME/cold-keys/node.counter \
--kes-period <startKesPeriod> \
--out-file node.cert
Copy node.cert to your hot environment.
Make a VRF key pair.
cardano-cli conway node key-gen-VRF \
--verification-key-file vrf.vkey \
--signing-key-file vrf.skey
Update vrf key permissions to read-only. You must also copy vrf.vkey to your cold environment.
chmod 400 vrf.skey
Stop your stake pool by running the following:
sudo systemctl stop cardano-node
Update your startup script with the new KES, VRF and Operation Certificate.
cat > $NODE_HOME/startCardanoNode.sh << EOF
DIRECTORY=$NODE_HOME
PORT=6000
HOSTADDR=0.0.0.0
TOPOLOGY=\${DIRECTORY}/topology.json
DB_PATH=\${DIRECTORY}/db
SOCKET_PATH=\${DIRECTORY}/db/socket
CONFIG=\${DIRECTORY}/config-bp.json
KES=\${DIRECTORY}/kes.skey
VRF=\${DIRECTORY}/vrf.skey
CERT=\${DIRECTORY}/node.cert
/usr/local/bin/cardano-node run +RTS -N -A16m -qg -qb -RTS --topology \${TOPOLOGY} --database-path \${DB_PATH} --socket-path \${SOCKET_PATH} --host-addr \${HOSTADDR} --port \${PORT} --config \${CONFIG} --shelley-kes-key \${KES} --shelley-vrf-key \${VRF} --shelley-operational-certificate \${CERT}
EOF
Now start your block producer node.
sudo systemctl start cardano-node
# Monitor with gLiveView
./gLiveView.sh
The following figure illustrates sample output of the gLiveView dashboard when Cardano Node is operating as a block producer.

Last updated