Cardano

Hace tiempo que unos compañeros y yo venimos participando en la comunidad Cardano mediante la configuración y el mantenimiento de un nodo propio. Así, entre nosotros, no tenemos muchas más pretensiones que apoyar a la comunidad y hacer algo de investigación de campo en el mundo de la blockchain. Así que si lo que quieres es hacerte rico… mejor busca en otra parte.

Importante: Este lugar es un mero registro de las anotaciones que hice durante la configuración inicial del nodo, por lo que no hay ninguna garantía de que esta información esté actualizada. Por esto mismo y por mucho más, desanimo a cualquiera a utilizar estos apuntes como referencia. Si quieres un tutorial hay un material magnífico en la red. Pero si lo que quieres es curiosear por mis idas y venidas, o compartir tu experiencia, entonces, sí, estás en el lugar indicado.


Administración y mantenimiento de un nodo Cardano

Administración y mantenimiento de un nodo Cardano

Las siguientes tareas las llevaremos a cabo mediante las herramientas de CNTOOLS. Se trata de operaciones rutinarias relativamente sencillas que implican transacciones. Por lo tanto, requerirán del uso de claves de firma que, por precaución, nunca deberían guardarse en el nodo. Existen dos modos de llevar a cabo este tipo de tareas.

  • Modo online: si disponemos de todas las claves en el nodo. Es la manera más cómoda de operar, aunque también la más arriesgada. Si realizamos operaciones en este modo, es importante conservar las claves en el nodo únicamente el tiempo imprescindible para realizar la operación.
  • Modo híbrido: La transacción se prepara en el nodo, se pasa a un entorno frío en el cual se encuentran las claves de firma y, una vez firmada, se lleva de vuelta al nodo para enviarla a la red.

En esta entrada, por simplicidad, nos referiremos al modo online y haremos referencia a las claves necesarias para cada operación. Dichas claves deberían conservarse en una unidad externa cifrada y ser copiadas temporalmente al nodo durante los minutos que dura la operación. A continuación deberán ser borradas con un programa de borrado seguro.

Rotación de claves

Hay ocasiones en las que un servidor es puesto en funcionamiento y posteriormente desatendido e incluso olvidado. Contrariamente a lo que se pudiera pensar, un servidor en estas condiciones puede mantenerse en funcionamiento durante mucho tiempo sin que nadie se ocupe de él e, incluso, sin que sea fácil siquiera acceder a su ubicación para retirarlo de la circulación. Esto no resulta tan raro si pensamos en servidores virtuales o servicios en funcionamiento alojados en servidores más grandes que están suministrando otros servicios de manera simultánea. Esto explicaría por qué el servidor físico sigue recibiendo mantenimiento por parte de responsables que pueden llegar a ignorar durante años la existencia de servicios «fantasma» ejecutándose en sus máquinas.

Sin ir más lejos, yo mismo me he encontrado con esta circunstancia al menos en dos ocasiones. En ambos casos se trataba de páginas web profesionales que habían sido puestas en funcionamiento en servidores compartidos por responsables que luego desaparecieron del mapa. Las páginas pronto quedaron obsoletas sin que fuera posible acceder a ellas para desactivarlas o actualizarlas.

Pues bien. Para evitar que los nodos de Cardano puedan llegar a convertirse en nodos fantasma, degradando así el funcionamiento de la red, los operadores tienen la obligación de renovar unas claves cada tres meses para que el nodo siga teniendo la capacidad de firmar bloques. A este proceso se le llama rotación.

Claves necesarias: cold.skey

ruta: $CNODE_HOME/priv/pool/<pool_name>/

Retiro de recompensas

Las recompensas obtenidas tras la firma de bloques se van depositando en una dirección específica dentro de nuestra billetera. Estas recompensas son delegadas en el «pool» de manera automática, por lo que si no queremos disponer de ellas no es necesario realizar ninguna acción. Sin embargo, estrictamente no forman parte de los fondos de la billetera propiamente dicha, así que no nos servirían para cumplir con el «pledge», en caso de que quisiéramos aumentarlo. En cualquier caso, bien porque queramos elevar el «pledge», bien porque queramos transferirlas a otra dirección, antes o después necesitaremos retirarlas.

Importante: Los gestores de billeteras tipo Daedalus o Yoroi incorporan una opción para retirar las recompensas directamente. Esto está muy bien si estamos delegando en cualquier «pool» que no sea el nuestro o siempre que se trate de una billetera diferente de la utilizada para crear el nodo. Sin embargo, si durante la creación del nodo decidimos incorporar una billetera externa generada con Yoroi o Daedalus es muy importante que no realicemos el retiro de las recompensas desde ninguno de estos programas externos, ya que en este caso se rompería la sincronización entre el saldo real y el mostrado en la billetera. Una billetera de este tipo debería utilizarse solamente como herramienta de monitorización. Cualquier transacción deberá realizarse directamente con las herramientas de cliente del nodo.

Claves necesarias: payment.skey, stake.skey

ruta: $CNODE_HOME/priv/wallet/<wallet_name>/

