Diese Anleitung basiert auf dem Tutorial von Coincashew. Ich habe sie für dieses Tutorial übersetzt und leicht verändert, im Wesentlichen enspricht es jedoch der Coincashew Anleitung von Ende Mai 2021.
Installation
System vorbereiten
Als 1. werden einige Grundlagen installiert:
sudo apt-get install automake build-essential pkg-config libffi-dev libgmp-dev libssl-dev libtinfo-dev libsystemd-dev zlib1g-dev make g++ tmux git jq wget libncursesw5 libtool autoconf liblmdb-dev -y
Libsodium installieren
Im 2. Schritt muss die Libsodium eingerichtet werden. Das ist eine kryptographie Bibliothek, welche einige Tools mitbringt:
mkdir $HOME/git cd $HOME/git git clone https://github.com/input-output-hk/libsodium cd libsodium git checkout dbb48cce5429cb6585c9034f002568964f1ce567 ./autogen.sh ./configure make sudo make install
Für Debian basierte Systeme, wie das hier genutzte Ubuntu ist es möglicherweise erforderlich noch ein wenig zu verlinken:
sudo ln -s /usr/local/lib/libsodium.so.23.3.0 /usr/lib/libsodium.so.23
secp256k1 installieren
Ab node Version 1.35.0 brauchen wir die secp256k1 lib. Sonst bricht der Build Vorgang mit einer Fehlermeldung bezüglich cardano-crypto-class ab.
Es kommt zu folgender Meldung:
cabal: Could not resolve dependencies: [__0] trying: cardano-crypto-class-2.0.0 (user goal) [__1] rejecting: cardano-crypto-class:+secp256k1-support (conflict: pkg-config package libsecp256k1-any, not found in the pkg-config database) [__1] rejecting: cardano-crypto-class:-secp256k1-support (manual flag can only be changed explicitly) [__1] fail (backjumping, conflict set: cardano-crypto-class, cardano-crypto-class:secp256k1-support) After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: cardano-crypto-class, cardano-crypto-class:secp256k1-support
Um die fehlende Abhängigkeit zu lösen, brauchen wir die secp256k1, aus dem Bitcoin-Core Repository.
Um diese kompilieren zu können, werden wir unser Ubuntu zunächst mit einigen Abhängigkeiten aufrüsten:
sudo apt-get install nano llvm-12 numactl libnuma-dev autoconf automake libtool
Jetzt gehen wir in user bekanntes git-Verzeichnis und führen folgende Kommandos aus:
git clone https://github.com/bitcoin-core/secp256k1.git cd secp256k1 git checkout v0.3.2 ./autogen.sh ./configure --prefix=/usr --enable-module-schnorrsig --enable-experimental make make check sudo make install sudo ldconfig sudo reboot
Jetzt noch ein Paar Ergänzungen in der .bashrc:
# Set environment variables so that the compiler finds libsodium on your computer export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH" export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH" # Set an environment variable indicating the file path to configuration files and scripts # related to operating your Cardano node export NODE_HOME="$HOME/cardano-my-node" # Set an environment variable indicating the Cardano network cluster where your node runs export NODE_CONFIG="mainnet"
BLST installieren
git clone https://github.com/supranational/blst cd blst git checkout v0.3.11 ./build.sh cat > libblst.pc << EOF prefix=/usr/local exec_prefix=\${prefix} libdir=\${exec_prefix}/lib includedir=\${prefix}/include Name: libblst Description: Multilingual BLS12-381 signature library URL: https://github.com/supranational/blst Version: 0.3.11 Cflags: -I\${includedir} Libs: -L\${libdir} -lblst EOF sudo cp libblst.pc /usr/local/lib/pkgconfig/ sudo cp bindings/blst_aux.h bindings/blst.h bindings/blst.hpp /usr/local/include/ sudo cp libblst.a /usr/local/lib sudo chmod u=rw,go=r /usr/local/{lib/{libblst.a,pkgconfig/libblst.pc},include/{blst.{h,hpp},blst_aux.h}}
Danach sollte die Cardano-Node auch in Version 1.35.0 und später kompilieren.
Cabal installieren
Als nächster Schritt werden wir Cabal installieren.
Wir beginnen mit den Abhängigkeiten, die sollten eigentlich schon installiert sein, aber sicher ist sicher:
sudo apt-get -y install pkg-config libgmp-dev libssl-dev libtinfo-dev libsystemd-dev zlib1g-dev build-essential curl libgmp-dev libffi-dev libncurses-dev libtinfo5
Im nächsten Schritt wird Cabal installiert.
Die Frage nach dem “haskell-language-server (HLS) beantworten wir mit NO.
Die Frage die PATH Variablen automatisch zum PATH in der .bashrc hinzuzufügen beantworten wir mit YES.
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
Die nachfolgenden Kommandos sollten bereits durch das Skript ausgeführt sein. Sicher ist sicher, wir führen sie ein weiteres mal aus, das schadet nicht:
cd $HOME source .bashrc ghcup upgrade ghcup install cabal 3.8.1.0 ghcup set cabal 3.8.1.0
Nun installieren wir den GHC:
ghcup install ghc 8.10.7 ghcup set ghc 8.10.7
Jetzt updaten wir den PATH noch etwas weiter, damit wir nicht immer die Pfade referenzieren müssen:
echo PATH="$HOME/.local/bin:$PATH" >> $HOME/.bashrc echo export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc echo export NODE_HOME=$HOME/cardano-my-node >> $HOME/.bashrc echo export NODE_CONFIG=mainnet>> $HOME/.bashrc echo export NODE_BUILD_NUM=$(curl https://hydra.iohk.io/job/Cardano/iohk-nix/cardano-deployment/latest-finished/download/1/index.html | grep -e "build" | sed 's/.*build\/\([0-9]*\)\/download.*/\1/g') >> $HOME/.bashrc source $HOME/.bashrc
Die Cardano Node bauen
Vorweg noch schnell alles auf den neuesten Stand bringen:
cabal update
Und schnell die Versionen abfragen:
cabal --version ghc --version
Cabal muss 3.8.1.0 sein.
GHC sollte 8.10.7 sein.
Andernfalls muss sichergestellt werden, ob dieses Tutorial noch aktuell ist.
Um diese Anleitung im Testnet zu verwenden:
Einfach in den CLI Parametern
–mainnet
mit
–testnet-magic 1097911063
ersetzen.
Wir bauen eine Node
Schritt 1, herunterladen der Quellen und zum letzten TAG wechseln:
cd $HOME/git git clone https://github.com/input-output-hk/cardano-node.git cd cardano-node git fetch --all --recurse-submodules --tags git checkout $(curl -s https://api.github.com/repos/IntersectMBO/cardano-node/releases/latest | jq -r .tag_name)
Schritt 2, konfigurieren der build Optionen. Also das, was bei C ./configure ist:
cabal configure -O0 -w ghc-8.10.7
Schritt 3, ein paar esoterische Konfigurationen:
echo -e "package cardano-crypto-praos\n flags: -external-libsodium-vrf" > cabal.project.local sed -i $HOME/.cabal/config -e "s/overwrite-policy:/overwrite-policy: always/g" rm -rf $HOME/git/cardano-node/dist-newstyle/build/x86_64-linux/ghc-8.10.7
Die 1. Zeile gibt an, dass die libsodium von extern kommt.
Die 2. Zeile das die Override policy auf always gesetzt wird. Der Zweck ist es, das ein evtl. vorhandener alter Build überschrieben wird.
Die 3. Zeile löscht ein vorhandenes ghc aus dem build Ordner.
Schritt 4, jetzt werden wir die eigentliche Node bauen:
cabal build cardano-cli cardano-node
Das Kompilat verschieben wir in ein globales bin Verzeichnis:
sudo cp -p "$(./scripts/bin-path.sh cardano-node)" /usr/local/bin/cardano-node sudo cp -p "$(./scripts/bin-path.sh cardano-cli)" /usr/local/bin/cardano-cli
Konfiguration der Nodes
Wir brauchen 5 json-Dateien zur Konfiguration der Node:
- config.json
- genesis.json (jeweils byron-genesis.json, shelley-genesis.json, alonzo-genesis.json und conway-genesis.json)
- topology.json
Achtung: Die hier heruntergeladenen config-Dateien sollten funktionieren, ob sie es wirklich tun, ist eine andere Frage. Weiter unten in diesem Tutorial gehe ich auf mögliche Probleme ein.
Zunächst legen wir das Konfigurationverzeichnis an.
mkdir $NODE_HOME cd $NODE_HOME
Die Konfigurationsdateien gibt es hier:
https://github.com/input-output-hk/cardano-node
Dort unter “Releases” und bei Releases unter “Downloads” dort unter “Configuration Files”.
Wir laden hier unter der Sektion “Mainnet”, die 5 oben genannten Dateien herunter.
Wir legen jetzt eine config.json an und updaten den Parameter TraceBlockFetchDecisions zu “true”:
sed -i ${NODE_CONFIG}-config.json \ -e "s/TraceBlockFetchDecisions\": false/TraceBlockFetchDecisions\": true/g"
Für die Relay Nodes interessant:
Der Speicherverbrauch einer Relay Node kann gesenkt werden, indem “TraceMemPool” auf “false” gesetzt wird.
Im nächsten Schritt updaten wir die .bashrc
echo export CARDANO_NODE_SOCKET_PATH="$NODE_HOME/db/socket" >> $HOME/.bashrc source $HOME/.bashrc
Bis hierhin sind alle Konfigurationen gleich. Diesen Teil wiederholen wir auf allen Maschinen.
Konfiguration der block-producer node
Die block producer node benötigt diverse Schlüsselpaare für die Block Erzeugung.
- cold keys
- KES hot keys
- VRF hot keys)
Die block producer node darf nur zu ihren relay nodes verbinden. Diese Node ist von der Außenwelt abgeschirmt. Die Firewall muss entsprechend konfiguriert werden.
Die anderen Nodes, die Relay Nodes, besitzen keinerlei Schlüssel. Infolgedesssen können sie auch keine Blöcke erzeugen.
Die eigentliche Konfiguration
Zunächst erzeugen wir die Topologie:
cat > $NODE_HOME/topology.json << EOF { "Producers": [ { "addr": "<RELAYNODE1'S PUBLIC IP ADDRESS>", "port": 6000, "valency": 1 }, { "addr": "<RELAYNODE2'S PUBLIC IP ADDRESS>", "port": 6000, "valency": 1 } ] } EOF
Bei mehreren Relays, fügen wir diese alle hinzu.
Konfiguration der relay node
cat > $NODE_HOME/topology.json << EOF { "Producers": [ { "addr": "<BLOCK PRODUCER NODE'S PUBLIC IP ADDRESS>", "port": 6000, "valency": 1 }, { "addr": "relays-new.cardano-mainnet.iohk.io", "port": 3001, "valency": 2 } ] } EOF
Konfiguration der offline Maschine
Wir verwenden ein vom Netz getrenntes Notebook als offline Maschine. Ziel dieser Maschine ist es die Schlüsselpaare des Block Producers zu erzeugen und uns vor diversen Bedrohungen zu schützen, indem diese Maschine physikalisch vom Netz getrennt ist.
Die offline Maschine hat folgende Eigenschaften:
- Nicht mit dem Internet verbunden.
- Physikalisch von jeder Internetverbindung abgekoppelt.
- Keine Virtuelle Maschine auf einen Host der mit dem Internet verbunden ist.
- Schutz vor Malware Bedrohungen
- Schutz vor Sicherheitslücken
Bevor wir fortfahren nehmen wir die Grundeinrichtung vor. Das bedeutet, wir installieren die Abhängigkeiten.
Zunächst legen wir uns das “cardano-my-node” Verzeichnis an, fügen es zur .bashrc hinzu und fügen es direkt zum PATH hinzu.
echo export NODE_HOME=$HOME/cardano-my-node >> $HOME/.bashrc source $HOME/.bashrc mkdir -p $NODE_HOME
Jetzt die gebauten binaries der cardano-cli vom “hot environment”, dass ist der “block producer” kopieren.
Um die Regeln des “cold environment” korrekt einzuhalten verwenden wir dazu einen usb stick und kopieren die binaries über eine Drittmaschine, sofern wir keinen physischen Zugang zum Server haben.
Startskripte
Um uns das Leben zu erleichtern halten wir die Prozedur des Startens einer Node in Skripten fest.
Wir beginnen mit den Relay 1 (alternativ anpassen, für so viele Relays, wie wir haben):
cat > $NODE_HOME/startRelayNode1.sh << EOF #!/bin/bash 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.json /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} EOF
Jetzt machen wir die angelegte Datei ausführbar:
chmod +x $NODE_HOME/startRelayNode1.sh
Im nächsten Schritt erstellen wir ein Skript für den Block Producer:
cat > $NODE_HOME/startBlockProducingNode.sh << EOF #!/bin/bash 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.json /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} EOF
Auf den dieses Skript machen wir ausführbar:
chmod +x $NODE_HOME/startBlockProducingNode.sh
Systemd services für die Nodes erstellen
Systemd bietet uns diverse Vorteile in der Verwaltung der Nodes
- Autostart der Nodes, wenn das System hochfährt oder durch Probleme zum Reboot gezwungen ist.
- Automatischer Neustart, wenn die Node abstürzt.
- Maximierte Performance der Nodes.
Im 1. Schritt beginnen wir wieder mit der Releay Node 1:
cat > $NODE_HOME/cardano-node.service << EOF # The Cardano node service (part of systemd) # file: /etc/systemd/system/cardano-node.service [Unit] Description = Cardano node service Wants = network-online.target After = network-online.target [Service] User = ${USER} Type = simple WorkingDirectory= ${NODE_HOME} ExecStart = /bin/bash -c '${NODE_HOME}/startRelayNode1.sh' KillSignal=SIGINT RestartKillSignal=SIGINT TimeoutStopSec=300 LimitNOFILE=32768 Restart=always RestartSec=5 SyslogIdentifier=cardano-node [Install] WantedBy = multi-user.target EOF
Wie zuvor auch, kann das obige für beliebig viele Relay Nodes angepasst werden.
Im 2. Schritt erstellen wir einen Service für die Block Producer Node:
cat > $NODE_HOME/cardano-node.service << EOF # The Cardano node service (part of systemd) # file: /etc/systemd/system/cardano-node.service [Unit] Description = Cardano node service Wants = network-online.target After = network-online.target [Service] User = ${USER} Type = simple WorkingDirectory= ${NODE_HOME} ExecStart = /bin/bash -c '${NODE_HOME}/startBlockProducingNode.sh' KillSignal=SIGINT RestartKillSignal=SIGINT TimeoutStopSec=300 LimitNOFILE=32768 Restart=always RestartSec=5 SyslogIdentifier=cardano-node [Install] WantedBy = multi-user.target EOF
Auf allen Systemen verschieben wir den unit file nun nach /etc/systemd/system und setzen die Zugriffsrechte:
sudo mv $NODE_HOME/cardano-node.service /etc/systemd/system/cardano-node.service sudo chmod 644 /etc/systemd/system/cardano-node.service
Jetzt schalten wir den Autostart der Node Services ein:
sudo systemctl daemon-reload sudo systemctl enable cardano-node
Nach dieser Maßnahme sind die Cardano Nodes von systemd verwaltet und profitieren von der automatischen Verwaltung durch diesen Dienst.
Systemd Kommandos
Den Status der Node einsehen:
sudo systemctl status cardano-node
Neustarten der Node:
sudo systemctl reload-or-restart cardano-node
Die Node stoppen:
sudo systemctl stop cardano-node
Anzeigen und filtern der Log-Files:
journalctl --unit=cardano-node --follow journalctl --unit=cardano-node --since=yesterday journalctl --unit=cardano-node --since=today journalctl --unit=cardano-node --since='2020-07-29 00:00:00' --until='2020-07-29 12:00:00'
Starten der Nodes
Der Zeitpunkt die Nodes zu starten ist jetzt gekommen.
Folgendes Kommando wird auf beiden Maschinen ausgeführt:
sudo systemctl start cardano-node
Jetzt kann gLiveView eingerichtet werden. Die Einrichtung ist im Kapitel überwachen der Nodes erklärt.
Info:
Cardano ist noch in Entwicklung, es kann sein, dass die Synchronisierung der Blockchain abbricht. Dann müssen die Konfigurationsdateien eventuell gegen neuere Versionen ausgetauscht werden. Das sind:
- config.json
- byron-genesis.json
- shelley-genesis.json
- alonzo-genesis.json
- conway-genesis.json
Meistens gibt es zu diesen Synchronisationsabbrüchen auch Forenbeiträge, von Menschen, die das Problem ebenfalls haben. Hier wäre beispielsweise so ein Fall.
Hier gibt es im Zweifel die letzten zutreffenden config-json-Dateien. Oder eben im Github Repo in der Downloads Sektion des entsprechenden Release.
Die Block Producer Keys
Die Block Producer Node benötigt 3 Keys:
-
stake pool cold key (node.cert)
-
stake pool hot key (kes.skey)
-
stake pool VRF key (vrf.skey)
Auf dem Block Producer
Im 1. Schritt erzeugen wir die KES Keys auf der Block Producer Node:
cd $NODE_HOME cardano-cli node key-gen-KES \ --verification-key-file kes.vkey \ --signing-key-file kes.skey
Die KES Keys müssen alle 90 Tage erneuert werden, wenn der Pool im Mainnet betrieben wird.
Auf der Offline Maschine
Die Cold-Keys müssen auf der Offline Maschine erzeugt und gespeichert werden.
Wir speichern diese Keys in einen Verzeichnis mit Namen Cold Keys:
mkdir $HOME/cold-keys pushd $HOME/cold-keys
Jetzt werden die cold-keys erzeugt und ein counter file für die cold-keys:
cardano-cli node key-gen \ --cold-verification-key-file node.vkey \ --cold-signing-key-file node.skey \ --operational-certificate-issue-counter node.counter
Es ist extrem wichtig alle Keys auf einen weiteren Gerät zu sichern!
Auf dem Block Producer
Ab hier muss unsere Node voll synchronisiert sein. Herausfinden können wir das, indem wir auf https://pooltool.io/ (oder mein Favourit: https://cardanoscan.io/) die Epoche und slot Nummer mit der in gLiveView vergleichen.
Zunächst müssen wir die Anzahl der slots per KES Periode bestimmen:
pushd +1 slotsPerKESPeriod=$(cat $NODE_HOME/${NODE_CONFIG}-shelley-genesis.json | jq -r '.slotsPerKESPeriod') echo slotsPerKESPeriod: ${slotsPerKESPeriod}
Das die Node voll synchronisiert st, finden wir heraus, wenn die Blocknummer und Slot Nummer in https://pooltool.io/ mit der von der Node übereinstimmt. Sonst werden wir nicht die korrekte KES-Periode herausfinden.
Zunächst die aktuelle Slot-Nr.:
slotNo=$(cardano-cli query tip --mainnet | jq -r '.slot') echo slotNo: ${slotNo}
Den Start der aktuellen KES-Periode finden wir heraus, wenn wir die slotNr. durch die slotsPerKesPeriode teilen:
kesPeriod=$((${slotNo} / ${slotsPerKESPeriod})) echo kesPeriod: ${kesPeriod} startKesPeriod=${kesPeriod} echo startKesPeriod: ${startKesPeriod}
Mit dieser Information können wir jetzt das operational Zertifikat für den Pool erzeugen.
Auf der Offline-Maschine
Dazu kopieren wird den key.vkey zum Cold-Environment.
Stake pool operators müssen ein “operational certificate” vorweisen, um nachweisen zu können, dass der Pool das Recht hat zu laufen.
Das Zertifikat beinhaltet:
- Die operators signature
- key information about the pool (addresses, keys, etc.)
Das “operational certificate” ist die Verbindung zwischen dem offline key des operators und seinem operational key.
Dieses Zertifikat erzeugen wir folgenden Kommando (<starKesPeriod> ersetzen wir durch den zuvor auf dem Block-Producer berechneten Wert):
cardano-cli 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
Auf dem Block-Producer
Wir kopieren das node.cert auf den Block-Producer.
Alles, was wir hier machen, geschieht in $NODE_HOME.
Wir erzeugen jetzt das VRF-Key-Paar:
cardano-cli node key-gen-VRF \ --verification-key-file vrf.vkey \ --signing-key-file vrf.skey
Die richtigen Berechtigungen setzen:
chmod 400 vrf.skey
Jetzt stoppen wir den Stake-Pool:
sudo systemctl stop cardano-node
Wir updaten jetzt das Startup-Skript mit den neu erzeugten Keys:
cat > $NODE_HOME/startBlockProducingNode.sh << EOF DIRECTORY=$NODE_HOME PORT=6000 HOSTADDR=0.0.0.0 TOPOLOGY=\${DIRECTORY}/${NODE_CONFIG}-topology.json DB_PATH=\${DIRECTORY}/db SOCKET_PATH=\${DIRECTORY}/db/socket CONFIG=\${DIRECTORY}/${NODE_CONFIG}-config.json KES=\${DIRECTORY}/kes.skey VRF=\${DIRECTORY}/vrf.skey CERT=\${DIRECTORY}/node.cert cardano-node run --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
Immer dran denken, wir müssen die Keys alle 90 Tage erneuern!
Wir starten den Block-Producer jetzt neu:
sudo systemctl start cardano-node
Und Prüfen das Ergebnis in gLiveView: ./gLiveView.sh
Einrichten der Payment und Stake Keys
Payment Keys werden verwendet, um payments zu senden und empfangen und stake keys um stake delegations zu verwalten.
Zuerst beschaffen wir uns die Blockchain Parameter:
cardano-cli query protocol-parameters \ --mainnet \ --out-file params.json
Es ist extrem wichtig, die payment und stake keys nur und ausschließlich auf der offline Maschine zu bewahren.
Sie werden verwendet um:
- Transaktionen in einen Cold-Environment zu erzeugen.
Die einzigen Schritte, die im Hot-Environment durchgeführt werden sind:
- Den momentanen Slot-Tip herausfinden.
- Die balance einer Adresse herausfinden.
- Eine Transaktion abschicken.
Das heißt, ausschließlich live data.
Es gibt jetzt 2 Methoden, um um die Schlüsselpaare für payments und stakes zu erzeugen. Eine CLI Methode und eine Mnemonic Methode.
Option 1: CLI-Methode – Auf der offline-Maschine
Das folgende geschieht komplett auf der offline-Maschine und im Verzeichnis $NODE_HOME.
Als 1. erzeugen wir die Schlüsselpaare payment.skey & payment.vkey:
### ### On air-gapped offline machine, ### cd $NODE_HOME cardano-cli address key-gen \ --verification-key-file payment.vkey \ --signing-key-file payment.skey
Als 2. erzeugen wir das stake Adressen Schlüsselpaar stake.skey & stake.vkey:
### ### On air-gapped offline machine, ### cardano-cli stake-address key-gen \ --verification-key-file stake.vkey \ --signing-key-file stake.skey
Jetzt erzeugen wir die stake.addr aus dem stake address verification key stake.vkey:
### ### On air-gapped offline machine, ### cardano-cli stake-address build \ --stake-verification-key-file stake.vkey \ --out-file stake.addr \ --mainnet
Zuletzt erzeugen wir die payment.addr für den payment.vkey
### ### On air-gapped offline machine, ### cardano-cli address build \ --payment-verification-key-file payment.vkey \ --stake-verification-key-file stake.vkey \ --out-file payment.addr \ --mainnet
Von dieser Adresse werden die Funds zur stake-Adresse delegiert.
Option 2: Mnemonic Methode – Auf der offline-Maschine
<TODO>
Funding der Payment Adresse
1. wir kopieren die payment.addr zum Hot-Environment. Das heißt, nach $NODE_HOME.
Wir können jetzt Adas zur Payment Adresse senden, die Payment-Adresse bekommen wir mit folgenden Kommando heraus:
cat payment.addr
Nachdem wir Geld zur Adresse gesendet haben, müsen wir warten, bis alle unsere Nodes voll synchronisiert sind, dann können wir unsere Adas mit folgenden Kommando abfragen:
cardano-cli query utxo \ --address $(cat payment.addr) \ --mainnet
In der Ausgabe sehen wir die Lovelace, welche wir zu der Adresse gesand haben:
TxHash TxIx Lovelace ---------------------------------------------------------------------------------------- 100322a39d02c2ead.... 0 1000000000
Registrierung der Stake Adresse
1. Wir erstellen auf der Offline-Maschine ein stake.cert, mittels des stake.vkey:
# offline Maschine cardano-cli stake-address registration-certificate \ --stake-verification-key-file stake.vkey \ --out-file stake.cert
Das stake.cert wird jetzt zur block producer node übertragen.
2. Es folgen jetzt die Schritte um die Registrierung der Stake Adresse durchzuführen, dies geschieht mittels einer Transaktion:
currentSlot=$(cardano-cli query tip --mainnet | jq -r '.slot') echo Current Slot: $currentSlot
3 .Wir stellen fest, wie viele Transaktionen es bisher auf der payment-Adresse gab und wie die Total Balance gerade ist:
cardano-cli query utxo \ --address $(cat payment.addr) \ --mainnet > fullUtxo.out tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out cat balance.out tx_in="" total_balance=0 while read -r utxo; do in_addr=$(awk '{ print $1 }' <<< "${utxo}") idx=$(awk '{ print $2 }' <<< "${utxo}") utxo_balance=$(awk '{ print $3 }' <<< "${utxo}") total_balance=$((${total_balance}+${utxo_balance})) echo TxHash: ${in_addr}#${idx} echo ADA: ${utxo_balance} tx_in="${tx_in} --tx-in ${in_addr}#${idx}" done < balance.out txcnt=$(cat balance.out | wc -l) echo Total ADA balance: ${total_balance} echo Number of UTXOs: ${txcnt}
4. Wir holen uns aus der param.json die Kosten zur Registrierung einer stake adresse:
stakeAddressDeposit=$(cat $NODE_HOME/params.json | jq -r '.stakeAddressDeposit') echo stakeAddressDeposit : $stakeAddressDeposit
Zum Zeitpunkt, wo diese Anleitung verfasst wurde betrugen die Kosten zur registrierung des stake adressen Zeritifikats 2000000 = 2 Ada.
5. Wir erzeugen jetzt eine raw transaction, diese ist unvollständig, enthält aber genügend informationen, um weiterarbeiten zu können:
cardano-cli transaction build-raw \ ${tx_in} \ --tx-out $(cat payment.addr)+0 \ --invalid-hereafter $(( ${currentSlot} + 10000)) \ --fee 0 \ --out-file tx.tmp \ --certificate stake.cert
invalid-herafter gibt an, wann die Transaktion ungültig wird, sofern sie nicht abgeschickt wird. Diese Zahl muss höher als die aktuelle Slot Nummer sein, daher in diesem Beispiel +1000.
6. Auf dieser Grundlage berechnen wir die aktuelle minimum fee:
fee=$(cardano-cli transaction calculate-min-fee \ --tx-body-file tx.tmp \ --tx-in-count ${txcnt} \ --tx-out-count 1 \ --mainnet \ --witness-count 2 \ --byron-witness-count 0 \ --protocol-params-file params.json | awk '{ print $1 }') echo fee: $fee
Die fee sollte sich in einem Bereich > 150000 und < 200000 bewegen.
7. Nun haben wir alle Daten beisammen und als Variablen gespeichert, um zu berechnen wie viel wir nach der Transaktion auf dem Konto übrig haben. Das ist txOut:
txOut=$((${total_balance}-${stakeAddressDeposit}-${fee})) echo Change Output: ${txOut}
8. Jetzt können wir endlich die Transaktion erstellen, um das stake.cert für den Deposit wert von 2 Ada zu registrieren. Dazu erstellen wir folgende Transaktion:
cardano-cli transaction build-raw \ ${tx_in} \ --tx-out $(cat payment.addr)+${txOut} \ --invalid-hereafter $(( ${currentSlot} + 10000)) \ --fee ${fee} \ --certificate-file stake.cert \ --out-file tx.raw
Wir kopieren die neue Datei tx.raw zur Offline-Maschine!
9. Auf der Offline-Maschine signieren wir jetzt die Transaktion:
# Offline-Maschine cardano-cli transaction sign \ --tx-body-file tx.raw \ --signing-key-file payment.skey \ --signing-key-file stake.skey \ --mainnet \ --out-file tx.signed
Wir kopieren die neue Datei tx.signed zur Block Producer Node!
10. Wir senden die signierte Transaktion:
# block producer node cardano-cli transaction submit \ --tx-file tx.signed \ --mainnet
Registrierung des Stake Pools
Die Registrierung eines Pools kostet 500 ADA deposit. Diese “Kaution” bekommen wir zwar zurück, wenn wir den Pool deregistrieren, aber man sollte sich darüber dennoch im Voraus im klaren sein. Bis hierhin sollte auch wirklich alles wie gewünscht laufen und man sollte alles verstanden haben.
1. Wir beginnen damit die poolMetaData.json Datei zu erstellen:
# block producer node cat > poolMetaData.json << EOF { "name": "MyPoolName", "description": "My pool description", "ticker": "MPN", "homepage": "https://myadapoolnamerocks.com" } EOF
Der Ticker mus zwischen 3-5 Zeichen lang sein!
Die Description darf nicht länger als 255 Zeichen sein!
Der Pool Name muss nicht pool enthalten und kann auch getrennt geschrieben sein. Zum Beispiel Financial Refuge.
2. Für die poolMetaData.json erzeugen wir jetzt einen Hash-Wert:
cardano-cli stake-pool metadata-hash --pool-metadata-file poolMetaData.json > poolMetaDataHash.txt
3. Hochladen der poolMetaData.json:
Die poolMetaData.json mus nun zu einen Ort hochgeladen werden, wo sie über eine normale URL erreichbar ist. In der Regel wird dies die Pool Website sein. Beispiel: https://financialrefuge.com/poolMetaData.json.
4. Die minimalen Betriebskosten eines Pools herausfinden:
# block producer node minPoolCost=$(cat $NODE_HOME/params.json | jq -r .minPoolCost) echo minPoolCost: ${minPoolCost}
Zum Zeitpunkt, wo diese Anleitung geschrieben wurde waren das 340 Ada, also 340000000 Lovelace.
Auf diesem Wert müssen die Poolkosten minimal sein.
Jetzt muss ein Registrierungszertifikat erstellt werden.
Zur angabe der Relays gibt es 3 Wege:
- DNS basiert
--single-host-pool-relay relaynode1.myadapoolnamerocks.com\ --pool-relay-port 6000 \ --single-host-pool-relay relaynode2.myadapoolnamerocks.com\ --pool-relay-port 6000 \
- IP basiert
--pool-relay-port 6000 \ --pool-relay-ipv4 <your first relay node public IP address> \ --pool-relay-port 6000 \ --pool-relay-ipv4 <your second relay node public IP address> \
- DNS round robin basiert
--multi-host-pool-relay relayNodes.myadapoolnamerocks.com\ --pool-relay-port 6000 \
Das Zertifikat werden wir auf der offline Maschine erstellen!
5. Erstellen des Zertifikats:
# offline Maschine cardano-cli stake-pool registration-certificate \ --cold-verification-key-file $HOME/cold-keys/node.vkey \ --vrf-verification-key-file vrf.vkey \ --pool-pledge 100000000 \ --pool-cost 345000000 \ --pool-margin 0.15 \ --pool-reward-account-verification-key-file stake.vkey \ --pool-owner-stake-verification-key-file stake.vkey \ --mainnet \ --single-host-pool-relay <dns based relay, example ~ relaynode1.myadapoolnamerocks.com> \ --pool-relay-port 6000 \ --metadata-url <url where you uploaded poolMetaData.json> \ --metadata-hash $(cat poolMetaDataHash.txt) \ --out-file pool.cert
Die Metadaten URL muss angepasst werden und die Relay Node Informationen. Außerdem natürlich die Daten des Pools, d.h. Kosten, Margin usw.
Dieses Pool Zeritifikat “pool.cert”, enthält die Basiskonfiguration des Pools. Vor dem Registrieren macht es vielleicht Sinn die Einstellungen entsprechend zu setzen und es sich gut zu überlegen. Die Registrierung kostet 500 Ada Kaution.
Gut ist, nachträgliche Änderungen kostet den Betrag nicht erneut. Registriert ist registriert.
Was wir jetzt noch brauchen ist ein Zertifikat zur Delegation:
6. Das “deleg.cert” erstellen:
# offline Maschine cardano-cli stake-address delegation-certificate \ --stake-verification-key-file stake.vkey \ --cold-verification-key-file $HOME/cold-keys/node.vkey \ --out-file deleg.cert
Das deleg.cert ist aus dem stake.vkey heraus endstanden für die node, die auf den node.vkey erzeugt wurde. Damit wird alles, was auf den Stake Adressen, die mit dem stake.vkey verbunden sind zum Pool delegiert, der mit node.vkey erzeugt wurde.
Die Zertifikate “pool.cert” und “deleg.cert” nun zum Block Producer kopieren!
Wir müssen diese beiden Zertifikate registrieren. Genau wie beim Stake-Key müssen wir dafür einige Adas hinterlegen. Zum Zeitpunkt dieses Tutorials kostete die Registrierung 500 Adas.
Die Registrierung geschieht mittels einer Transaktion, die wir nun auf dem block producer beginnen zu bauen.
1. Wir müssen herausfinden, welchen Slot und Tip wir gerade haben, um den Zeitraum festlegen zu können, wo die Transaktion gültig ist:
# block producer node currentSlot=$(cardano-cli query tip --mainnet | jq -r '.slot') echo Current Slot: $currentSlot
2. Wir benötigen die Account Balance der payment.addr und die Transaktionsnummer:
# block producer node cardano-cli query utxo \ --address $(cat payment.addr) \ --mainnet > fullUtxo.out tail -n +3 fullUtxo.out | sort -k3 -nr > balance.out cat balance.out tx_in="" total_balance=0 while read -r utxo; do in_addr=$(awk '{ print $1 }' <<< "${utxo}") idx=$(awk '{ print $2 }' <<< "${utxo}") utxo_balance=$(awk '{ print $3 }' <<< "${utxo}") total_balance=$((${total_balance}+${utxo_balance})) echo TxHash: ${in_addr}#${idx} echo ADA: ${utxo_balance} tx_in="${tx_in} --tx-in ${in_addr}#${idx}" done < balance.out txcnt=$(cat balance.out | wc -l) echo Total ADA balance: ${total_balance} echo Number of UTXOs: ${txcnt}
3. Jetzt holen wir uns die genaue Höhe der “Kaution” (Deposit), die wir brauchen, um das Zertifikat registrieren zu können:
# block producer node stakePoolDeposit=$(cat $NODE_HOME/params.json | jq -r '.stakePoolDeposit') echo stakePoolDeposit: $stakePoolDeposit
4. Nun wird eine einfache raw transaction erzeugt, welche uns zum berechnen der fee dienen wird:
# block producer node cardano-cli transaction build-raw \ ${tx_in} \ --tx-out $(cat payment.addr)+$(( ${total_balance} - ${stakePoolDeposit})) \ --invalid-hereafter $(( ${currentSlot} + 10000)) \ --fee 0 \ --certificate-file pool.cert \ --certificate-file deleg.cert \ --out-file tx.tmp
5. Damit können wir nun die Transaction fee berechnen:
# block producer node fee=$(cardano-cli transaction calculate-min-fee \ --tx-body-file tx.tmp \ --tx-in-count ${txcnt} \ --tx-out-count 1 \ --mainnet \ --witness-count 3 \ --byron-witness-count 0 \ --protocol-params-file params.json | awk '{ print $1 }') echo fee: $fee
6. Damit haben wir alles zusammen, um die Balance unseres Accounts nach der Transaction zu bestimmen:
# block producer node txOut=$((${total_balance}-${stakePoolDeposit}-${fee})) echo txOut: ${txOut}
7. Jetzt bauen wir die Transaction, welche wir später signieren und abschicken:
cardano-cli transaction build-raw \ ${tx_in} \ --tx-out $(cat payment.addr)+${txOut} \ --invalid-hereafter $(( ${currentSlot} + 10000)) \ --fee ${fee} \ --certificate-file pool.cert \ --certificate-file deleg.cert \ --out-file tx.raw
tx.raw werden wir jetzt zur Offline-Maschine kopieren!
8. Signieren der Transaktion:
# Offline Maschine cardano-cli transaction sign \ --tx-body-file tx.raw \ --signing-key-file payment.skey \ --signing-key-file $HOME/cold-keys/node.skey \ --signing-key-file stake.skey \ --mainnet \ --out-file tx.signed
tx.signed werden wir jetzt zum Block-Producer kopieren!
9. Abschicken der Transaktion:
cardano-cli transaction submit \ --tx-file tx.signed \ --mainnet
Damit sollte der Stake Pool Registriert sein und laufen. Er ist bereit Blöcke zu produzieren.
Stake Pool ID herausfinden und Prüfen ob alles läuft
1. Auf der Offline-Maschine holen wir uns die Stake Pool ID:
# Offline-Maschine cardano-cli stake-pool id --cold-verification-key-file $HOME/cold-keys/node.vkey --output-format hex > stakepoolid.txt cat stakepoolid.txt
stakepoolid.txt kopieren wir zum Block-Producer!
2. Auf dem Block-Producer holen wir uns einige Stake Pool Daten:
cardano-cli query stake-snapshot --stake-pool-id $(cat stakepoolid.txt) --mainnet
Ein nicht leerer String bedeutet, dass alles geklappt hat. Gratulation Sie sind nun Besitzer eines eigenen Stake Pools!
Relay Node Topology Updaten
Das Cardano Netzwerk kann derzeit noch keine p2p Suche nach vertrauenswürdigen Nodes durchführen. Daher muss das Hinzufügen vertrauenswürdiger Relay Pools von Hand unternommen werden.
Wir erstellen hierzu ein Skript, welches ein Topology update bei einem (hoffentlich) vertrauenswürdigen Fremdserver abfragt.
1. Skript erstellen:
### ### On relaynode1 ### cat > $NODE_HOME/topologyUpdater.sh << EOF #!/bin/bash # shellcheck disable=SC2086,SC2034 USERNAME=$(whoami) CNODE_PORT=6000 # must match your relay node port as set in the startup command CNODE_HOSTNAME="CHANGE ME" # optional. must resolve to the IP you are requesting from CNODE_BIN="/usr/local/bin" CNODE_HOME=$NODE_HOME CNODE_LOG_DIR="\${CNODE_HOME}/logs" GENESIS_JSON="\${CNODE_HOME}/${NODE_CONFIG}-shelley-genesis.json" NETWORKID=\$(jq -r .networkId \$GENESIS_JSON) CNODE_VALENCY=1 # optional for multi-IP hostnames NWMAGIC=\$(jq -r .networkMagic < \$GENESIS_JSON) [[ "\${NETWORKID}" = "Mainnet" ]] && HASH_IDENTIFIER="--mainnet" || HASH_IDENTIFIER="--testnet-magic \${NWMAGIC}" [[ "\${NWMAGIC}" = "1097911063" ]] && NETWORK_IDENTIFIER="--mainnet" || NETWORK_IDENTIFIER="--testnet-magic \${NWMAGIC}" export PATH="\${CNODE_BIN}:\${PATH}" export CARDANO_NODE_SOCKET_PATH="\${CNODE_HOME}/db/socket" blockNo=\$(/usr/local/bin/cardano-cli query tip \${NETWORK_IDENTIFIER} | jq -r .block ) # Note: # if you run your node in IPv4/IPv6 dual stack network configuration and want announced the # IPv4 address only please add the -4 parameter to the curl command below (curl -4 -s ...) if [ "\${CNODE_HOSTNAME}" != "CHANGE ME" ]; then T_HOSTNAME="&hostname=\${CNODE_HOSTNAME}" else T_HOSTNAME='' fi if [ ! -d \${CNODE_LOG_DIR} ]; then mkdir -p \${CNODE_LOG_DIR}; fi curl -s "https://api.clio.one/htopology/v1/?port=\${CNODE_PORT}&blockNo=\${blockNo}&valency=\${CNODE_VALENCY}&magic=\${NWMAGIC}\${T_HOSTNAME}" | tee -a \$CNODE_LOG_DIR/topologyUpdater_lastresult.json EOF
Hier muss noch der DNS Name angepasst werden.
2. Jetzt das Skript ausführbar machen und ausführen:
### ### On relaynode1 ### cd $NODE_HOME chmod +x topologyUpdater.sh ./topologyUpdater.sh
in $NODE_HOME wird ein Verzeichnis logs erstellt, wo das Resultat der letzten Ausführung abgelegt wird. Im Erfolgsfall sieht es so aus:
{ "resultcode": "201", "datetime":"2020-07-28 01:23:45", "clientIp": "1.2.3.4", "iptype": 4, "msg": "nice to meet you" }
3 Jetzt erstellen wir dafür einen Crontab eintrag, welcher dieses Skript jedes mal zur 33 Minute jeder Stunde ausführt:
### ### On relaynode1 ### cat > $NODE_HOME/crontab-fragment.txt << EOF 33 * * * * ${NODE_HOME}/topologyUpdater.sh EOF crontab -l | cat - ${NODE_HOME}/crontab-fragment.txt > ${NODE_HOME}/crontab.txt && crontab ${NODE_HOME}/crontab.txt rm ${NODE_HOME}/crontab-fragment.txt
Nach 4 Stunden wird die Adresse des Relays registriert sein, dann kann mit den nächsten Kapitel fortgefahren werden!
Das Update der Topologie
Wir erzeugen jetzt ein relay-topology_pull.sh Skript.
1. Das Skript erzeugen:
### ### On relaynode1 ### cat > $NODE_HOME/relay-topology_pull.sh << EOF #!/bin/bash BLOCKPRODUCING_IP=<BLOCK PRODUCERS PUBLIC IP ADDRESS> BLOCKPRODUCING_PORT=6000 curl -s -o $NODE_HOME/${NODE_CONFIG}-topology.json "https://api.clio.one/htopology/v1/fetch/?max=20&customPeers=\${BLOCKPRODUCING_IP}:\${BLOCKPRODUCING_PORT}:1|relays-new.cardano-mainnet.iohk.io:3001:2" EOF
Hier natürlich unbedingt die eigene Block Producer public IP einfügen!
2. Berechtigungen setzen und das Skript ausführen:
### ### On relaynode1 ### chmod +x relay-topology_pull.sh ./relay-topology_pull.sh
3. Um die neue Topologie aktiv werden zu lassen, muss die Node neu gestartet werden:
### ### On relaynode1 ### sudo systemctl restart cardano-node
Jetzt sollte der Stake Pool wirklich dazu in der Lage sein Blöcke zu erzeugen!
Überwachen der Nodes
Es gibt einige gute und auch notwendige Werkzeuge, um eine Cardano Node überwachen zu können. Wir beginnen mit gLiveView, dem einfachsten und grundlegendsten dieser Werkzeuge.
gLiveView
Wir uns gLiveView und die environment files:
cd $NODE_HOME sudo apt install bc tcptraceroute -y curl -s -o gLiveView.sh https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/gLiveView.sh curl -s -o env https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/env chmod 755 gLiveView.sh
Noch ein paar Settings mit dem stream editor setzen:
sed -i env \ -e "s/\#CONFIG=\"\${CNODE_HOME}\/files\/config.json\"/CONFIG=\"\${NODE_HOME}\/config.json\"/g" \ -e "s/\#SOCKET=\"\${CNODE_HOME}\/sockets\/node0.socket\"/SOCKET=\"\${NODE_HOME}\/db\/socket\"/g"
Das Tool arbeitet jetzt.