English
๐Ÿ› 
18. Operational and Maintenance Tips

โ€‹
๐Ÿค–
18.1 Rotate pool's KES keys - Updating the operational cert with a new KES Period

You are required to regenerate the hot keys and issue a new operational certificate, a process called rotating the KES keys, when the hot keys expire.
Mainnet: KES keys will be valid for 120 rotations or 90 days
When it's time to issue a new operational certificate, run the following to find the starting KES period.
block producer node
1
cd $NODE_HOME
2
slotNo=$(cardano-cli query tip --mainnet | jq -r '.slot')
3
slotsPerKESPeriod=$(cat $NODE_HOME/${NODE_CONFIG}-shelley-genesis.json | jq -r '.slotsPerKESPeriod')
4
kesPeriod=$((${slotNo} / ${slotsPerKESPeriod}))
5
startKesPeriod=${kesPeriod}
6
echo startKesPeriod: ${startKesPeriod}
Copied!
Make a new KES key pair.
block producer node
1
cd $NODE_HOME
2
cardano-cli node key-gen-KES \
3
--verification-key-file kes.vkey \
4
--signing-key-file kes.skey
Copied!
Copy kes.vkey to your cold environment.
Verify the current value of your node.counter is valid.
1
cat $HOME/cold-keys/node.counter
2
โ€‹
3
# Example where value is 6
4
# "Next certificate issue number: 6"
Copied!
A valid value of your node.counter MUST be greater than a recently created block's OpCertC value.
To find your pool's current OpCertC value, search for your pool on https://adapools.org/ and check the Blocks tab, then look at the OpCertC column.
For example, if your OpCerC value is 5, then your node.counter should be"Next certificate issue number: 6"
If not, then you need to increment the counter by running the below command with issue-op-cert.
Create the new node.cert file with the following command. Update <startKesPeriod> with the value from above.
air-gapped offline machine
1
cd $NODE_HOME
2
chmod u+rwx $HOME/cold-keys
3
cardano-cli node issue-op-cert \
4
--kes-verification-key-file kes.vkey \
5
--cold-signing-key-file $HOME/cold-keys/node.skey \
6
--operational-certificate-issue-counter $HOME/cold-keys/node.counter \
7
--kes-period <startKesPeriod> \
8
--out-file node.cert
9
chmod a-rwx $HOME/cold-keys
Copied!
Copy node.cert back to your block producer node.
Stop and restart your block producer node to complete this procedure.
block producer node
manual
1
sudo systemctl restart cardano-node
Copied!
1
cd $NODE_HOME
2
killall -s 2 cardano-node
3
./startBlockProducingNode.sh
Copied!
โ€‹
๐Ÿ’ก
Best practice recommendation: It's now a good time to make a new backup of your new node.counter file and cold-keys directory to another USB drive or other offline location.

โ€‹
๐Ÿ”ฅ
18.2 Resetting the installation

Want a clean start? Re-using existing server? Forked blockchain?
Delete git repo, and then rename your previous $NODE_HOME and cold-keys directory (or optionally, remove). Now you can start this guide from the beginning again.
1
rm -rf $HOME/git/cardano-node/ $HOME/git/libsodium/
2
mv $NODE_HOME $(basename $NODE_HOME)_backup_$(date -I)
3
mv $HOME/cold-keys $HOME/cold-keys_backup_$(date -I)
Copied!

โ€‹
๐ŸŒŠ
18.3 Resetting the databases

Corrupted or stuck blockchain? Delete all db folders.
1
cd $NODE_HOME
2
rm -rf db
Copied!

โ€‹
๐Ÿ“
18.4 Changing the pledge, fee, margin, etc.