Listado de claves

A modo de chuleta, aquí dejo una tabla con el listado de claves del nodo y donde podemos encontrar cada una de ellas.

Para el pool

Clave hot node cold node
cold.skey X
cold.vkey X X
hot.vkey X X
hot.skey X X
vrf.vkey X X
vrf.skey X X

Para la billetera

Clave hot node cold node
base.addr X X
reward.addr X X
payment.addr X X
payment.vkey X X
payment.skey X
stake.vkey X X
stake.skey X
stake.cert X
delegation.cert X
Publicado por David en Cardano, 0 comentarios
Visualización de métricas con Prometheus y Grafana

Visualización de métricas con Prometheus y Grafana

¿Prometheus, Grafana o los dos?

Grafana es una de las herramientas más extendidas y populares para visualizar datos de manera gráfica. Además, estos datos pueden ser adquiridos en tiempo real de sistemas en funcionamiento, lo que permite controlarlos y monitorizarlos con detalle.

La verdad es que a poco que nos hayamos movido por el entorno de Cardano seguro que ya nos hemos encontrado con Grafana, ya que se trata de la opción más extendida y recomendada cuando se trata de supervisar un nodo de la red. No obstante, sus aplicaciones son prácticamente ilimitadas, y en mi caso concreto también me resulta muy útil como panel de control del sistema domótico Openhab.

Grafana puede conectarse a varias fuentes de datos. Una de las más populares, por ser la utilizada por Cardano, es Prometheus. También puede conectarse a InfluxDB, lo cual es muy conveniente, al ser una de las opciones más comunes de entre las disponibles en Openhab.

Prometheus es un software que tiene algunos puntos en común con Grafana. Por sí sólo también es capaz de recolectar datos y mostrarlos en forma de gráficas, aunque sus posibilidades en este sentido son mucho más limitadas. En realidad, sólo con Prometheus ya podríamos realizar la monitorización de un sistema, incluyendo el nodo de Cardano, pero Grafana añade una capa de funcionalidad y prestaciones que resultan muy convenientes. De ahí que, a menudo, en todos los artículos referidos a la monitorización en Cardano aparezcan juntos.

A efectos prácticos utilizaremos Prometheus como un sistema para recolectar y recopilar las métricas que nos interese monitorizar y Grafana como una capa adicional para transformar y visualizar estos datos de la manera que nos resulte más conveniente.

Empecemos por Prometheus

Prometheus recolecta métricas a partir de lo que llama end-points, los cuales no son sino puntos de conexión mediante el protocolo http en los que se encuentran expuestas dichas métricas en un formato XML entendible por Prometheus.

Configuración

La configuración es sencilla, pero si no queremos desorganizar demasiado los scripts de inicio del servicio systemd conviene hechar un vistazo al contenido de éste:

sudo nano /lib/systemd/system/prometheus.service
...
EnvironmentFile=/etc/default/prometheus
ExecStart=/usr/bin/prometheus $ARGS
...

Por cierto, si quieres recordar cómo encontrar la ubicación de los scripts de servicio, echa un vistazo a esta entrada.

En este archivo vemos que el ejecutable es invocado con una variable de entorno $ARGS que contiene los argumentos que se pasan al programa. Vemos también la ubicación del archivo de entorno donde encontraremos la asignación de dicha variable. Si editamos dicho archivo:

sudo nano /etc/default/prometheus

# Set the command-line arguments to pass to the server.
ARGS=""

# Prometheus supports the following options:
#  --config.file="/etc/prometheus/prometheus.yml"
#                             Prometheus configuration file path.
#  --web.listen-address="0.0.0.0:9090"
...

Observamos que la variable de entorno está vacía, lo que nos indica que se toman los argumentos por defecto. Vemos también, comentados, todos los argumentos que pueden ser pasados al ejecutable. Una opción sería especificar dichos parámetros directamente en el archivo de servicio donde se llama al ejecutable, eliminando la variable de entorno $ARGS. Sin embargo, una opción más elegante es colocar dicho parámetro dentro de la cadena $ARGS y permitir que para el resto de parámetros no especificados se apliquen los valores por defecto. Por ejemplo, para modificar el puerto al 9095 podríamos dejar el archivo así (observar las secuencias de escape para las dobles comillas):

sudo nano /etc/default/prometheus

# Set the command-line arguments to pass to the server.
ARGS="--web.listen-address=\"0.0.0.0:9095\""

# Prometheus supports the following options:
#  --config.file="/etc/prometheus/prometheus.yml"
#                             Prometheus configuration file path.
#  --web.listen-address="0.0.0.0:9090"
...

Para configurar los endpoints a los que conectarse, editar el archivo:

sudo nano /etc/prometheus/prometheus.yml

Métricas de Cardano

El software cardano-node ofrece, de manera nativa, un end-point con las métricas de funcionamiento del nodo. En el archivo de configuración de cardano-node encontraremos un apartado donde configurar el número de puerto (por si necesitáramos cambiarlo) y las direcciones desde las cuales es posible conectarse al end-point (punto importante cuando el servidor Prometheus está en una máquina diferente). Concretamente, esta sección tiene el siguiente aspecto:

