Stake Pool

Construir un Stake Pool con CNTools

Construir un Stake Pool con CNTools

GUILD Operators es uno de los muchos grupos de trabajo que rodean al proyecto Cardano. Se han hecho muy populares por desarrollar un conjunto de herramientas que permiten instalar y mantener un nodo, automatizando muchas de las (a menudo) tediosas tareas requeridas para operar a mano. Sin embargo, muchos operadores no las recomiendan por diversos motivos:

  • Al tratarse de una capa de software que envuelve al núcleo del software oficial puede contener errores e, incluso, algunas alteraciones maliciosas introducidas subrepticiamente por algunos colaboradores del proyecto más o menos espontáneos.
  • Su documentación oficial no está muy detallada y no favorece la comprensión de lo que está ocurriendo por debajo.
  • Alimenta la tentación de montar un nodo en cuatro pasos sin conocer con la suficiente profundidad el funcionamiento del software que está en su núcleo, lo que puede dar una falsa sensación de seguridad.

Lo cierto es que ellos mismos aconsejan que nadie utilice sus herramientas como una excusa para ahorrarse el proceso de aprender a manejar el nodo a mano siempre que sea necesario. De hecho, he observado que hay un número no despreciable de gente montando nodos siguiendo tutoriales hechos por operadores (algunos muy bien currados, todo hay que decirlo) al pie de la letra, sin llegar a comprender completamente lo que están haciendo. Huelga decir que cualquier tutorial debe ser utilizado, precisamente, como herramienta de aprendizaje, y nunca como un folleto de instrucciones para poner en marcha una máquina cuyo funcionamiento desconocemos.

Así que, después de practicar y aprender los fundamentos del funcionamiento de los diversos conceptos de Cardano, algunos de los cuales voy vertiendo por aquí, finalmente me he decidido a probar estas famosas herramientas. Lo que viene a continuación son algunas de las anotaciones que he ido haciendo a medida que avanzaba en la configuración, puesta en marcha y mantenimiento del nodo. No pretende ni puede ser una guía exhaustiva de cómo usar las CNTools y demás herramientas. Tan sólo un bloc de notas con aquellos aspectos que me ha parecido relevante destacar.

Leerse la documentación de cabo a rabo

Ésta es mi primera recomendación. Además, no es muy larga. La propia documentación no está escrita en modo tutorial, por lo que hay muchos detalles e informaciones importantes que aparecen después de que hubiera sido necesario tenerlos en cuenta.

Descargar el repositorio y construir el nodo

Este paso no plantea ninguna dificultad en especial. Existen algunos parámetros que pueden ser configurados, pero viene bien explicado en la documentación. En caso de duda, las opciones por defecto dan un buen resultado.

Es interesante familiarizarse con la estructura de directorios creada por la herramienta, ya que necesitaremos navegar por ella para editar, configurar y ejecutar los diferentes archivos de script. Aunque todo esto ya lo cuentan ellos mismos.

Por ejemplo, en el directorio de scripts existe un archivo, llamado env en el que aparecen muchas variables de entorno. Una de las principales (y más útiles en el día a día) es CNODE_HOME, que es la que contiene la ruta en la que se instalará el nodo. Podemos ahorrarnos mucho tecleo cada vez que queremos cambiar a dicha ruta tecleando

cd $CNODE_HOME

en lugar de

cd /opt/cardano/cnode

o cualquier otra ruta de la que se trate

Instalar como un servicio systemd

Aquí viene la primera peculiaridad. Las herramientas contienen un script que automatiza los pasos necesarios para instalar el programa como un servicio del sistema, copiando los scripts de inicio y creando los enlaces simbólicos adecuados. No es algo que resulte difícil de hacer a mano, pero es necesario comprender de qué se trata, lo cual queda fuera del objeto de esta entrada. Para ello, mejor echar un vistazo aquí.

Además, a la hora de ejecutarse el script nos pregunta si queremos instalar un servicio adicional llamado topologyUpdater. Este servicio es el que se encarga (de manera provisional, según el equipo oficial de Cardano, a falta de un servicio de autodescubrimiento P2P que formará parte en un futuro del propio nodo), de descargar una lista de los nodos a los que conectarse, más allá del enlace por defecto a la red de Cardano). Pues bien. Aquí conviene contestar NO al nodo productor de bloques (al que también llamaremos núcleo, que es más corto) y YES al nodo relé.

Por cierto, que el script se llama deploy-as-systemd.sh

Una vez instalado podemos encontrar los scripts de los servicios en las siguientes ubicaciones

Para el productor de bloques:

ls /etc/systemd/system/ | grep cnode
cnode.service