Important Reminder
๐Ÿ”ฅ
Any changes made in this section take effect in two epochs. A common mistake is lowering the pledge amount and removing funds too soon. This results in zero rewards as the current live pledge amount is no longer met.
Need to change your pledge, fee, margin, pool IP/port, or metadata? Simply resubmit your stake pool registration certificate.
Reminder: There is no requirement to pay the 500 ADA stake pool deposit again.
First, generate the protocol-parameters.
block producer node
1
cardano-cli query protocol-parameters \
2
--mainnet \
3
--out-file $NODE_HOME/params.json
Copied!
If you're changing your poolMetaData.json, remember to calculate the hash of your metadata file and re-upload the updated poolMetaData.json file. Refer to section 9 for information.
block producer node
1
cardano-cli stake-pool metadata-hash --pool-metadata-file poolMetaData.json > poolMetaDataHash.txt
Copied!
If you changed your poolMetaData.json, copy poolMetaDataHash.txt to your cold environment.
Update the below registration-certificate transaction with your desired stake pool settings.
If you have multiple relay nodes, refer to section 12 and change your parameters appropriately.
metadata-url must be no longer than 64 characters.
air-gapped offline machine
1
cardano-cli stake-pool registration-certificate \
2
--cold-verification-key-file $HOME/cold-keys/node.vkey \
3
--vrf-verification-key-file vrf.vkey \
4
--pool-pledge 1000000000 \
5
--pool-cost 345000000 \
6
--pool-margin 0.20 \
7
--pool-reward-account-verification-key-file stake.vkey \
8
--pool-owner-stake-verification-key-file stake.vkey \
9
--mainnet \
10
--single-host-pool-relay <dns based relay, example ~ relaynode1.myadapoolnamerocks.com> \
11
--pool-relay-port 6000 \
12
--metadata-url <url where you uploaded poolMetaData.json> \
13
--metadata-hash $(cat poolMetaDataHash.txt) \
14
--out-file pool.cert
Copied!
minPoolCost is 340000000 lovelace or 340 ADA. Therefore, your --pool-cost must be at a minimum this amount.
Here we are pledging 1000 ADA with a fixed pool cost of 345 ADA and a pool margin of 20%.
Copy pool.cert to your hot environment.
Pledge stake to your stake pool.
air-gapped offline machine
1
cardano-cli stake-address delegation-certificate \
2
--stake-verification-key-file stake.vkey \
3
--cold-verification-key-file $HOME/cold-keys/node.vkey \
4
--out-file deleg.cert
Copied!
Copy deleg.cert to your hot environment.
You need to find the tip of the blockchain to set the invalid-hereafter parameter properly.
block producer node
1
currentSlot=$(cardano-cli query tip --mainnet | jq -r '.slot')
2
echo Current Slot: $currentSlot
Copied!
Find your balance and UTXOs.
block producer node
1
cardano-cli query utxo \
2
--address $(cat payment.addr) \
3
--mainnet > fullUtxo.out
4
โ€‹
5
tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out
6
โ€‹
7
cat balance.out
8
โ€‹
9
tx_in=""
10
total_balance=0
11
while read -r utxo; do
12
in_addr=$(awk '{ print $1 }' <<< "${utxo}")
13
idx=$(awk '{ print $2 }' <<< "${utxo}")
14
utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
15
total_balance=$((${total_balance}+${utxo_balance}))
16
echo TxHash: ${in_addr}#${idx}
17
echo ADA: ${utxo_balance}
18
tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
19
done < balance.out
20
txcnt=$(cat balance.out | wc -l)
21
echo Total ADA balance: ${total_balance}
22
echo Number of UTXOs: ${txcnt}
Copied!
Run the build-raw transaction command.
The invalid-hereafter value must be greater than the current tip. In this example, we use current slot + 10000.
block producer node
1
cardano-cli transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${total_balance} \
4
--invalid-hereafter $(( ${currentSlot} + 10000)) \
5
--fee 0 \
6
--certificate-file pool.cert \
7
--certificate-file deleg.cert \
8
--out-file tx.tmp
Copied!
Calculate the minimum fee:
block producer node
1
fee=$(cardano-cli transaction calculate-min-fee \
2
--tx-body-file tx.tmp \
3
--tx-in-count ${txcnt} \
4
--tx-out-count 1 \
5
--mainnet \
6
--witness-count 3 \
7
--byron-witness-count 0 \
8
--protocol-params-file params.json | awk '{ print $1 }')
9
echo fee: $fee
Copied!
Calculate your change output.
block producer node
1
txOut=$((${total_balance}-${fee}))
2
echo txOut: ${txOut}
Copied!
Build the transaction.
block producer node
1
cardano-cli transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${txOut} \
4
--invalid-hereafter $(( ${currentSlot} + 10000)) \
5
--fee ${fee} \
6
--certificate-file pool.cert \
7
--certificate-file deleg.cert \
8
--out-file tx.raw
Copied!
Copy tx.raw to your cold environment.
Sign the transaction.
air-gapped offline machine
1
cardano-cli transaction sign \
2
--tx-body-file tx.raw \
3
--signing-key-file payment.skey \
4
--signing-key-file $HOME/cold-keys/node.skey \
5
--signing-key-file stake.skey \
6
--mainnet \
7
--out-file tx.signed
Copied!
Copy tx.signed to your hot environment.
Send the transaction.
block producer node
1
cardano-cli transaction submit \
2
--tx-file tx.signed \
3
--mainnet
Copied!
Changes take effect in two epochs. After the next epoch transition, verify that your pool settings are correct.
block producer node
1
cardano-cli query ledger-state --mainnet > ledger-state.json
2
jq -r '.esLState._delegationState._pstate._pParams."'"$(cat stakepoolid.txt)"'" // empty' ledger-state.json
Copied!