"hasPrometheus": [
    "127.0.0.1",
    12798
  ]

Ésta es la configuración por defecto. Indica que la conexión sólo es posible desde la máquina local y en el puerto 12798. Si necesitamos conectarnos desde otra máquina, deberemos especificar, o bien la dirección IP de la misma, o bien «0.0.0.0» para la conexión desde cualquier dirección IP. No olvidemos que, en este caso, además deberemos habilitar este puerto en el firewall.

Si queremos echar un vistazo a los datos en crudo ofrecidos por el end-point de nuestro nodo bastará con dirigir nuestro navegador a la dirección:

http://<ip_nodo>:12798/metrics

Obviamente, el end-point deberá ser accesible desde la máquina en la que tengamos el navegador. Como es posible que eso no coincida con la configuración que estamos planeando, y para no andar toqueteando aquí o alla, una buena alternativa al navegador es el comando curl en la misma máquina en la que se encuentre el end-point:

curl -s http://localhost:12798/metrics

Métricas del nodo

Otro conjunto de datos que suele resultar interesante para comprobar el buen desempeño de una máquina es el relacionado con el correcto funcionamiento y rendimiento del hardware y del sistema operativo: temperaturas, carga de la CPU, uso de memoria, etc. Estas métricas pueden obtenerse instalando el software prometheus-node-exporter, el cual recopila todos estos parámetros y los expone en un nuevo end-point en el puerto 9100. Como antes, para comprobar el buen funcionamiento del end-point:

curl -s http://<ip_nodo>:9100/metrics

Aunque parezca una trivialidad, no está de más no confundir el software prometheus-node-exporter, el cual sólo crea un end-point donde exponer métricas de funcionamiento de la máquina, con el servidor Prometheus, que es el que se encarga de recopilar y almacenar todos los datos obtenidos de los diferentes end-points. Aunque a menudo se instalen a la vez, son piezas de software diferentes y ni siquiera es necesario que vayan juntos.

Métricas de dispositivos de red

El protocolo SNMP (Simple Network Management Protocol) permite el intercambio de información entre dispositivos conectados a una misma red. Entre sus usos más frecuentes se encuentra la configuración automática de routers o firewalls por parte de aquellos programas que lo necesiten. Sin embargo, también es posible utilizarlo para obtener métricas de dispositivos de red y mostrarlas en Grafana. Por ejemplo, podemos monitorizar el router y comprobar el buen funcionamiento de nuestra conexión a internet.

Necesitaremos dos cosas:

  • Que nuestro router sea compatible con SNMP y que éste se encuentre habilitado
  • Tener instalado prometheus-snmp-exporter en nuestro servidor. Este software es capaz de comunicar con dispositivos que hablen SNMP y de ofrecer las métricas así obtenidas exponiendo un end-point para Prometheus. Este software se puede instalar directamente desde los repositorios de Ubuntu o bien descargándolo desde github, concretamente, aquí.

Su configuración se encuentra en el archivo:

sudo nano /etc/prometheus/snmp.yml
# Due to licensing reasons, it is not possible to ship a ready-to-use snmp.yml
# config file.
#
# See /usr/share/doc/prometheus-snmp-exporter/README.Debian for instructions
# on using prometheus-snmp-generator to create a suitable snmp.yml config.

En el que nos encontramos este curioso mensaje. La lectura del archivo README.Debian tampoco proporciona mucha más información.

La manera de proceder es sencilla. En github, que es donde se aloja el proyecto, viene un archivo snmp.yml por defecto que en la mayoría de las ocasiones nos funcionará correctamente, así que podemos, simplemente, descargarlo en el directorio arriba mencionado.

Importante: dependiendo del método escogido para instalar prometheus-snmp-exporter nos encontraremos con una versión u otra. Normalmente, las versiones disponibles en los repositorios oficiales de Ubuntu suelen estar algo desfasadas con respecto a la última versión disponible en GitHub. Esto es importante, porque si el software instalado y el archivo de configuración descargado corresponden a versiones diferentes, podría no funcionar.

Por ejemplo, en el momento de escribir esta entrada, la versión instalada a partir de los repositorios de Ubuntu es la v0.16.1, bastante anterior a la versión actual de GitHub, que es la v0.20.0. Por lo tanto necesitamos buscar el archivo de configuración de la versión adecuada, lo que conseguimos tecleando:

sudo wget https://raw.githubusercontent.com/prometheus/snmp_exporter/v0.16.1/snmp.yml

Si todo va bien, podemos observar las métricas en el endpoint correspondiente:

curl http://<server_ip>:9116/snmp?target=<router_ip>

Visualizando con Prometheus

Como decíamos, Prometheus por sí mismo puede ser utilizado como herramienta de monitorización y visualización. Para ello, sólo hay que conectarse desde un navegador a la dirección de la máquina donde se esté ejectuando el servidor:

http://<nodo_prometheus>:9010

Y veremos algo como esto:

Prometheus