Y, para el relé:

ls /etc/systemd/system/ | grep cnode
cnode-tu-fetch.service
cnode-tu-push.service
cnode-tu-push.timer
cnode-tu-restart.service
cnode-tu-restart.timer
cnode.service
cnode.service.wants

El servicio correspondiente al nodo es el que se llama simplemente cnode.service. Todos los que contienen la expresión ‘-tu-‘ son los referidos al topologyUpdater

Notar que en este punto ambos nodos mostrarán el mismo aspecto desde la herramienta gLiveView y que ambos están funcionando como relés. De hecho, ni siquiera se comunican entre sí, sino que se lo hacen directamente con la red Cardano, sincronizando la cadena de bloques. Por cierto, no es mala idea dejar que terminen de sincronizar antes de continuar. Así que vete a tomar un café o a dar una vuelta, ya que el proceso durará varias horas y hay más mundo ahí fuera que la pantalla del ordenador.

Configurar parámetros de los nodos

Puerto y nombre del pool (sólo en el núcleo) se ajusta en $CNODE_HOME\scripts\env

Nº de núcleos se ajusta en $CNODE_HOME\scripts\cnode.sh

 

Conectar los nodos entre sí (Actualizar la topología)

Éste es uno de los pasos que no sale en la documentación, pero para que los nodos se comuniquen entre sí es necesario especificar sus direcciones IP en los archivos de topología. Dichos archivos se encuentran en:

 nano $CNODE_HOME/files/topology.json

Veremos que en este momento estos archivos contienen información diferente para el núcleo y para el relé. En el caso del núcleo tendremos la configuración de topología por defecto que proporciona un enlace estándar para conectar con los relés de la red Cardano. En el caso del relé, tendremos una expresión algo más compleja pero que si la miramos con detalle veremos que contiene básicamente lo mismo, más un mensaje de error que nos dice que aún no estamos autorizados para descargar la lista de relés. No hay que alarmarse, todo va bien. Simplemente, el acceso a esta lista está reservado a los nodos registrados, y el nuestro aún no lo está. Todo llegará.

De momento, actualizaremos la topología para permitir que los nodos puedan hablar entre sí (y no sólo con la red Cardano, cosa que sólo el relé debería hacer, por cierto).

En el núcleo, actualizaremos el archivo de topología manualmente, poniendo la IP y el puerto del relé:

nano $CNODE_HOME/files/topology.json

{
  "Producers": [
    {
      "addr": "RELAY_IP_ADDRESS",  
      "port": RELAY_PORT,  
      "valency": 1
    }
  ]
}

Si tenemos más de un relé, bastará con ponerlos todos uno a continuación de otros separados por comas, de acuerdo con la sintaxis JSON: Cada máquina está representada por un objeto dentro de un vector que da valor a la variable «Producers».

Y en el relé, como su topología se actualiza automáticamente, lo que editaremos es el script:

nano $CNODE_HOME/scripts/topologyUpdater.sh