โ€‹
๐Ÿงฉ
18.5 Transferring files over SSH

Common use cases can include
  • Downloading backups of stake/payment keys
  • Uploading a new operational certificate to the block producer from an offline node

To download files from a node to your local PC

1
ssh <USERNAME>@<IP ADDRESS> -p <SSH-PORT>
2
rsync -avzhe โ€œssh -p <SSH-PORT>โ€ <USERNAME>@<IP ADDRESS>:<PATH TO NODE DESTINATION> <PATH TO LOCAL PC DESTINATION>
Copied!
Example:
ssh [email protected] -p 12345
rsync -avzhe "ssh -p 12345" [email protected]:/home/myusername/cardano-my-node/stake.vkey ./stake.vkey

To upload files from your local PC to a node

1
ssh <USERNAME>@<IP ADDRESS> -p <SSH-PORT>
2
rsync -avzhe โ€œssh -p <SSH-PORT>โ€ <PATH TO LOCAL PC DESTINATION> <USERNAME>@<IP ADDRESS>:<PATH TO NODE DESTINATION>
Copied!
Example:
ssh [email protected] -p 12345
rsync -avzhe "ssh -p 12345" ./node.cert [email protected]:/home/myusername/cardano-my-node/node.cert

โ€‹
โœ…
18.7 Verify your stake pool ticker with ITN key

In order to defend against spoofing and hijacking of reputable stake pools, a owner can verify their ticker by proving ownership of an ITN stake pool.
Incentivized Testnet phase of Cardanoโ€™s Shelley era ran from late November 2019 to late June 2020. If you participated, you can verify your ticker.
Make sure the ITN's jcli binaries are present in $NODE_HOME. Use jcli to sign your stake pool id with your itn_owner.skey
air-gapped offline machine
1
./jcli key sign --secret-key itn_owner.skey stakepoolid.txt --output stakepoolid.sig
Copied!
Visit pooltool.io and enter your owner public key and pool id witness data in the metadata section.
Find your pool id witness with the following command.
air-gapped offline machine
1
cat stakepoolid.sig
Copied!
Find your owner public key in the file you generated on ITN. This data might be stored in a file ending in .pub
Finally, follow instructions to update your pool registration data with the pooltool generated metadata-url and metadata-hash. Notice the metadata has an "extended" field which proves your ticker ownership since ITN.

โ€‹
๐Ÿ“š
18.8 Updating your node's configuration files

Keep your config files fresh by downloading the latest .json files.
1
cd $NODE_HOME
2
wget -N https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/${NODE_CONFIG}-config.json
3
wget -N https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/${NODE_CONFIG}-byron-genesis.json
4
wget -N https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/${NODE_CONFIG}-shelley-genesis.json
5
wget -N https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/${NODE_CONFIG}-alonzo-genesis.json
6
wget -N https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/${NODE_CONFIG}-topology.json
7
sed -i ${NODE_CONFIG}-config.json \
8
-e "s/TraceBlockFetchDecisions\": false/TraceBlockFetchDecisions\": true/g" \
9
-e "s/127.0.0.1/0.0.0.0/g"
Copied!

โ€‹
๐Ÿ’ธ
18.9 Send a simple transaction example