En esta página disponemos de algunas opciones que nos permiten ir añadiendo gráficas y seleccionando las métricas deseadas.

Y sigamos con Grafana

Grafana suele ser instalada en la misma máquina en la que tenemos el servidor Prometheus pero, en realidad, podría estar en cualquier otro. Dispone de la posibilidad para conectar con diferentes fuentes de datos, entre ellas, como ya hemos comentado, con Prometheus y con InfluxDB.

Contrariamente a lo que pensé en un principio, Grafana no es capaz de conectar directamente con los end-points que proporcionan los datos para Prometheus, sino sólo con éste último. Es decir, que para monitorizar un nodo de Cardano, Grafana nos la podríamos ahorrar, pero Prometheus no.

Base de datos

Grafana utiliza una base de datos de tipo SQLite ubicada en /var/lib/grafana/grafana.db

  • Si en algún momento metemos la pata y deseamos deshacer el desaguisado manualmente, siempre podemos descargar el archivo y editarlo manualmente con esta excelente herramienta de código abierto: DB Browser for SQLite
  • No está de más incluir este archivo entre aquellos de los que solemos hacer copia de seguridad.
Publicado por David en Cardano, Domótica, Linux, 0 comentarios
Monitorización del nodo

Monitorización del nodo

La primera herramienta que se suele utilizar para monitorizar el funcionamiento de un nodo recién creado es gLiveView, que forma parte de las CNTOOLS proporcionadas por GUILD Operators.

Un dato que se suele indicar como relevante para comprobar el buen funcionamiento del nodo suele ser el que indica el número de transacciones procesadas y pendientes de procesamiento. En condiciones normales, este número se va incrementando. Sin embargo, no es extraño que al instalar un nodo por primera vez, y dependiendo de la versión de Cardano que hayamos utilizado, nos encontremos con que este número se mantiene invariablemente igual a cero.

Una posibilidad es que el nodo no esté funcionando adecuadamente debido a que los nodos no se están comunicando bien entre sí o con el exterior. Podemos comprobar las conexiones, tanto para el núcleo como para los reles, con esta instrucción:

netstat -pant | grep 6000

Sin embargo, otra causa puede ser, simplemente, que el nodo no esté informando de este parámetro, por lo que gLiveView no puede mostrarlo. Podemos comprobar las métricas informadas por el nodo con el siguiente comando:

curl -s 127.0.0.1:12798/metrics | sort

El que dicho parámetro se informe o no se encuentra en el ajuste del parámetro «TraceMempool»:false que se encuentra en el arcivo de configuración. Siguiendo la estructura de directorios utilizada por CNTOOLS:

nano $CNODE_HOME/files/config.json

Es importante precisar que el ajuste de este parámetro puede influir en el rendimiento del nodo. El ajuste a ‘false’ parece ser que favorece la reducción de memoria y cpu, lo que es interesante cuando las máquinas vay muy ajustadas, por lo que también ser reduce la probabilidad de perder bloques (Éste es el ajuste por defecto, al menos desde la versión 1.31.0. En las anteriores, no me acuerdo). Sin embargo también puede enmascarar un mal funcionamiento del nodo. En general, un criterio que parace razonable es ajustarlo en ‘true’ siempre que nuestro hardware no se vea comprometido, al menos en el núcleo y, en todo caso, ajustarlo a ‘false’ en los relés (Hay una discusión sobre este asunto aquí).


Publicado por David en Cardano, 0 comentarios
Securizar un stake pool

Securizar un stake pool

Lo primero, el servicio SSH

Lo primero que tenemos que hacer para estar razonablemente seguros de que nuestro stake pool se encuentra seguro ante posibles intrusiones es ajustar el servicio SSH a nuestras necesidades reales. en nuestro caso, utilizamos una autenticación de dos factores mediante un par de claves pública y privada y el servicio de autenticación de Goggle. Tampoco estaría de más restringir las direcciones desde las cuales vamos a autorizar las conexiones al servicio SSH, siempre que esto sea posible. Lógicamente, si estamos en una red privada o una VPN en la que disponemos de direcciones privadas bien definidas, o nos conectamos desde accesos con IP’s públicas fijas, esta opción es inmejorable. Sin embargo, si necesitamos conectarnos desde lugares más o menos arbitrarios con IP’s públicas o privadas asignadas dinámicamente, esta estrategia no es posible.

Como siempre, no existe un plan de seguridad estándar perfecto. El mejor plan de seguridad es el que se adapta de manera adecuada a la estructura de nuestro sistema y a las circunstancias personales de cada cual.

Después, el firewall

Lo siguiente es restringir el tráfico a nuestros ordenadores mediante el firewall. Como la mayoría de operadores de Stake Pools, he elegido la opción de ufw (Uncomplicated FireWall) frente a la configuración de IPtables. Sé que los más avezados expertos en Linux no tardarán en advertir que si IPtables existe es por algo, y que su mayor complejidad ofrece la contrapartida de un control mucho más preciso y robusto de las conexiones del PC. Y tendrán toda la razón. En mi descargo diré que también es bastante más lioso de configurar y, por lo tanto, mucho más probable que en manos de un zarpas como yo se deslicen gazapos que puedan convertirse en brechas de seguridad.