Ahora buscaremos la línea con el parámetro CUSTOM_PEERS y la descomentaremos (aunque personalmente yo prefiero copiar la línea debajo sin el #; de esta manera conservo los comentarios originales) y especificaremos la dirección y puerto de nuestro núcleo con la sintaxis indicada en los comentarios del archivo. Si conocemos más relés de otros nodos de sean de nuestra confianza (es decir, de operadores amiguetes nuestros) los colocaremos también aquí.

Si reiniciamos el relé y comprobamos el aspecto del archivo de topología comprobaremos que su contenido se ha modificado (además de su aspecto, mucho más legible) y que ahora también incluye la información de conexión al núcleo.

Nota: En este momento, en teoría bastaría con reiniciar el servicio en ambas máquinas para que todo empezara a funcionar, pero he observado que para que las nuevas topologías surtan efecto puede ser necesario reiniciarlas.

Si ahora comprobamos la información en gLiveView, veremos que ambos nodos han cambiando la información de sus pares. El núcleo ya sólo tiene uno (el relé), y el relé tiene uno más (el núcleo). A partir de ahora, todo el tráfico que llegue al núcleo pasará necesariamente por el relé, así que sería un buen momento para activar el firewall y restringir las conexiones entrantes al núcleo a las provinientes del relé. Todo, lógicamente, dependiendo de nuestro plan de seguridad, según como tengamos estructurada la red.

Si lo que queremos es actualizar las CNTOOLS (Y eventualmente el nodo)

Lo primero es actualizar el script prereqs.sh y ejecutarlo con la opción -f, tal y como viene indicado en la página de GUILD Operators

La opción -f sobreescribirá los scripts y archivos de configuración, pero guardará una copia de aquellos que hayan sido modificados. Entre estos, los más importantes son:

/scripts/env    donde se especifica el puerto y el nombre del pool (sólo para el núcleo)

/scripts/cnode.sh  donde especificamos el nº de núcleos a utilizar

/files/topology.json (sólo para el núcleo, tal y como se ha descrito más arriba)

files/topologyUpdater.sh (sólo para el relé, tal y como se ha descrito más arriba)

 

Publicado por David en Cardano, 0 comentarios

Registrar Stake Pool

En primer lugar, podemos ya probar a ejecutar nuestro stake pool con las claves y el certificado:

cardano-node run \
--topology testnet-topology.json \
--database-path ./db \
--socket-path ./db \
--host-addr 127.0.0.1 \
--port 3000 \
--config testnet-config.json \
--shelley-kes-key kes.vkey \
--shelley-vrf-key vrf.vkey \
--shelley-operational-certificate node.cert

Si bien la salida que obtendremos no será más que un conjunto de mensajes no demasiado reveladores, sí que podremos comprobar que cuando se ejecutan el productor y algún relé simultáneamente, realmente se están comunicando entre sí. Si queremos ver algo más descriptivo de cómo está funcionando nuestro nodo necesitaremos instalar alguna de las herramientas proporcionadas por GUILD Operators, concretamente, gLiveView.

  • Crear certificados

Crear el archivo de metadatos

blah, blah

Crear el certificado de registro

cardano-cli stake-pool registration-certificate \
    --cold-verification-key-file node.vkey \
    --vrf-verification-key-file vrf.vkey \
    --pool-pledge 1000000000 \
    --pool-cost 345000000 \
    --pool-margin 0.01 \
    --pool-reward-account-verification-key-file stake.vkey \
    --pool-owner-stake-verification-key-file stake.vkey \
    --testnet-magic $MAGIC_NUM \
    --single-host-pool-relay <rele.dominio.net> \
    --pool-relay-port 3000 \
    --metadata-url https://miweb.net/metadata \
    --metadata-hash <metadatahash> \
    --out-file pool-registration.cert

Aquí hemos definido algunos parámetros básicos, como la cantidad que estamos dispuestos a comprometer en nuestro pool (1000A), el margen de ganancias (1%), el coste de operación (345A). También pondremos la IP pública (o el nombre de dominio) y el puerto público al que conectarse. Si estamos detrás de un router NAT no olvidemos redirigir este puerto a nuestra IP privada.

También vemos que la dirección de stake para recibir recompensas y para la delegación de los propietarios (que no es otra cosa que la delegación necesaria para cubrir el pledge), son la misma, si bien podrían ser direcciones diferentes. A este respecto, señalar que para proporcionar fondos para el pledge es necesario transferir los mismos a la dirección payment.addr asociada a esta dirección de stake. Para ello creamos el siguiente…

Certificado de delegación

cardano-cli stake-address delegation-certificate \
--stake-verification-key-file stake.vkey \
--cold-verification-key-file cold.vkey \
--out-file pool-delegation.cert

Esto crea un certificado que delega los fondos de la dirección asociada a stake.vkey al pool asociado a la clave node.vkey

  • Registrar el Stake Pool

Este paso consiste en realizar la transacción que enviará nuestros certificados de registro y de delegación a la cadena de bloques. Se trata de una transacción en la que, además de la tarifa ordinaria, deberemos incluir el depósito de registro del pool. Sucesivos re-registros (para cambiar parámetros como el pledge o el archivo de metadatos) requerirán una transacción similar pero sin incluir este depósito.

Borrador de la transacción

cardano-cli transaction build-raw \
--tx-in <TxHash>#<TxIx> \
--tx-out $(cat payment.addr)+0 \
--invalid-hereafter 0 \
--fee 0 \
--out-file tx.draft \
--certificate-file pool-registration.cert \
--certificate-file pool-delegation.cert

Es similar al borrador de una transacción estándar salvo que en las últimas líneas especifican las opciones para incluir los certificados.

Cálculo de la tarifa mínima

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

Igual que siempre

Cálculo del cambio

En este caso, para calcular el cambio debemos deducir, no sólo la tarifa, sino también el depósito de registro. Dicho depósito lo obtenemos de los parámetros del protocolo (esos que antes hemos obtenido y guardado convenientemente en un archivo llamado protocol.json). Como no recuerdo exactamente el nombre del parámetro, que además va cambiando de una versión a otra, tecleo…

cat protocol.json | grep Deposit
    "stakePoolDeposit": 500000000,
    "stakeAddressDeposit": 2000000,

En este caso, el valor que nos interesa es el primero: 500 A

Ya sólo nos queda calcular el cambio como <Balance de UTxO> – tarifa – 500

Construir transacción preliminar

cardano-cli transaction build-raw \
--tx-in <TxHash>#<TxIx> \
--tx-out $(cat payment.addr)+<Cambio> \
--invalid-hereafter <ttl> \
--fee <tarifa> \
--out-file tx.raw \
--certificate-file pool-registration.cert \
--certificate-file pool-delegation.cert

Firmarla

cardano-cli 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

Y enviarla

cardano-cli transaction submit \
--tx-file tx.signed \
--testnet-magic $MAGIC_NUM
Publicado por David en Cardano, 0 comentarios

Generar claves y certificado de operación del Stake Pool

El Stake Pool necesita tres pares de claves, a saber:

  • Node (Cold) Keys: Son las claves del nodo propiamente dicho. A menudo también se les llama Cold Keys por la importancia de ser mantenidas siempre almacenadas en un entorno frío, es decir, fuera del alcance de una conexión a internet, ya que con estas claves se puede obtener el control del Stake Pool. Idealmente, cualquier uso de estas claves debería hacerse en una máquina desconectada de internet, copiando posteriormente los archivos generados al nodo.
  • VRF Keys (Verification Random Function Keys): Son las claves que nos permitirán participar en el procedimiento de Staking.
  • KES Keys (Key Evolving Signature Keys): Claves que van cambiando cada cierto periodo de tiempo para evitar que alguien pueda hacer trampas introduciendo bifurcaciones en la cadena de bloques a partir de bloques anteriores.

Además de estos pares de claves necesitaremos generar un Certificado Operacional

  • Claves del Nodo (Cold)

cardano-cli node key-gen \
    --cold-verification-key-file node.vkey \
    --cold-signing-key-file node.skey \
    --operational-certificate-issue-counter node.counter
  • Claves VRF

cardano-cli node key-gen-VRF \
    --verification-key-file vrf.vkey \
    --signing-key-file vrf.skey
  • Claves KES

cardano-cli node key-gen-KES \
    --verification-key-file kes.vkey \
    --signing-key-file kes.skey

Como vemos, estos tres pares de claves se generan de la nada, es decir, no necesitan ningún archivo previo y su creación no reviste ninguna dificultad. Cada par de claves, como es habitual, consta de una clave de firma (skey) y una clave de verificación (vkey).

  • Certificado operacional

Este certificado es el que nos permitirá ejecutar nuestro nodo de manera que sea candidato para firmar bloques. Para generar este archivo sí que necesitamos contar con algo de información previa, tanto del protocolo como del estado actual de la cadena de bloques. Concretamente, necesitamos saber el nº de periodo KES en el que nos encontramos, y para ello debemos dividir el nº del Slot actual por el nº de slots por periodo

Consultamos el nº de slot por periodo KES a partir de los archivos de información:

cat testnet-shelley-genesis.json | grep KES

"slotsPerKESPeriod": 129600,
"maxKESEvolutions": 62,

De esta salida nos interesa el primer parámetro, en nuestro caso: 129600

Y consultamos el slot actual (con el nodo completamente sincronizado)

 cardano-cli query tip --testnet-magic $MAGIC_NUM
{
    "epoch": 166,
    "hash": "b7331f9a6ec5de5871a74d02807d3fe811cd3f03258cd7542e6002cba592f310",
    "slot": 41772106,
    "block": 3049366,
    "era": "Alonzo",
    "syncProgress": "100.00"
}

Entonces, dividiento slot / slotsPerKESPeriod

expr 41772106 / 129600
322

Que será el nº de periodo KES a partir del cual será válido nuestro certificado. Con este dato ejecutamos:

cardano-cli node issue-op-cert \
    --kes-verification-key-file kes.vkey \
    --cold-signing-key-file node.skey \
    --operational-certificate-issue-counter node.counter \
    --kes-period 322 \
    --out-file node.cert

Y obtenemos el certificado operacional del nodo. Con este archivo ya podemos ejecutar nuestro nodo activamente, es decir, participando en la firma de bloques.

Como medida de seguridad, las claves dejan de ser válidas tras un periodo de 90 días, por lo que tienen que ser regeneradas antes de ese plazo para que el pool siga operando. El proceso es tan sencillo como generar un nuevo par de claves KES y crear otro certificado operacional a partir de la nueva kes.vkey. Despues, basta con reiniciar el productor de bloques y el nodo ya se ejecutará con el nuevo certificado.

Publicado por David en Cardano, 0 comentarios