Let's walk through an example to send 10 ADA to CoinCashew's tip address
๐Ÿ™ƒ
The minimum amount, or smallest UTXO, you can send in one transaction is 1 ADA.
First, find the tip of the blockchain to set the invalid-hereafter parameter properly.
block producer node
1
currentSlot=$(cardano-cli query tip --mainnet | jq -r '.slot')
2
echo Current Slot: $currentSlot
Copied!
Set the amount to send in lovelaces.
โœจ
Remember 1 ADA = 1,000,000 lovelaces.
block producer node
1
amountToSend=10000000
2
echo amountToSend: $amountToSend
Copied!
Set the destination address which is where you're sending funds to.
block producer node
1
destinationAddress=addr1qxhazv2dp8yvqwyxxlt7n7ufwhw582uqtcn9llqak736ptfyf8d2zwjceymcq6l5gxht0nx9zwazvtvnn22sl84tgkyq7guw7q
2
echo destinationAddress: $destinationAddress
Copied!
Find your balance and UTXOs.
block producer node
1
cardano-cli query utxo \
2
--address $(cat payment.addr) \
3
--mainnet > fullUtxo.out
4
โ€‹
5
tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out
6
โ€‹
7
cat balance.out
8
โ€‹
9
tx_in=""
10
total_balance=0
11
while read -r utxo; do
12
in_addr=$(awk '{ print $1 }' <<< "${utxo}")
13
idx=$(awk '{ print $2 }' <<< "${utxo}")
14
utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
15
total_balance=$((${total_balance}+${utxo_balance}))
16
echo TxHash: ${in_addr}#${idx}
17
echo ADA: ${utxo_balance}
18
tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
19
done < balance.out
20
txcnt=$(cat balance.out | wc -l)
21
echo Total ADA balance: ${total_balance}
22
echo Number of UTXOs: ${txcnt}
Copied!
Run the build-raw transaction command.
block producer node
1
cardano-cli transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+0 \
4
--tx-out ${destinationAddress}+0 \
5
--invalid-hereafter $(( ${currentSlot} + 10000)) \
6
--fee 0 \
7
--out-file tx.tmp
Copied!
Calculate the current minimum fee:
block producer node
1
fee=$(cardano-cli transaction calculate-min-fee \
2
--tx-body-file tx.tmp \
3
--tx-in-count ${txcnt} \
4
--tx-out-count 2 \
5
--mainnet \
6
--witness-count 1 \
7
--byron-witness-count 0 \
8
--protocol-params-file params.json | awk '{ print $1 }')
9
echo fee: $fee
Copied!
Calculate your change output.
block producer node
1
txOut=$((${total_balance}-${fee}-${amountToSend}))
2
echo Change Output: ${txOut}
Copied!
Build your transaction.
block producer node
1
cardano-cli transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${txOut} \
4
--tx-out ${destinationAddress}+${amountToSend} \
5
--invalid-hereafter $(( ${currentSlot} + 10000)) \
6
--fee ${fee} \
7
--out-file tx.raw
Copied!
Copy tx.raw to your cold environment.
Sign the transaction with the payment secret key.
air-gapped offline machine
1
cardano-cli transaction sign \
2
--tx-body-file tx.raw \
3
--signing-key-file payment.skey \
4
--mainnet \
5
--out-file tx.signed
Copied!
Copy tx.signed to your hot environment.
Send the signed transaction.
block producer node
1
cardano-cli transaction submit \
2
--tx-file tx.signed \
3
--mainnet
Copied!
Check if the funds arrived.
block producer node
1
cardano-cli query utxo \
2
--address ${destinationAddress} \
3
--mainnet
Copied!
You should see output similar to this showing the funds you sent.
1
TxHash TxIx Lovelace
2
----------------------------------------------------------------------------------------
3
100322a39d02c2ead.... 0 10000000
Copied!

โ€‹
๐Ÿ”“
18.10 Harden your node's security

Do not skimp on this critical step to protect your pool and reputation.

โ€‹
๐Ÿฐ
18.11 Claim your rewards