Es importante entender que la seguridad real implica un compromiso entre la robustez de la herramienta y la habilidad para manejarla de manera correcta. No hay nada más peligroso que un AK-47 en manos de un chimpancé.

Y, la verdad, es que ufw cumple con este cometido, al menos para mí. Si un día me decido a estudiar IPtables a fondo, os prometo que seréis los primeros en saberlo.

Dicho esto, lo primero será asegurarnos de que tenemos ufw instalado en nuestro equipo, lo cual no es difícil porque en la mayoría de distribuciones suele venir por defecto. En cualquier caso, basta con teclear:

sudo apt install ufw

Reading package lists... Done
Building dependency tree       
Reading state information... Done
ufw is already the newest version (0.36-6).
ufw set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

Lo cual nos demuestra que, efectivamente, ya está instalado. Cuando hacemos esto, nos encontramos con el mensaje de que el paquete en cuestión ha sido marcado como instalado manualmente, lo cual a mí, que soy un maniático, me ralla un poco. Si quieres saber más, mira esta otra entrada.

Volviendo al firewall, lo primero que comprobamos es su estado

sudo ufw status
Status: inactive

Es decir, que viene deshabilitado por defecto. Lo cual es conveniente para evitar cortar servicios que pudieran estar en ejecución antes de poder configurarlo. Sin ir más lejos, si estamos conectados a la máquina por SSH y habilitamos el firewall ya podéis imaginar lo que iba a pasar (spoiler: la conexión se corta sin posibilidad de volver a conectar hasta poder acceder físicamente)

Así que lo primero de todo, habilitaremos la conexión al servicio ssh

sudo ufw allow ssh
Rules updated
Rules updated (v6)

Como vemos, esta es una manera rápida de habilitar conexiones al ordenador, basándonos en servicios, en lugar de puertos.

Nota: En muchos manuales veremos que es interesante como medida adicional de protección modificar el puerto por defecto utilizado por el servicio ssh (que pertenece a ese grupo de puertos denominados como «bien conocidos» y que corresponde siempre al 22). En mi opinión, se trata de una medida más incómoda que eficaz. Cualquier atacante puede imaginar que el servicio ssh se puede estar ejecutando en cualquier otro puerto y el primer paso antes de probar nada suele ser un escaneo de puertos para averiguar qué tenemos por ahí. Y lo mismo vale para cualquier servicio ejecutado en uno de los susodichos «well known ports»

Ahora sí, habilitamos el firewall

sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Y como era de esperar en un programa bien implementado y dirigido a dummies como yo, nos advierte de los peligros antes de hacernos caso.

Comprobemos las reglas que tenemos hasta ahora:

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere 
22/tcp (v6)                ALLOW       Anywhere (v6)       

Efectivamente, el bien conocido puerto 22 accesible para el protocolo tcp desde cualquier lugar. Eso es lo que ha mantenido nuestra conexión activa. Nuevamente, si sabemos desde qué direcciones nos vamos a conectar, éste sería otro buen lugar para restringir el acceso desde esas direcciones, además de la configuración del propio servicio ssh. Cuantas más puertas, mejor.

Bien, si ya teníamos nuestro stake pool en funcionamiento con un núcleo y un relé hablando entre sí, será interesante lanzar la aplicación gLiveView para ver lo que ha pasado. Y es que, si todo va bien, las dos máquinas ya no podrán hablar entre sí. Al menos, el relé ya no podrá acceder al núcleo, ya que éste está restringiendo todas las conexiones entrantes. Lógicamente, nos interesa añadir una regla que permita esta comunicación. Será la siguiente:

sudo ufw allow proto tcp from <IP_RELAY> to any port <PORT_KERNEL>

En cristiano, permitir toda conexión entrante en protocolo tcp desde la IP del relé al puerto en el cual se ejecuta el nodo del núcleo. Sencillo, ¿no?

Comprobemos…

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
<PORT_KERNEL>/tcp          ALLOW       <IP_RELAY>             
22/tcp (v6)                ALLOW       Anywhere (v6) 

Y para evitar paranoias, nada como un túnel SSH

Cualquier manual básico de Cardano nos explica que la necesidad de disponer un cierto número de relés además del nodo productor de bloques (o núcleo) tiene que ver con una cuestión básica de seguridad: el núcleo jamás debería estar directamente expuesto a la red. De este modo, los únicos nodos que pueden ser comprometidos son los relés, y si disponemos de más de uno, bastaría con apagarlo y usar los otros mientras arreglamos el desaguisado. Pero claro, la primera pregunta que surge es… y si el núcleo no está abierto a la Internet… ¿cómo diablos me conecto a él para configurarlo? Si te has hecho esta pregunta, felicidades: vas por el buen camino (y estás jodido).

Y ahora, veamos las distintas respuestas:

1.- ¡Qué le vamos a hacer!

Dejaremos el puerto ssh abierto con un porrón de medidas de seguridad, especiamente, autenticación multifactorial (MFA) y cruzaremos los dedos.

Bien, no está mal. Conozco a unos cuantos que han seguido esta política y aún no les ha pasado nada. Afortunadamente, un servicio ssh bien configurado es muy seguro.

2.- Restringimos también el acceso ssh a través del relé.

Es decir, nos conectaremos mediante ssh al relé, y de allí al núcleo. Es una medida muy sensata. Y lo único que requiere es modificar un poquito el firewall para que el acceso al núcleo quede restringido únicamente al relé.

Añadimos una regla por aquí… (la que nos permitirá el acceso al núcleo desde el relé)

sudo ufw allow proto tcp from <IP_RELAY> to any port 22

Con lo cual:

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
6000/tcp                   ALLOW       <IP_RELAY>             
22/tcp                     ALLOW       <IP_RELAY>             
22/tcp (v6)                ALLOW       Anywhere (v6)   

Y eliminamos otra por allá… (la que permitía el acceso ssh indiscriminado)

sudo ufw delete 1
Deleting:
 allow 22/tcp
Proceed with operation (y|n)? y
Rule deleted

Y ya estaría. Sin embargo, esta estrategia plantea un nuevo problemilla nada trivial. Como comentábamos en el apartado relativo a la conexión segura con SSH, si ya era importante no dejar la llave privada en cualquier máquina local, aún más lo será no dejarla permanentemente en el relé para cuando necesitemos realizar la conexión al núcleo desde allí. La solución de copiarla mediante scp y borrarla cada vez puede ser una opción, pero desde luego resulta lo bastante incómoda como para caer en la muy humana tentación de dejarla almacenada en el relé y confiar en el sistema 2FA. Aunque, si todo este guirigay de relés tienen que ver con considerar la posibilidad de que se estos puedan verse comprometidos, ya no parece tan buena opción, ¿verdad?. Afortunadamente, aún existe una tercera opción (y más que habrá, pero hasta aquí llega mi cacumen por hoy).

3. Crear un túnel ssh desde la máquina local al núcleo a través del relé

Y una vez establecido dicho túnel, conectarnos directamente desde la máquina local al núcleo. Tenemos como prerequisito que la máquina núcleo sea accesible únicamente desde la máquina relé, lo cual ya ha quedado descrito en la opción número 2. La magia vienen a continuación:

En primer lugar, creamos un túnel a través del relé que redirija un puerto de nuestra máquina local a otro puerto de la máquina núcleo.

ssh -L 8022:<IP_CORE>:22 <user_relay>@<IP_RELAY> -i /route-to-key/private-key

Este comando crea un túnel desde el puerto 8022 de mi máquina local al puerto 22 de la máquina core. Utilizamos el puerto local 8022 ya que el puerto 22 suele estar ocupado por el servidor ssh local y es preferible utilizar uno libre para evitar conflictos. Los datos de conexión son los mismos que usamos para conectar al relé: el nombre de usuario y su IP. Y, por supuesto, la clave pública que guardamos en nuestro pendrive, y que se especifica con el parámetro -i (identidad). Si todo va bien, el único dato que nos pedirá será el código del Google Authenticator y el túnel quedará establecido.

Desde ahora, cualquier petición al puerto 8022 a la máquina local será como si la realizáramos directamente al puerto 22 del nucleo, por lo que podremos conectar simplemente así:

ssh  -p 8022 <user>@127.0.0.1 -i /route-to-key/private-key 

Es decir, que en realidad nos estamos conectando a nuestra propia máquina en el puerto 8022. Y, por supuesto, el archivo de clave privada permanece a buen recaudo en nuestro preciado pendrive. ¿A que mola?

Publicado por David en Cardano, Linux, Seguridad, SSH, 0 comentarios
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

Tipos de direcciones en Cardano

Explicado de una manera muy sencilla, una dirección en Cardano es básicamente un número que puede contener fondos. En este sentido, podríamos verlo como el número de cuenta bancaria en la cual mantenemos nuestro dinero. Los fondos pueden transferirse entonces de unas direcciones a otras mediante unas operaciones llamadas transacciones (el equivalente a una transferencia bancaria)

La cadena de bloques sería la base de datos en la cual quedan registradas de manera inalterable todas las transacciones en que las distintas direcciones se ven implicadas. De esta manera, consultando la cadena de bloques es posible conocer el saldo de cualquier dirección, así como todo el histórico de transferencias

En Cardano existen básicamente dos tipos de direcciónes, a las que nos referiremos como direcciones de pago (payment) y de stake.

Cada uno de este tipo de dirección está asociada a un par de claves, una pública y otra privada. A la dirección pública la llamamos de verificación y a la privada de firma.

La clave de verificación, abreviadamente vkey (que es pública), es la que permite que cualquiera pueda verificar su existencia y su saldo en la cadena de bloques. La clave de firma, abreviada como skey (que es privada) servirá para firmar las transacciones que permiten transferir fondos de una dirección a otra.

Generación de claves y direcciones