Let's walk through an example to claim your stake pools rewards.
Rewards are accumulated in the stake.addr address.
First, find the tip of the blockchain to set the invalid-hereafter parameter properly.
block producer node
1
currentSlot=$(cardano-cli query tip --mainnet | jq -r '.slot')
2
echo Current Slot: $currentSlot
Copied!
Set the amount to send in lovelaces.
โœจ
Remember 1 ADA = 1,000,000 lovelaces.
block producer node
1
rewardBalance=$(cardano-cli query stake-address-info \
2
--mainnet \
3
--address $(cat stake.addr) | jq -r ".[0].rewardAccountBalance")
4
echo rewardBalance: $rewardBalance
Copied!
Set the destination address which is where you're moving your reward to. This address must have a positive balance to pay for transaction fees.
block producer node
1
destinationAddress=$(cat payment.addr)
2
echo destinationAddress: $destinationAddress
Copied!
Find your payment.addr balance, utxos and build the withdrawal string.
block producer node
1
cardano-cli query utxo \
2
--address $(cat payment.addr) \
3
--mainnet > fullUtxo.out
4
โ€‹
5
tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out
6
โ€‹
7
cat balance.out
8
โ€‹
9
tx_in=""
10
total_balance=0
11
while read -r utxo; do
12
in_addr=$(awk '{ print $1 }' <<< "${utxo}")
13
idx=$(awk '{ print $2 }' <<< "${utxo}")
14
utxo_balance=$(awk '{ print $3 }' <<< "${utxo}")
15
total_balance=$((${total_balance}+${utxo_balance}))
16
echo TxHash: ${in_addr}#${idx}
17
echo ADA: ${utxo_balance}
18
tx_in="${tx_in} --tx-in ${in_addr}#${idx}"
19
done < balance.out
20
txcnt=$(cat balance.out | wc -l)
21
echo Total ADA balance: ${total_balance}
22
echo Number of UTXOs: ${txcnt}
23
โ€‹
24
withdrawalString="$(cat stake.addr)+${rewardBalance}"
Copied!
Run the build-raw transaction command.
block producer node
1
cardano-cli transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+0 \
4
--invalid-hereafter $(( ${currentSlot} + 10000)) \
5
--fee 0 \
6
--withdrawal ${withdrawalString} \
7
--out-file tx.tmp
Copied!
Calculate the current minimum fee:
block producer node
1
fee=$(cardano-cli transaction calculate-min-fee \
2
--tx-body-file tx.tmp \
3
--tx-in-count ${txcnt} \
4
--tx-out-count 1 \
5
--mainnet \
6
--witness-count 2 \
7
--byron-witness-count 0 \
8
--protocol-params-file params.json | awk '{ print $1 }')
9
echo fee: $fee
Copied!
Calculate your change output.
block producer node
1
txOut=$((${total_balance}-${fee}+${rewardBalance}))
2
echo Change Output: ${txOut}
Copied!
Build your transaction.
block producer node
1
cardano-cli transaction build-raw \
2
${tx_in} \
3
--tx-out $(cat payment.addr)+${txOut} \
4
--invalid-hereafter $(( ${currentSlot} + 10000)) \
5
--fee ${fee} \
6
--withdrawal ${withdrawalString} \
7
--out-file tx.raw
Copied!
Copy tx.raw to your cold environment.
Sign the transaction with both the payment and stake secret keys.
air-gapped offline machine
1
cardano-cli transaction sign \
2
--tx-body-file tx.raw \
3
--signing-key-file payment.skey \
4
--signing-key-file stake.skey \
5
--mainnet \
6
--out-file tx.signed
Copied!
Copy tx.signed to your hot environment.
Send the signed transaction.
block producer node
1
cardano-cli transaction submit \
2
--tx-file tx.signed \
3
--mainnet
Copied!
Check if the funds arrived.
block producer node
1
cardano-cli query utxo \
2
--address ${destinationAddress} \
3
--mainnet
Copied!
You should see output similar to this showing your updated Lovelace balance with rewards.
1
TxHash TxIx Lovelace
2
----------------------------------------------------------------------------------------
3
100322a39d02c2ead....
Copied!

โ€‹
๐Ÿ•’
18.12 Slot Leader Schedule - Find out when your pool will mint blocks

โ€‹
๐Ÿ”ฅ
Hot tip: You can calculate your slot leader schedule, which tells you when it's your stake pools turn to mint a block. This can help you know what time is best to schedule maintenance on your stake pool. It can also help verify your pool is minting blocks correctly when it is your pool's turn. This is to be setup and run on the block producer node.
CNCLI Tool
[Deprecated] Python Method

โ€‹CNCLI by BCSH, SAND, SALADโ€‹

A community-based cardano-node CLI tool. It's a collection of utilities to enhance and extend beyond those available with the cardano-cli.

โ€‹
๐Ÿงฌ
Install the binary release