El proceso de generación de cualquiera de las claves es muy similar: Primero se solicita a la herramienta cardano-cli la creación del par de claves, vkey y skey, y, a partir de la primera, se genera la clave en cuestión.

Generación de las claves y la dirección de payment:

cardano-cli address key-gen \
--verification-key-file payment.vkey \
--signing-key-file payment.skey

A partir de la clave de verificación generamos la dirección:

cardano-cli address build \
--payment-verification-key-file payment.vkey \
--out-file payment.addr \
--testnet-magic $MAGIC_NUM

Generación de las claves y la dirección de stake:

cardano-cli stake-address key-gen \
--verification-key-file stake.vkey \
--signing-key-file stake.skey

A partir de la clave de verificación generamos la dirección::

cardano-cli stake-address key-gen \
--verification-key-file stake.vkey \
--testnet-magic $MAGIC_NUM

Un par de observaciones:

  • Las claves son generadas con independencia de la red en la cual vayan a ser utilizadas. Sin embargo, para generar la dirección, es necesario especificar a qué red va a pertenecer (testnet o mainnet)
  • Aunque cada dirección lleva asociadas dos claves, una pública y otra privada, la generación de la dirección se realiza utilizando únicamente la clave pública.

Diferencias entre claves de payment y de stake

  • La clave de payment es una clave que sirve, básicamente, para almacenar, recibir y transferir fondos.
  • La clave de stake sirve para tomar el control en la participación en el protocolo. Permite delegar fondos en los diferentes Stake Pools y también es donde se reciben las recompensas por ello. Será necesaria, también, si queremos crear nuestro propio Stake Pool. No es posible, sin embargo, transferir fondos a una dirección de Stake, aunque sí lo es transferir las recompensas recibidas hacia otras direcciones, evidentemente.

Es importante señalar que una clave de payment generada como hemos visto, aunque perfectamente funcional, no permite la delegación de fondos en un stake pool. Para que esta delegación sea posible, será necesario que la dirección de payment se encuentre vinculada a una dirección de stake, la cual, a su vez, será la que nos permitirá realizar la delegación. Este procedimiento será el que estudiaremos en detalle en las próximas entradas.

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

Cómo delegar fondos en un «stake pool»

Para ser capaces de delegar fondos en un determinado Stake Pool será necesario cumplir tres condiciones:

  1. La dirección de payment en la cual tenemos los fondos que deseamos delegar deberá estar asociada a una dirección de stake.
  2. Dicha dirección de stake debe estar convenientemente registrada en la en la cadena de bloques mediante un certificado de registro. Este certificado deberá ser remitido a la cadena de bloques con una transferencia específica que comporta un depósito. En el momento de escribir estas líneas, el depósito es de 2 ₳ 
  3. Será necesario, además, un certificado de delegación que asocie la dirección de stake con el pool seleccionado, que deberá ser remitido a la cadena de bloques con una transferencia estándar con la tarifa mínima.

Una vez realizado el proceso completo, los fondos depositados en la dirección de payment asociada a la clave de stake en cuestión participarán del monto total de fondos delegados al pool, colaborando en la creación de bloques por parte de ese pool y recibiendo recompensas por ello en la misma dirección de stake.

Dado el procedimiento, podemos ver también que cambiar de pool es tan sencillo como crear un nuevo certificado de delegación y remitirlo a la cadena de bloques, lo que implica una transacción estándar con tarifa mínima. El depósito inicial de 2 ₳ es necesario realizarlo solamente una vez para habilitar nuestra dirección a participar en el proceso de delegación. 

  • Crear una dirección de payment asociada a una dirección de stake

Para obtener una dirección de payment asociada a una dirección de stake, el procedimiento es muy sencillo, ya que basta con generar la dirección aportando la clave de verificación de stake, además de la clave de verificación de payment. En este ejemplo, para distinguir la dirección de payment asociada a stake de una dirección de payment regular, la llamaremos paymentwithstake.addr

cardano-cli address build \
--payment-verification-key-file payment.vkey \
--stake-verification-key-file stake.vkey \
--out-file paymentwithstake.addr \
--testnet-magic $MAGIC_NUM
  • Registrar la dirección de Stake

  • Crear un certificado de registro

Antes de poder empezar a delegar fondos es necesario registrar la dirección de stake en la cadena de bloques. Y el primer paso para ellos es crear un certificado de registro de dicha dirección.

cardano-cli stake-address registration-certificate \
--stake-verification-key-file stake.vkey \
--out-file stake.cert

A continuación, es encesario remitir el certificado a la cadena de bloques. Para ello, realizaremos una transacción desde la dirección de pago , en este caso, paymentwithstake.addr en la cual hay que incluir, de la tarifa estándar, el depósito antes mencionado. Ambas se deducen del balance de la dirección de pago a la hora de especificar el cambio devuelto.

Es importante señalar que en este tipo de transacción no se transfieren fondos a ninguna dirección. Tanto la tarifa como el depósito son descontados durante la transacción al calcular el balance resultante que es devuelto en la misma dirección de pago. El destino de ambas cantidades podemos entenderlo como una especie de servicio de tesorería dentro sistema de Cardano, el mismo que genera y administra las recompensas y la expansión monetaria del sistema. Los pasos para realizar la transacción son los habituales:

  • Obtenemos el balance de la dirección de pago

cardano-cli query utxo --address $(cat paymentwithstake.addr) --testnet-magic $MAGIC_NUM

                          TxHash                                 TxIx        Amount
--------------------------------------------------------------------------------------
96c74decbb8079ef017efabe5901ef40ff046a9c1f74ddd0c5eefc46353b53e5     0        1000000000 lovelace + TxOutDatumHashNone
  • Comprobamos la tarifa de registro

Si no lo hemos hecho antes, obtenemos los parámetros del protocolo que guardaremos en el archivo params.json. Entre otras muchas cosas, podemos obtener la tarifa por registrar la dirección de stake que, como ya hemos dicho, en este momento es de 2 ₳.

cardano-cli query protocol-parameters \
--testnet-magic $MAGIC_NUM \
--out-file params.json
  • Calcular el TTL (Time To Live)

Obtenemos el slot actual de la cadena para calcular el TTL (Time To Live) de la transacción

cardano-cli query tip --testnet-magic $MAGIC_NUM

{
    "epoch": 166,
    "hash": "13e9f47d0a19feb5f860a4b7b571162479ad103331cff1c56d24c116a937ae8f",
    "slot": 41347556,
    "block": 3036045,
    "era": "Alonzo",
    "syncProgress": "100.00"
}

Sabiendo que el tiempo entre dos slots es de un segundo, basta con sumar al slot actual un tiempo que consideremos razonable para armar la transacción sin prisas (normalmente, unos pocos minutos es suficiente)

  • Construimos el borrador de la transacción

Esto es necesario como paso previo para poder calcular la tarifa de la transacción. En este caso podemos dar un valor ‘0’ a los parámetros específicos de la transacción, tales como la tarifa, el cambio o el ttl.

cardano-cli shelley transaction build-raw \
--tx-in 96c74decbb8079ef017efabe5901ef40ff046a9c1f74ddd0c5eefc46353b53e5#0 \
--tx-out $(cat paymentwithstake.addr)+0 \
--ttl 0 \
--fee 0 \
--out-file tx.draft \
--certificate-file stake.cert
  • Calcular la tarifa mínima

A partir del borrador, calculamos la tarifa mínima

Es interesante comprobar que la tarifa de la transacción no depende para nada de las cantidades a transferir.

cardano-cli transaction calculate-min-fee \
--tx-body-file tx.draft \
--tx-in-count 1 \
--tx-out-count 1 \
--witness-count 1 \
--byron-witness-count 0 \
--testnet-magic $MAGIC_NUM \
--protocol-params-file protocol.json
 
172761 Lovelace
  • Construir la transacción definitiva

Aquí es donde podemos observar como la única dirección de salida es la misma que aquella de la que se obtienen los fondos y que se especifica solamente para recibir el «cambio» de la transacción, el cual es básicamente el balance inicial menos la tarifa y el depósito.

En mi caso, el cálculo de dicho cambio es el siguiente: 1000.000.000 – 2.000.000 – 172.761 = 997.827.239

cardano-cli transaction build-raw \
--tx-in 96c74decbb8079ef017efabe5901ef40ff046a9c1f74ddd0c5eefc46353b53e5#0 \
--tx-out $(cat paymentwithstake.addr)+997827239 \
--ttl 41444206 \
--fee 172761 \
--out-file tx.raw \
--certificate-file stake.cert
  • Firmar la transacción

Aquí podemos observar una caracterísitica específica de este tipo de transacción con respecto a una transacción convencional de movimiento de fondos: En este caso se proporcionan ambas claves de firma: la de pago y la de stake.

cardano-cli transaction sign \
--tx-body-file tx.raw \
--signing-key-file payment.skey \
--signing-key-file stake.skey \
--testnet-magic $MAGIC_NUM \
--out-file tx.signed
  • Enviar la transacción firmada

cardano-cli transaction submit \
--tx-file tx.signed \
--testnet-magic $MAGIC_NUM

Transaction successfully submitted.

Y… voilà!

  • Registrar la delegación en un determinado pool

  • Crear el certificado de delegación

Si deseamos delegar en un determinado pool, necesitaremos conocer el identificador de dicho pool. Se trata de un valor público que contiene la información necesaria para asociar nuestros fondos al pool sin necesidad de conocer sus claves y, por lo tanto, sin comprometer la seguridad del mismo.

cardano-cli stake-address delegation-certificate \
    --stake-verification-key-file stake.vkey \
    --stake-pool-id <stake pool ID> \
    --out-file deleg.cert

Igual que antes, hay que remitir este nuevo certificado a la cadena de bloques mediante una transacción que, en este caso, no implica realizar ningún depósito más allá de la tarifa estándar. Los pasos serán los mismos que en la transacción anterior.

 

Publicado por David en Blog, Cardano, 0 comentarios