1
###
2
### On blockproducer
3
###
4
RELEASETAG=$(curl -s https://api.github.com/repos/AndrewWestberg/cncli/releases/latest | jq -r .tag_name)
5
VERSION=$(echo ${RELEASETAG} | cut -c 2-)
6
echo "Installing release ${RELEASETAG}"
7
curl -sLJ https://github.com/AndrewWestberg/cncli/releases/download/${RELEASETAG}/cncli-${VERSION}-x86_64-unknown-linux-gnu.tar.gz -o /tmp/cncli-${VERSION}-x86_64-unknown-linux-gnu.tar.gz
Copied!
1
sudo tar xzvf /tmp/cncli-${VERSION}-x86_64-unknown-linux-gnu.tar.gz -C /usr/local/bin/
Copied!

Checking that cncli is properly installed

Run the following command to check if cncli is correctly installed and available in your system PATH variable:
1
command -v cncli
Copied!
It should return /usr/local/bin/cncli

โ€‹
โ›
Running LeaderLog with stake-snapshot

This command calculates a stake pool's expected slot list.
  • prev and current logs are available as long as you have a synchronized database.
  • next logs are only available 1.5 days (36 hours) before the end of the epoch.
  • You need to use poolStakeMark and activeStakeMark for next, poolStakeSet and activeStakeSet for current, poolStakeGo and activeStakeGo for prev.
Example usage with the stake-snapshot approach for next epoch:
Run this command 1.5 days (36 hours) before the next epoch begins.
1
/usr/local/bin/cncli sync --host 127.0.0.1 --port 6000 --no-service
2
โ€‹
3
MYPOOLID=$(cat $NODE_HOME/stakepoolid.txt)
4
echo "LeaderLog - POOLID $MYPOOLID"
5
โ€‹
6
SNAPSHOT=$(/usr/local/bin/cardano-cli query stake-snapshot --stake-pool-id $MYPOOLID --mainnet)
7
POOL_STAKE=$(echo "$SNAPSHOT" | grep -oP '(?<= "poolStakeMark": )\d+(?=,?)')
8
ACTIVE_STAKE=$(echo "$SNAPSHOT" | grep -oP '(?<= "activeStakeMark": )\d+(?=,?)')
9
MYPOOL=`/usr/local/bin/cncli leaderlog --pool-id $MYPOOLID --pool-vrf-skey ${NODE_HOME}/vrf.skey --byron-genesis ${NODE_HOME}/mainnet-byron-genesis.json --shelley-genesis ${NODE_HOME}/mainnet-shelley-genesis.json --pool-stake $POOL_STAKE --active-stake $ACTIVE_STAKE --ledger-set next`
10
echo $MYPOOL | jq .
11
โ€‹
12
EPOCH=`echo $MYPOOL | jq .epoch`
13
echo "\`Epoch $EPOCH\` ๐Ÿง™๐Ÿ”ฎ:"
14
โ€‹
15
SLOTS=`echo $MYPOOL | jq .epochSlots`
16
IDEAL=`echo $MYPOOL | jq .epochSlotsIdeal`
17
PERFORMANCE=`echo $MYPOOL | jq .maxPerformance`
18
โ€‹
19
echo "\`MYPOOL - $SLOTS \`๐ŸŽฐ\`, $PERFORMANCE% \`๐Ÿ€max, \`$IDEAL\` ๐Ÿงฑideal"
Copied!
Example usage with the stake-snapshot approach for current epoch:
1
/usr/local/bin/cncli sync --host 127.0.0.1 --port 6000 --no-service
2
โ€‹
3
MYPOOLID=$(cat $NODE_HOME/stakepoolid.txt)
4
echo "LeaderLog - POOLID $MYPOOLID"
5
โ€‹
6
SNAPSHOT=$(/usr/local/bin/cardano-cli query stake-snapshot --stake-pool-id $MYPOOLID --mainnet)
7
POOL_STAKE=$(echo "$SNAPSHOT" | grep -oP '(?<= "poolStakeSet": )\d+(?=,?)')
8
ACTIVE_STAKE=$(echo "$SNAPSHOT" | grep -oP '(?<= "activeStakeSet": )\d+(?=,?)')
9
MYPOOL=`/usr/local/bin/cncli leaderlog --pool-id $MYPOOLID --pool-vrf-skey ${NODE_HOME}/vrf.skey --byron-genesis ${NODE_HOME}/mainnet-byron-genesis.json --shelley-genesis ${NODE_HOME}/mainnet-shelley-genesis.json --pool-stake $POOL_STAKE --active-stake $ACTIVE_STAKE --ledger-set current`
10
echo $MYPOOL | jq .
11
โ€‹
12
EPOCH=`echo $MYPOOL | jq .epoch`
13
echo "\`Epoch $EPOCH\` ๐Ÿง™๐Ÿ”ฎ:"
14
โ€‹
15
SLOTS=`echo $MYPOOL | jq .epochSlots`
16
IDEAL=`echo $MYPOOL | jq .epochSlotsIdeal`
17
PERFORMANCE=`echo $MYPOOL | jq .maxPerformance`
18
โ€‹
19
echo "\`MYPOOL - $SLOTS \`๐ŸŽฐ\`, $PERFORMANCE% \`๐Ÿ€max, \`$IDEAL\` ๐Ÿงฑideal"
Copied!
Example usage with the stake-snapshot approach for previous epoch:
1
/usr/local/bin/cncli sync --host 127.0.0.1 --port 6000 --no-service
2
โ€‹
3
MYPOOLID=$(cat $NODE_HOME/stakepoolid.txt)
4
echo "LeaderLog - POOLID $MYPOOLID"
5
โ€‹
6
SNAPSHOT=$(/usr/local/bin/cardano-cli query stake-snapshot --stake-pool-id $MYPOOLID --mainnet)
7
POOL_STAKE=$(echo "$SNAPSHOT" | grep -oP '(?<= "poolStakeGo": )\d+(?=,?)')
8
ACTIVE_STAKE=$(echo "$SNAPSHOT" | grep -oP '(?<= "activeStakeGo": )\d+(?=,?)')
9
MYPOOL=`/usr/local/bin/cncli leaderlog --pool-id $MYPOOLID --pool-vrf-skey ${NODE_HOME}/vrf.skey --byron-genesis ${NODE_HOME}/mainnet-byron-genesis.json --shelley-genesis ${NODE_HOME}/mainnet-shelley-genesis.json --pool-stake $POOL_STAKE --active-stake $ACTIVE_STAKE --ledger-set prev`
10
echo $MYPOOL | jq .
11
โ€‹
12
EPOCH=`echo $MYPOOL | jq .epoch`
13
echo "\`Epoch $EPOCH\` ๐Ÿง™๐Ÿ”ฎ:"
14
โ€‹
15
SLOTS=`echo $MYPOOL | jq .epochSlots`
16
IDEAL=`echo $MYPOOL | jq .epochSlotsIdeal`
17
PERFORMANCE=`echo $MYPOOL | jq .maxPerformance`
18
โ€‹
19
echo "\`MYPOOL - $SLOTS \`๐ŸŽฐ\`, $PERFORMANCE% \`๐Ÿ€max, \`$IDEAL\` ๐Ÿงฑideal"
Copied!

PoolTool Integration

CNCLI can send your tip and block slots to PoolTool. To do this, it requires that you set up a pooltool.json file containing your PoolTool API key and stake pool details. Your PoolTool API key can be found on your pooltool profile page.
Here's an example pooltool.json file.
Please update with your pool information and save it at $NODE_HOME/scripts/pooltool.json
1
cat > ${NODE_HOME}/scripts/pooltool.json << EOF
2
{
3
"api_key": "<UPDATE WITH YOUR API KEY FROM POOLTOOL PROFILE PAGE>",
4
"pools": [
5
{
6
"name": "<UPDATE TO MY POOL TICKER>",
7
"pool_id": "$(cat ${NODE_HOME}/stakepoolid.txt)",
8
"host" : "127.0.0.1",
9
"port": 6000
10
}
11
]
12
}
13
EOF
Copied!

Systemd Services

CNCLI sync and sendtip can be easily enabled as systemd services. When enabled as systemd services:
  • sync will continuously keep the cncli.db database synchronized.
  • sendtip will continuously send your stake pool tip to PoolTool.
To set up systemd:
  • Create the following and move to/etc/systemd/system/cncli-sync.service
1
cat > ${NODE_HOME}/cncli-sync.service << EOF
2
[Unit]
3
Description=CNCLI Sync
4
After=multi-user.target
5
โ€‹
6
[Service]
7
User=$USER
8
Type=simple
9
Restart=always
10
RestartSec=5
11
LimitNOFILE=131072
12
ExecStart=/usr/local/bin/cncli sync --host 127.0.0.1 --port 6000 --db ${NODE_HOME}/scripts/cncli.db
13
KillSignal=SIGINT
14
SuccessExitStatus=143
15
StandardOutput=syslog
16
StandardError=syslog
17
SyslogIdentifier=cncli-sync
18
โ€‹
19
[Install]
20
WantedBy=multi-user.target
21
EOF
Copied!
1
sudo mv ${NODE_HOME}/cncli-sync.service /etc/systemd/system/cncli-sync.service
Copied!
  • Create the following and move to /etc/systemd/system/cncli-sendtip.service
1
cat > ${NODE_HOME}/cncli-sendtip.service << EOF
2
[Unit]
3
Description=CNCLI Sendtip
4
After=multi-user.target
5
โ€‹
6
[Service]
7
User=$USER
8
Type=simple
9
Restart=always
10
RestartSec=5
11
LimitNOFILE=131072
12
ExecStart=/usr/local/bin/cncli sendtip --cardano-node /usr/local/bin/cardano-node --config ${NODE_HOME}/scripts/pooltool.json
13
KillSignal=SIGINT
14
SuccessExitStatus=143
15
StandardOutput=syslog
16
StandardError=syslog
17
SyslogIdentifier=cncli-sendtip
18
โ€‹
19
[Install]
20
WantedBy=multi-user.target
21
EOF
Copied!
1
sudo mv ${NODE_HOME}/cncli-sendtip.service /etc/systemd/system/cncli-sendtip.service
Copied!
  • To enable and run the above services, run:
1
sudo systemctl daemon-reload
Copied!
1
sudo systemctl start cncli-sync.service
Copied!
1
sudo systemctl start cncli-sendtip.service
Copied!

โ€‹
๐Ÿ› 
Updating cncli from earlier versions

1
RELEASETAG=$(curl -s https://api.github.com/repos/AndrewWestberg/cncli/releases/latest | jq -r .tag_name)
2
VERSION=$(echo ${RELEASETAG} | cut -c 2-)
3
echo "Installing release ${RELEASETAG}"
4
curl -sLJ https://github.com/AndrewWestberg/cncli/releases/download/${RELEASETAG}/cncli-${VERSION}-x86_64-unknown-linux-gnu.tar.gz -o /tmp/cncli-${VERSION}-x86_64-unknown-linux-gnu.tar.gz
Copied!
1
sudo tar xzvf /tmp/cncli-${VERSION}-x86_64-unknown-linux-gnu.tar.gz -C /usr/local/bin/
Copied!

Checking that cncli is properly updated

1
cncli -V
Copied!
It should return the updated version number.
Credits for inventing this process goes to the hard work by Andrew Westberg @amw7 (developer of JorManager and operator of BCSH family of stake pools).
Check if you have python installed.
1
python3 --version
Copied!
Otherwise, install python3.
1
sudo apt-get update
2
sudo apt-get install -y software-properties-common
3
sudo add-apt-repository ppa:deadsnakes/ppa
4
sudo apt-get update
5
sudo apt-get install -y python3.9
Copied!
Check if you have pip installed.
1
pip3 --version
Copied!
Install pip3 if needed.
1
sudo apt-get install -y python3-pip
Copied!
Install pytz which handles timezones.
1
pip3 install pytz
Copied!
Verify python and pip are setup correctly before continuing.
1
python3 --version
2
pip3 --version
Copied!
Clone the leaderLog scripts from papacarp/pooltool.io git repo.
Official documentation for this LeaderLogs tool can be read here.โ€‹
1
cd $HOME/git
2
git clone https://github.com/papacarp/pooltool.io
3
cd pooltool.io/leaderLogs
Copied!
Calculate your slot leader schedule for the latest current epoch.
1
python3 leaderLogs.py \
2
--pool-id $(cat ${NODE_HOME}/stakepoolid.txt) \
3
--tz America/Los_Angeles \
4
--vrf-skey ${NODE_HOME}/vrf.skey
Copied!
Set the timezone name to format the schedule's times properly. Use the --tz option. [Default: America/Los_Angeles]') Refer to the official documentation for more info.โ€‹
โ€‹
๐Ÿค–
Pro Tip: 1.5 days before the end of the current epoch, you can find the next epoch's schedule.
โ€‹
๐Ÿค–
Pro Tip #2: Add the flag --epoch <INTEGER #> to find a specific epoch's slot schedule.
โ€‹
๐Ÿค–
Pro Tip #3: Ensure your slot leader scripts are up to date.
1
cd $HOME/git/pooltool.io/leaderLogs
2
git pull
Copied!
If your pool is scheduled to mint blocks, you should hopefully see output similar to this. Listed by date and time, this is your slot leader schedule or in other words, when your pool is eligible to mint a block.
1
Checking leadership log for Epoch 222 [ d Param: 0.6 ]
2
2020-10-01 00:11:10 ==> Leader for slot 121212, Cumulative epoch blocks: 1
3
2020-10-01 00:12:22 ==> Leader for slot 131313, Cumulative epoch blocks: 2
4
2020-10-01 00:19:55 ==> Leader for slot 161212, Cumulative epoch blocks: 3
Copied!
Your slot leader log should remain confidential. If you share this information publicly, an attacker could use this information to attack your stake pool.

โ€‹
๐Ÿ”
18.13 Update your node's height on pooltool.io

Credits to QCPOL for this addition and credits to papacarp which this script is based on. Alternatively, use cncli's pooltool integration as described in section 18.12.
When browsing pools on pooltool.io, you'll notice that there's a column named height. It shows the node's current block and let your (future) delegators know that your node is running and up to date.
block producer node
If your block producer doesn't have Internet access, you can use a relay node.
Installing the script
1
cd $NODE_HOME
2
wget https://cardano.stakepool.quebec/scripts/qcpolsendmytip.sh
3
sed -i -e 's/\r$//' qcpolsendmytip.sh
4
md5sum qcpolsendmytip.sh
Copied!
To make sure the file is genuine, the md5 hash should be f7646132e922b24b140202e5f5cba3ac. If it's not, stop here and delete the file with rm qcpolsendmytip.sh.
You will need your pooltool.io API key (shown in your profile after registering).