# Glosario

Lista de términos, conceptos y propuestas de mejora (CIPs) relacionados con Cardano. Actualizado al estado del ecosistema en 2026.

***

## A

### **ACTIVO DIGITAL**

Una colección de datos binarios autocontenida, identificable de forma única y con valor económico o funcional. En Cardano, los activos nativos coexisten con ADA en el mismo UTXO sin necesidad de contratos inteligentes para representarlos.

### **ADA**

La criptomoneda nativa de la blockchain de Cardano. Nombrada en honor a Ada Lovelace, matemática y escritora inglesa considerada la primera programadora de la historia.

1 ADA = 1.000.000 Lovelaces

### **AIKEN**

Lenguaje de programación moderno diseñado específicamente para escribir contratos inteligentes en Cardano. Es más accesible que Haskell/Plutus, con sintaxis similar a Rust, y ha ganado adopción masiva en el ecosistema desde 2023. IO está contribuyendo activamente a su desarrollo. Los contratos escritos en Aiken compilan a UPLC (Untyped Plutus Core), el mismo bytecode que Plutus.

### **ALONZO**

Hard fork de septiembre de 2021 que introdujo los contratos inteligentes (Plutus) en Cardano. Marcó el inicio real del ecosistema de dApps.

***

## B

### **BASHO**

La cuarta fase de desarrollo de Cardano, enfocada en escalabilidad y optimización del rendimiento. Incluye trabajos como Hydra, Mithril, UTxO-HD y Ouroboros Leios. Nombrada en honor a Matsuo Basho, el poeta japonés más famoso del período Edo.

### **BFT — Byzantine Fault Tolerance**

Tolerancia a Fallos Bizantinos. Propiedad de los sistemas distribuidos que les permite funcionar correctamente incluso cuando algunos nodos fallan o actúan de forma maliciosa. Cardano usó OBFT durante la transición de Byron a Shelley.

### **BIFURCACIÓN DURA (HARD FORK)**

Actualización de protocolo no retrocompatible que cambia las reglas fundamentales de la blockchain. En Cardano los hard forks se coordinan mediante el mecanismo HFC (Hard Fork Combinator), que permite transiciones suaves sin interrumpir la red. Requieren aprobación de DReps, SPOs y el Comité Constitucional.

### **BIFURCACIÓN SUAVE (SOFT FORK)**

Actualización retrocompatible del protocolo. Los nodos que no actualizan siguen siendo compatibles con los que sí lo hacen.

### **BLOQUE**

Contenedor de transacciones que se agrega a la blockchain tras ser validado por el líder de ranura designado. Cada bloque referencia el anterior formando la cadena.

### **BYRON**

La primera fase de Cardano (2017–2020), centrada en el lanzamiento de la red y la billetera Daedalus. Red centralizada bajo federación controlada por IOHK, Emurgo y la Cardano Foundation.

***

## C

### **CATALYST**

El programa de financiamiento descentralizado de Cardano. Permite a la comunidad proponer y votar proyectos que reciben financiamiento del tesoro. Funciona en rondas de votación y es uno de los experimentos de gobernanza más grandes de Web3. A partir de la era Conway, Catalyst está migrando hacia una gobernanza on-chain más directa.

### **CHANG**

Hard fork de agosto de 2024 que activó la era Conway en Cardano. Introdujo la infraestructura de gobernanza on-chain definida en CIP-1694: DReps, Comité Constitucional interino, y los primeros mecanismos de votación en mainnet.

### **CIP — Cardano Improvement Proposal**

Propuesta de Mejora de Cardano. Es el proceso formal por el cual la comunidad propone cambios técnicos, estándares o mejoras al ecosistema. Los CIPs son revisados por editores de la Cardano Foundation y se publican en el repositorio oficial. Cualquiera puede proponer un CIP.

**CIPs clave:**

| CIP      | Nombre                        | Estado    | Qué hace                                                                                                                                     |
| -------- | ----------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| CIP-0025 | Media Token Metadata Standard | Activo    | Estándar para adjuntar metadata a NFTs y tokens en el momento del minteo (on-chain via tx metadata)                                          |
| CIP-0030 | dApp-Wallet Web Bridge        | Activo    | API estándar que permite a los dApps comunicarse con wallets del navegador                                                                   |
| CIP-0067 | Asset Name Label Registry     | Activo    | Define cómo codificar el prefijo de label en el nombre de un asset (trabaja con CIP-0068)                                                    |
| CIP-0068 | Datum Metadata Standard       | Activo    | Mejora de CIP-0025 que guarda la metadata en datums on-chain, permitiendo actualizarla post-minteo                                           |
| CIP-0381 | Plutus Support for Pairings   | Activo    | Agrega operaciones de criptografía de curvas elípticas (BLS12-381) a Plutus, habilitando ZK proofs                                           |
| CIP-1694 | On-Chain Governance           | Activo    | El CIP más importante de la era Voltaire. Define DReps, Comité Constitucional, tipos de governance actions y el sistema de votación on-chain |
| CIP-0164 | Ouroboros Leios               | Propuesto | Define el protocolo de escalabilidad Layer 1 con Input Endorsers                                                                             |

### **COMITÉ CONSTITUCIONAL (CC)**

Uno de los tres pilares de gobernanza de Cardano (junto con DReps y SPOs). Es un grupo de 7 miembros elegidos por la comunidad que vela porque las governance actions sean constitucionales. Pueden vetar acciones que violen la Constitución de Cardano. Reemplazó al Comité Constitucional Interino (ICC) en 2026 tras las primeras elecciones comunitarias.

### **CONSTITUCIÓN DE CARDANO**

Documento fundamental que establece los principios y reglas de gobernanza de Cardano. Fue ratificada on-chain en 2026 con el 79% del stake activo de DReps votando a favor. Es el marco dentro del cual el Comité Constitucional evalúa las governance actions.

### **CONWAY**

La era actual de Cardano (desde el hard fork Chang, agosto 2024). Implementa la gobernanza on-chain completa definida en CIP-1694, incluyendo DReps, votación de SPOs, Comité Constitucional y governance actions.

### **CONSENSO**

El proceso por el cual los nodos de la red se ponen de acuerdo sobre el estado válido de la blockchain. Cardano usa Ouroboros Praos (y en el futuro Ouroboros Leios) para alcanzar consenso de forma segura y descentralizada.

### **COSTO POR ÉPOCA**

Tarifa fija en ADA que un pool cobra por época. Se deduce de las recompensas totales antes de calcular el margen. El mínimo del protocolo es 170 ADA. Nunca se descuenta de los wallets de los delegadores.

***

## D

### **DAEDALUS**

Billetera full-node de Cardano. Descarga y verifica toda la blockchain localmente. Soporta delegación de stake y gestión de activos nativos. Ideal para usuarios que priorizan la verificación completa sobre la conveniencia.

### **DAPP — Aplicación Descentralizada**

Aplicación que corre sobre una blockchain usando contratos inteligentes. En Cardano, las dApps interactúan con wallets del navegador mediante el estándar CIP-0030.

### **DELEGACIÓN**

El acto de asignar el poder de stake de tu ADA a un stake pool para participar en la producción de bloques y recibir recompensas. Delegar no implica ceder custodia: el ADA permanece en tu wallet en todo momento.

### **DESEMPEÑO (POOL)**

Porcentaje de ranuras asignadas que un pool convierte exitosamente en bloques. Un pool con 4 ranuras asignadas que produce 3 bloques tiene un desempeño del 75%.

### **DIRECCIÓN**

Estructura de datos que representa un destino o fuente en la blockchain. Contiene información sobre propiedad, tipo de red (mainnet/testnet) y preferencias de delegación. Las direcciones de Cardano comienzan con `addr1` en mainnet.

### **DREP — Delegated Representative**

Representante delegado, uno de los pilares del sistema de gobernanza CIP-1694. Los holders de ADA pueden delegar su poder de voto de gobernanza a un DRep (similar a delegar stake a un pool). Los DReps votan en governance actions on-chain. Cualquier persona puede registrarse como DRep.

***

## E

### **ÉPOCA**

Período de tiempo de aproximadamente 5 días (432.000 slots). Las recompensas se calculan y distribuyen por época. Los parámetros del protocolo cambian entre épocas.

***

## F

### **FEE — Tarifa de transacción**

Costo en ADA para procesar una transacción. En Cardano se calcula con una fórmula: `fee = a + b * size`, donde `a` y `b` son parámetros del protocolo. El fee va a los pools y al tesoro.

***

## G

### **GOVERNANCE ACTION**

Acción de gobernanza on-chain. Cualquier participante puede someter una governance action. Existen 7 tipos:

1. **Motion of No Confidence**: voto de no confianza en el Comité Constitucional
2. **Update Committee**: actualizar miembros del CC
3. **New Constitution**: proponer una nueva constitución
4. **Hard Fork Initiation**: iniciar un hard fork
5. **Protocol Parameter Change**: cambiar parámetros del protocolo
6. **Treasury Withdrawal**: retirar fondos del tesoro
7. **Info Action**: publicar información on-chain sin efecto de protocolo

Cada tipo requiere umbrales de aprobación distintos de DReps, SPOs y/o CC.

***

## H

### **HARD FORK COMBINATOR (HFC)**

Mecanismo técnico de Cardano que permite ejecutar hard forks sin interrumpir la red. Permite que el nodo soporte múltiples eras del protocolo simultáneamente, haciendo las transiciones transparentes para los operadores.

### **HYDRA**

Protocolo de escalabilidad Layer 2 de Cardano. Los participantes abren un "Head" donde pueden ejecutar miles de transacciones por segundo con finalidad casi instantánea y sin pagar fees por cada transacción interna. Al cerrar el Head, el estado final se liquida en Cardano L1. Los Heads son isomórficos: los contratos Plutus válidos en L1 son válidos en Hydra. Alcanzó v1.0.0 en 2025.

***

## I

### **INPUT ENDORSERS (OUROBOROS LEIOS)**

El próximo gran salto de escalabilidad Layer 1 de Cardano. Desacopla la producción de transacciones de la producción de bloques de consenso introduciendo tres tipos de bloques: Input Blocks (IBs), Endorser Blocks (EBs) y Ranking Blocks (RBs). Promete 30–65x más throughput que Praos. Definido en CIP-0164. En desarrollo activo como de 2026.

### **INTERSECT**

Organización sin fines de lucro creada en 2023 para ser el custodio del desarrollo del ecosistema Cardano. Coordina el proceso de gobernanza, administra el presupuesto del ecosistema aprobado on-chain, y facilita la colaboración entre IO, la Cardano Foundation, Emurgo y la comunidad. Reemplaza en parte el rol que antes tenían IOHK/IO de forma centralizada.

***

## K

### **KES — Key Evolving Signature**

Firma de Clave Evolutiva. Las claves KES de un stake pool cambian automáticamente cada 90 días por seguridad. Los operadores deben renovarlas periódicamente (antes del vencimiento) para que el pool pueda seguir produciendo bloques. Ver [Renovar KES keys](/mantenimiento-del-pool/renovar-kes).

***

### **L**

### **LEDGER**

Base de datos distribuida que registra todas las transacciones y el estado actual de la blockchain. En Cardano, el estado del ledger incluye todos los UTXOs existentes, los parámetros del protocolo, el estado de gobernanza y las recompensas pendientes.

### **LÍDER DE RANURA (SLOT LEADER)**

El stake pool seleccionado aleatoriamente para producir el bloque de una ranura determinada. La probabilidad de ser elegido es proporcional al stake del pool relativo al stake total de la red.

### **LOVELACE**

La unidad mínima de ADA. 1 ADA = 1.000.000 Lovelaces. Nombrada en honor a Ada Lovelace.

### **LSM — Log-Structured Merge Tree**

El backend de almacenamiento introducido en cardano-node 10.7 como parte de UTxO-HD. Almacena el estado del ledger en disco en lugar de RAM, reduciendo los requisitos de memoria de 24 GB a 8 GB. Es el modo recomendado para operadores a partir de la versión 10.7+.

***

## M

### **MARGEN DE GANANCIA**

Porcentaje de las recompensas totales que retiene el operador del pool, aplicado después de la tarifa fija y antes de distribuir al resto de los delegadores. Un pool con margen 0% devuelve el máximo posible a sus delegadores (pero igual cobra la tarifa fija).

### **MARLOWE**

Lenguaje de dominio específico (DSL) de Cardano para contratos inteligentes financieros. Está diseñado para ser usado por personas sin conocimientos de programación mediante una interfaz visual (Marlowe Playground). Los contratos Marlowe compilan a Plutus.

### **MIDNIGHT**

Blockchain independiente desarrollada por IOG que funciona como Partner Chain de Cardano. Está diseñada para uso empresarial con privacidad selectiva usando zero-knowledge proofs (ZK). Utiliza Cardano como capa de liquidación y sus contratos inteligentes usan TypeScript. Tiene su propio token ($NIGHT).

### **MITHRIL**

Protocolo de firmas multi-umbral basado en stake. Permite generar snapshots certificados del estado de la blockchain de Cardano que los clientes pueden verificar sin necesidad de descargar y re-ejecutar toda la historia de bloques. Usado principalmente para bootstrap rápido de nodos. Ver [Bootstrap con Mithril](/primeros-pasos/mithril).

### **MULTI-ASSET**

Característica introducida en el hard fork Mary (marzo 2021) que permite crear y transferir tokens nativos en Cardano, incluyendo NFTs, sin necesidad de contratos inteligentes. Los tokens nativos coexisten con ADA en los UTXOs.

***

## N

### **NCL — Net Change Limit**

Límite Neto de Cambio. Parámetro de gobernanza que establece la cantidad máxima de ADA que puede retirarse del tesoro en un período determinado. Debe ser aprobado on-chain antes de que puedan procesarse treasury withdrawals.

### **NFT — Token No Fungible**

Activo digital único en la blockchain. En Cardano los NFTs son tokens nativos con metadata adjunta (estándar CIP-0025 o CIP-0068). No requieren contratos inteligentes para existir, lo que los hace más eficientes que en otras blockchains.

### **NODO (NODE)**

Participante de la red de Cardano que mantiene una copia de la blockchain y participa en la validación de transacciones. Existen nodos relay (que retransmiten bloques) y nodos productores de bloques (que pertenecen a un stake pool registrado).

***

## O

### **OBFT — Ouroboros Byzantine Fault Tolerant**

Variante de Ouroboros usada durante la transición de Byron a Shelley. Incluía tolerancia a fallos bizantinos para garantizar la seguridad durante ese período de transición.

### **OUROBOROS**

La familia de protocolos de consenso Proof-of-Stake de Cardano, con seguridad demostrable matemáticamente. Las versiones principales son:

* **Ouroboros Classic**: primer protocolo PoS demostrable
* **Ouroboros Praos**: protocolo actual en producción, resistente a adversarios adaptativos
* **Ouroboros Genesis**: permite a nuevos nodos unirse sin un punto de confianza
* **Ouroboros Leios**: próxima versión con Input Endorsers para escalar el throughput 30–65x

***

## P

### **P2P — Peer-to-Peer**

Modo de red recomendado desde cardano-node 8.9+. En modo P2P, los nodos descubren y gestionan sus peers automáticamente sin necesidad de topologyUpdater ni configuración manual de peers. Se configura mediante el archivo de topology con `localRoots` y `publicRoots`.

### **PARTNER CHAINS**

Framework de IOG que permite crear blockchains independientes que se integran con Cardano como capa de liquidación y seguridad. Midnight es el ejemplo más prominente. El framework usa el stack tecnológico de Substrate (de Polkadot) combinado con las garantías de seguridad de Cardano.

### **PLEDGE**

La cantidad de ADA que el operador de un pool compromete con su propio pool. Un pledge más alto incrementa ligeramente las recompensas (vía el parámetro `a0` del protocolo). El pledge debe mantenerse activo — si el operador retira sus fondos por debajo del pledge declarado, el pool no produce bloques en esa época.

### **PLUTUS**

La plataforma de contratos inteligentes de Cardano. Los contratos Plutus se escriben en Haskell (o en Aiken, que compila a Plutus Core) y se ejecutan en la EUTxO VM. Las versiones son:

* **Plutus V1**: introducido en Alonzo
* **Plutus V2**: introducido en Vasil (2022), con acceso a más datos del contexto
* **Plutus V3**: introducido en Chang (2024), agrega primitivas criptográficas BLS12-381, nuevas operaciones de bitwise, y soporte para Voting/Governance

### **POOL DE STAKE (STAKE POOL)**

Nodo productor de bloques que agrega el stake de múltiples delegadores. Los pools compiten por ranuras proporcionalmente a su stake total. Operan con una clave caliente (KES) que se rota periódicamente y claves frías que se guardan off-line.

### **PROOF-OF-STAKE (PoS)**

Mecanismo de consenso donde el poder de validación es proporcional al stake (ADA bloqueado) en lugar de poder computacional (como en Bitcoin). Cardano fue el primer blockchain PoS con seguridad demostrable matemáticamente en producción.

***

## R

### **RANURA (SLOT)**

La unidad mínima de tiempo en Cardano: 1 segundo. 432.000 slots = 1 época (\~5 días). En cada slot puede producirse un bloque, aunque no todos los slots tienen un líder asignado.

### **RECOMPENSA**

ADA distribuida a pools y delegadores por participar en la producción de bloques. Las recompensas se calculan por época y se acumulan en la "reward account" del stake address. No se envían automáticamente al wallet — el usuario debe retirarlas con una transacción.

***

## S

### **SATURACIÓN**

El punto a partir del cual un pool tiene más stake del óptimo del protocolo (actualmente \~64M ADA para k=500). Por encima de la saturación, las recompensas por ADA delegada disminuyen, desincentivando la concentración en un solo pool.

### **SHELLEY**

La segunda era de Cardano (julio 2020). Marcó la descentralización de la red con la introducción de stake pools y delegación. Nombrada en honor a Percy Bysshe Shelley.

### **SPO — Stake Pool Operator**

Operador de stake pool. Persona o entidad responsable de mantener la infraestructura (nodos relay y productor) de un pool de Cardano. Los SPOs son uno de los tres pilares de gobernanza de CIP-1694.

***

## T

### **TESORO (TREASURY)**

Porción de las recompensas reservada para financiar el desarrollo futuro del ecosistema. Actualmente el 20% de las recompensas por época va al tesoro. Los fondos se liberan mediante governance actions de tipo Treasury Withdrawal, sujetas a aprobación de DReps, CC y el NCL vigente.

### **TOKEN FUNGIBLE**

Token donde cada unidad es intercambiable por otra del mismo tipo. El ADA es fungible. Los tokens de utilidad suelen ser fungibles.

### **TOKEN NO FUNGIBLE (NFT)**

Ver NFT.

### **TOKENIZACIÓN**

Representar activos del mundo real (bienes raíces, arte, bonos, etc.) como tokens en la blockchain. Cardano tiene infraestructura nativa para tokenización sin contratos inteligentes.

### **TOPOLOGY**

Archivo de configuración que define con qué peers se conecta un nodo de Cardano. En modo P2P moderno (recomendado), usa el formato:

```json
{
  "bootstrapPeers": [...],
  "localRoots": [
    {
      "accessPoints": [{"address": "ip-del-peer", "port": 3001}],
      "advertise": false,
      "valency": 1
    }
  ],
  "publicRoots": [...],
  "useLedgerAfterSlot": 128908821
}
```

El `topologyUpdater` ya no es necesario con P2P habilitado.

### **TPS — Transacciones Por Segundo**

Métrica de throughput de la blockchain. Actualmente Cardano procesa entre 5–10 TPS en condiciones normales, con capacidad de rafaga mayor. Con Ouroboros Leios se espera un salto de 30–65x.

***

## U

### **UTXO — Unspent Transaction Output**

Salida de transacción no gastada. El modelo de contabilidad de Cardano (y Bitcoin). En lugar de balances de cuenta, cada wallet posee UTXOs que son "consumidos" en nuevas transacciones. Esto facilita el procesamiento paralelo de transacciones.

### **EUTxO — Extended UTXO**

Extensión del modelo UTXO de Cardano que agrega datums y scripts a los UTXOs, permitiendo contratos inteligentes con estado. Es el modelo que habilita Plutus.

### **UTxO-HD**

Mejora del ledger de Cardano que separa el estado del UTxO set del resto del estado del ledger, permitiendo almacenarlo en disco (modo OnDisk/LSM) en lugar de RAM. Introducido en cardano-node 10.7. Reduce los requisitos de RAM de \~24 GB a \~8 GB con el backend LSM.

***

## V

### **VASIL**

Hard fork de septiembre de 2022. Introdujo Plutus V2 y mejoras de rendimiento significativas (diffusion pipelining, referencia a scripts, inline datums). Nombrado en honor a Vasil Dabov, miembro de la comunidad Cardano.

### **VOLTAIRE**

La quinta y actual fase de desarrollo de Cardano, enfocada en gobernanza descentralizada y sostenibilidad financiera del ecosistema. Voltaire es "ahora" — no es una promesa futura. La era Conway es su implementación técnica on-chain. Nombrada en honor al filósofo François-Marie Arouet (Voltaire).

### **VRF — Verifiable Random Function**

Función Aleatoria Verificable. Usada en Ouroboros para seleccionar líderes de ranura de forma aleatoria pero verificable. Cada pool usa su VRF key para demostrar que fue legítimamente seleccionado para producir un bloque.

***

## W

### **WALLET**

Software para gestionar claves privadas y interactuar con la blockchain. Las principales wallets de Cardano son Lace, Eternl, Yoroi, Nami, Flint y Daedalus (full-node). Todas implementan el estándar CIP-0030 para integración con dApps.

***

## Y

### **YOROI**

Billetera web ligera de Cardano desarrollada por Emurgo. Corre como extensión de Chrome/Firefox y como app móvil. No descarga la blockchain completa — conecta a un servidor backend (usando el protocolo Cardano Wallet).

***

## Z

### **ZERO-KNOWLEDGE PROOF (ZK)**

Técnica criptográfica que permite demostrar que se conoce un dato sin revelar el dato en sí. Cardano introdujo primitivas ZK (BLS12-381) en Plutus V3 via CIP-0381, habilitando casos de uso de privacidad y escalabilidad. Midnight, la Partner Chain de Cardano, está construida sobre ZK proofs.


# Consejos

Consejos de operación que aprendes con el tiempo y que nadie documenta en ningún lado.

## Sincronizar la base de datos entre nodos via rsync

Si tienes que levantar un nodo nuevo o restablecer uno dañado, puedes copiar la base de datos desde un nodo que ya está sincronizado en lugar de esperar días:

```bash
rsync -av --progress \
  --exclude 'socket' \
  tu_usuario@nodo-origen:/ruta/al/db/ \
  /ruta/local/db/
```

Detén el nodo destino antes de copiar. El nodo origen puede seguir corriendo — los archivos immutable son seguros de copiar en caliente.

***

## Sincronización rápida con Mithril

En lugar de sincronizar desde cero durante días, usa Mithril para descargar un snapshot certificado criptográficamente. Tiempo de sincronización: menos de una hora en la mayoría de las conexiones.

{% content-ref url="/pages/o0aYviFsObEfLdvShtxp" %}
[Bootstrap con Mithril](/primeros-pasos/mithril)
{% endcontent-ref %}

***

## Monitorear el vencimiento de KES

No esperes a que el nodo deje de producir bloques para darte cuenta de que las KES expiraron. Consulta el estado del certificado regularmente:

```bash
cardano-cli query kes-period-info \
  --mainnet \
  --op-cert-file $HOME/pool-keys/node.cert
```

La salida te indica cuántos períodos quedan. Pon un recordatorio cuando queden menos de 10 períodos (\~13 días).

***

## Ver logs en tiempo real

Para seguir lo que está haciendo un servicio en directo:

```bash
journalctl -fu NOMBRE-SERVICIO
```

Patrones útiles para filtrar:

```bash
# Solo errores
journalctl -fu BP | grep -i error

# Eventos de forja de bloques
journalctl -fu BP | grep -i "TraceForge"

# Estado de peers conectados
journalctl -fu RELAY | grep -i "AddedToCurrentChain"
```

***

## P2P simplifica la red

Con P2P activo ya no necesitas el script `topologyUpdater` ni llamadas periódicas a la API de IOHK para anunciar tu nodo. El descubrimiento de peers es automático gracias a `localRoots`, `publicRoots` y `bootstrapPeers` en el archivo de topología. Si todavía tienes ese cron job corriendo, puedes eliminarlo.

***

## Rollback tras un problema grave

Si el nodo queda en un estado inconsistente tras una actualización o un problema de hardware, detén el nodo, renombra la carpeta `db/` como backup, y vuelve a sincronizar:

```bash
sudo systemctl stop RELAY
mv $HOME/cardano/relay/db $HOME/cardano/relay/db.bak
sudo systemctl start RELAY
```

Si tienes Mithril disponible, úsalo para acelerar la resincronización. En versiones recientes de cardano-node, el proceso es considerablemente más rápido que hace unos años gracias a las mejoras en el ledger state.


# Preparando el servidor

Pasos previos para configurar tu pool de Cardano desde el código fuente. No usamos scripts tipo CNTools ni similares. Se asume Ubuntu 22.04 LTS (recomendado) o 24.04 LTS, y el usuario con el que traba

## Requisitos de hardware

Antes de empezar, asegurémonos de que el servidor cumple con lo mínimo necesario para correr un nodo de Cardano de forma estable:

| Componente     | Mínimo recomendado           |
| -------------- | ---------------------------- |
| CPU            | 2 núcleos (4 recomendado)    |
| RAM            | 16 GB (ver nota abajo)       |
| Almacenamiento | 300 GB SSD (NVMe preferible) |
| OS             | Ubuntu 22.04 LTS o 24.04 LTS |

{% hint style="info" %}
**Sobre la RAM según el modo UTxO-HD:**

* **OnDisk / LSM** (recomendado, modo por defecto desde cardano-node 10.7): con 8 GB puede funcionar, aunque 16 GB es más cómodo para tener margen.
* **InMemory**: necesitás al menos 24 GB. Este modo mantiene todo el estado en RAM y es considerablemente más exigente.

Si no sabés cuál vas a usar, quedáte con 16 GB como mínimo y usá el modo OnDisk — es el que recomendamos.
{% endhint %}

## Actualizar el sistema

Lo primero siempre es traer el sistema al día:

```bash
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get autoremove -y
```

{% hint style="info" %}
Si el servidor pide reiniciar después de las actualizaciones, hacelo antes de seguir. Es especialmente importante si se actualizó el kernel.
{% endhint %}

## Instalar dependencias

Instalamos todas las bibliotecas y herramientas que necesita cardano-node para compilar correctamente. A partir de la versión 11.x se agregan tres nuevas dependencias para el backend LSM: `liburing-dev`, `libsnappy-dev` y `protobuf-compiler`:

```bash
sudo apt-get install -y \
  automake build-essential pkg-config libffi-dev libgmp-dev libssl-dev \
  libncurses-dev libsystemd-dev zlib1g-dev make g++ tmux git jq wget \
  libtool autoconf liblmdb-dev libsnappy-dev protobuf-compiler liburing-dev \
  curl htop nano screen net-tools
```

## Configurar el firewall

Este paso es opcional pero muy recomendable. La idea es dejar pasar únicamente el tráfico que necesitamos y bloquear todo lo demás.

Tenemos dos opciones: `iptables` (más control, más verboso) o `ufw` (más simple, ideal si no tenés un esquema complejo).

### Opción A: UFW (más simple)

```bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp          # SSH
sudo ufw allow 3001/tcp        # cardano-node relay
sudo ufw allow from <ip_grafana> to any port 12798
sudo ufw allow from <ip_grafana> to any port 9001
sudo ufw enable
sudo ufw status verbose
```

### Opción B: iptables

```bash
sudo iptables -F

sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -p icmp -s <ip_otros_nodos> -j ACCEPT
sudo iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 3001 -j ACCEPT
sudo iptables -A INPUT -p tcp -m state --state NEW -m tcp -s <ip_grafana> --dport 12798 -j ACCEPT
sudo iptables -A INPUT -p tcp -m state --state NEW -m tcp -s <ip_grafana> --dport 9001 -j ACCEPT
sudo iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited

sudo /sbin/iptables-save
```

Para aplicar cambios de forma segura (se revierten solos en 60 segundos si algo sale mal), editá `/etc/iptables/rules.v4` directamente y luego:

```bash
sudo iptables-apply -t 60 /etc/iptables/rules.v4
```

{% hint style="danger" %}
**Importante antes de aplicar cualquier regla de firewall:**

Siempre verificá que el puerto SSH esté incluido en las reglas de entrada. Si lo bloqueás sin querer, perdés el acceso al servidor.

Además, SSH debería estar asegurado con llaves RSA, autenticación de doble factor, puerto personalizado o una combinación de estas. Un pool con SSH débil es un riesgo real para tu pledge.
{% endhint %}

## Ajustes adicionales recomendados

Vale la pena revisar estos puntos antes de seguir:

* **Swap**: si tu servidor tiene el mínimo de RAM, tener swap evita que el proceso muera en momentos de pico.
* **Swappiness**: reducirlo (por ejemplo a `10`) hace que el kernel prefiera RAM antes de recurrir al swap.
* **Cache Pressure**: ajustarlo a `50` o menos reduce la presión sobre la caché de inodos y directorios.

Podés guiarte con [este artículo de Digital Ocean](https://do.co/3j0CPSD) que lo explica paso a paso.


# Instalación y actualización

Cómo instalar o actualizar cardano-node 11.0.1 y cardano-cli compilando desde el código fuente. Usamos ghcup para gestionar el toolchain de Haskell.

## Antes de empezar

Existen tres formas de instalar cardano-node:

1. **Compilar desde el código fuente** (esta guía): más trabajo, pero control total sobre la versión y el entorno.
2. **Binarios pre-compilados**: descargá `cardano-node` y `cardano-cli` directamente desde los [releases en GitHub](https://github.com/IntersectMBO/cardano-node/releases). Más rápido si solo necesitás actualizar.
3. **Docker**: útil para entornos de prueba o si ya usás contenedores.

Las versiones que vamos a instalar en esta guía son:

| Componente   | Versión  |
| ------------ | -------- |
| GHC          | 9.6.7    |
| Cabal        | 3.12.1.0 |
| cardano-node | 11.0.1   |

***

## Crear el directorio para ejecutables

{% hint style="info" %}
Solo necesario en instalaciones nuevas.
{% endhint %}

```bash
mkdir -p ~/.local/bin
```

## Variables de entorno

Definimos las variables que necesita el nodo para funcionar correctamente. Abrimos `~/.bashrc` y agregamos al final:

{% hint style="info" %}
Reemplazá `TU_USUARIO` con tu nombre de usuario real. Podés verificarlo con `whoami`.

Solo necesario en instalaciones nuevas.
{% endhint %}

{% code title="\~/.bashrc" %}

```bash
# Cardano node
export PATH="/home/TU_USUARIO/.local/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH"
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"
export CARDANO_NODE_SOCKET_PATH=/home/TU_USUARIO/cardano-node/db/block/node.socket
```

{% endcode %}

Aplicamos los cambios a la sesión actual:

```bash
source ~/.bashrc
```

***

## Instalar ghcup

{% hint style="info" %}
Solo necesario en instalaciones nuevas.
{% endhint %}

`ghcup` es el gestor de toolchain de Haskell. Nos permite instalar y cambiar versiones de GHC y Cabal fácilmente sin ensuciar el sistema.

```bash
mkdir -p ~/src && cd ~/src
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
```

Durante la instalación:

* Presioná **ENTER** dos veces para aceptar.
* Cuando pregunte por el **HLS** (Haskell Language Server), podés responder **NO** — no lo necesitamos.
* Cuando pregunte si agrega `ghcup` al `$PATH` automáticamente, respondé **YES**.

***

## Instalar GHC

{% hint style="info" %}
Podés saltar este paso si `ghcup list` ya muestra GHC 9.6.7 instalado y activo.
{% endhint %}

```bash
source ~/.bashrc

ghcup upgrade
ghcup install ghc 9.6.7
ghcup set ghc 9.6.7
ghc --version
```

***

## Instalar Cabal

{% hint style="info" %}
Podés saltar este paso si `ghcup list` ya muestra Cabal 3.12.1.0 instalado y activo.
{% endhint %}

{% tabs %}
{% tab title="Nueva instalación" %}

```bash
ghcup install cabal 3.12.1.0
ghcup set cabal 3.12.1.0
cabal --version

cabal clean && cabal update
```

{% endtab %}

{% tab title="Actualización" %}

```bash
ghcup install cabal 3.12.1.0
ghcup set cabal 3.12.1.0
# Eliminamos la versión anterior (ajustá el número según lo que tengas)
ghcup rm cabal 3.10.3.0
cabal --version

cabal clean && cabal update
```

{% endtab %}
{% endtabs %}

***

## Instalar libsodium (fork IOHK)

Cardano usa un fork de `libsodium` mantenido por IOHK que incluye funciones criptográficas adicionales no presentes en la versión oficial.

{% hint style="info" %}
Solo necesario en instalaciones nuevas.
{% endhint %}

```bash
cd ~/src

git clone https://github.com/input-output-hk/libsodium
cd libsodium
git checkout dbb48cc
./autogen.sh
./configure
make
sudo make install
```

***

## Instalar libsecp256k1

{% hint style="info" %}
Solo necesario en instalaciones nuevas o si venís de una versión anterior a la 1.35.0.
{% endhint %}

```bash
cd ~/src
git clone https://github.com/bitcoin-core/secp256k1
cd secp256k1
git checkout ac83be33
./autogen.sh
./configure --prefix=/usr --enable-module-schnorrsig --enable-experimental
make
sudo make install
```

***

## Instalar blst

La versión correcta de `blst` la obtenemos dinámicamente desde el `flake.lock` de `iohk-nix`, que es la fuente de verdad para las dependencias del proyecto:

```bash
BLST_VERSION=$(curl -s https://raw.githubusercontent.com/input-output-hk/iohk-nix/master/flake.lock | jq -r '.nodes.blst.original.ref')
echo "Usando blst versión: ${BLST_VERSION}"
```

Una vez identificada la versión, la instalamos:

```bash
cd ~/src

: ${BLST_VERSION:='v0.3.11'}
git clone --depth 1 --branch ${BLST_VERSION} https://github.com/supranational/blst
cd blst
./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: ${BLST_VERSION#v}
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}}
```

***

## Clonar el repositorio de cardano-node

{% hint style="info" %}
Solo necesario en instalaciones nuevas.
{% endhint %}

```bash
cd ~
git clone https://github.com/IntersectMBO/cardano-node.git
```

***

## Backup de ejecutables (solo en actualizaciones)

{% hint style="warning" %}
Antes de sobreescribir los binarios actuales, guardamos una copia. Si algo falla, el rollback es inmediato.
{% endhint %}

```bash
cd ~/.local/bin
cp cardano-node cardano-node.10.x
cp cardano-cli cardano-cli.10.x
```

Ajustá el sufijo al número de versión que estás reemplazando.

***

## Compilar cardano-node 11.0.1

```bash
cd ~/cardano-node
git fetch --all --recurse-submodules --tags
git switch -d tags/11.0.1

echo "with-compiler: ghc-9.6.7" >> cabal.project.local

cabal update
cabal build exe:cardano-node cardano-cli
```

{% hint style="info" %}
Usamos `cabal build exe:cardano-node cardano-cli` en lugar de `cabal build all` porque compilar todo el repositorio incluye tests y herramientas auxiliares que no necesitamos, y lleva bastante más tiempo.

La compilación puede tomar entre 20 y 60 minutos dependiendo del hardware. Es normal.
{% endhint %}

***

## Copiar los ejecutables

Para actualizar puede que necesités detener el nodo primero:

```bash
sudo systemctl stop <NOMBRE-DEL-SERVICIO>
```

Copiamos los ejecutables recién compilados. Usamos `cabal list-bin` para encontrar la ruta exacta (el script `scripts/bin-path.sh` de versiones anteriores ya no existe):

```bash
cp -p "$(cabal list-bin cardano-node)" ~/.local/bin/
cp -p "$(cabal list-bin cardano-cli)" ~/.local/bin/

# Opcional: si también querés el submit-api
cp -p "$(cabal list-bin cardano-submit-api)" ~/.local/bin/
```

Verificamos la instalación:

```bash
cardano-node --version
cardano-cli --version
```

***

## Reiniciar el nodo

```bash
sudo systemctl restart <NOMBRE-DEL-SERVICIO>
```

Revisamos los logs para confirmar que arrancó correctamente:

```bash
journalctl -fu <NOMBRE-DEL-SERVICIO>
```

{% hint style="info" %}
**Primera arrancada después de una actualización mayor:**

Es normal que cardano-node elimine y reconstruya los snapshots del ledger en `db/ledger/` al iniciar por primera vez tras un update. No es un error — es parte de la migración del estado entre versiones. El nodo puede tardar más de lo habitual en sincronizarse durante este proceso.
{% endhint %}


# Bootstrap con Mithril

Cómo sincronizar un nodo de Cardano en minutos usando Mithril en lugar de esperar días a que sincronice desde el génesis.

## ¿Qué es Mithril?

Mithril es un protocolo de firmas multi-umbral basado en stake que permite generar y verificar snapshots certificados del estado de la blockchain de Cardano. En términos prácticos: en lugar de esperar días a que tu nodo sincronice desde el génesis, podés descargar un snapshot firmado criptográficamente y tener el nodo listo en menos de 20 minutos.

El snapshot es certificado por los stake pools participantes — no confiás ciegamente en un servidor central, el protocolo garantiza la integridad del estado.

{% hint style="info" %}
Mithril es especialmente útil cuando levantás un nodo nuevo, después de una reinstalación, o cuando necesitás recuperar un nodo rápidamente tras un problema grave.
{% endhint %}

***

## Descargar el cliente Mithril

El cliente de Mithril es un binario estático. Lo descargamos desde los releases oficiales:

```bash
# Verificamos la arquitectura del sistema
uname -m

# Descargamos el binario (ajustá la versión y arquitectura según corresponda)
MITHRIL_VERSION="latest"
curl -sSL https://github.com/input-output-hk/mithril/releases/latest/download/mithril-client-cli-x86_64-unknown-linux-gnu.tar.gz \
  | tar -xz -C ~/.local/bin/

# Verificamos
mithril-client --version
```

{% hint style="info" %}
Para arquitecturas ARM (por ejemplo Raspberry Pi o servidores ARM en la nube), el binario se llama `mithril-client-cli-aarch64-unknown-linux-gnu.tar.gz`.
{% endhint %}

***

## Configurar las variables de entorno

Necesitamos apuntar el cliente al agregador de mainnet y proveer la clave de verificación del génesis de Mithril. Estas variables se pueden definir en la sesión actual o agregarse al `~/.bashrc`:

```bash
# Agregador de mainnet
export AGGREGATOR_ENDPOINT="https://aggregator.release-mainnet.api.mithril.network/aggregator"

# Clave de verificación del génesis (la obtenemos directamente del repo oficial)
export GENESIS_VERIFICATION_KEY=$(curl -sS https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/release-mainnet/genesis.vkey)
```

{% hint style="info" %}
Para **preprod** o **preview**, los endpoints son:

* Preprod: `https://aggregator.release-preprod.api.mithril.network/aggregator`
* Preview: `https://aggregator.pre-release-preview.api.mithril.network/aggregator`

Y las claves de verificación están en la misma ruta del repo, en las carpetas `release-preprod` y `pre-release-preview` respectivamente.
{% endhint %}

***

## Detener el nodo

Antes de restaurar la base de datos, el nodo debe estar detenido:

```bash
sudo systemctl stop <NOMBRE-DEL-SERVICIO>
```

***

## Hacer backup de la base de datos actual (opcional)

Si tenés datos que querés conservar o simplemente ser precavido:

```bash
mv ~/cardano-node/db ~/cardano-node/db.bak
```

De lo contrario, borramos directamente:

```bash
rm -rf ~/cardano-node/db
```

***

## Descargar y restaurar el snapshot

Usamos el flag `--include-ancillary` para incluir el último estado del ledger y el último archivo immutable, lo que acelera significativamente el tiempo de arranque del nodo:

```bash
mithril-client cardano-database download latest \
  --include-ancillary \
  --db-directory ~/cardano-node/db
```

{% hint style="info" %}
La opción `--include-ancillary` descarga el snapshot del ledger state además de los archivos immutable. Sin esta opción el nodo tendría que reconstruir el ledger desde los bloques al arrancar, lo que puede tomar horas adicionales.

Si el comando te pide una clave de verificación adicional (`ANCILLARY_VERIFICATION_KEY`), podés obtenerla del mismo repositorio de configuración de Mithril.
{% endhint %}

La descarga puede tardar entre 10 y 30 minutos dependiendo de tu conexión. Una vez completada, el cliente verifica la integridad criptográfica del snapshot automáticamente.

***

## Reiniciar el nodo

```bash
sudo systemctl start <NOMBRE-DEL-SERVICIO>
```

Revisamos los logs para confirmar que está sincronizando correctamente:

```bash
journalctl -fu <NOMBRE-DEL-SERVICIO>
```

Deberías ver que el nodo arranca y se pone al día con los últimos bloques en cuestión de minutos en lugar de días.

***

## Verificar snapshots disponibles

Si querés ver los snapshots disponibles antes de descargar, o verificar qué se está ofreciendo en el agregador:

```bash
# Listar snapshots disponibles
mithril-client cardano-database list

# Ver detalles de un snapshot específico
mithril-client cardano-database show <DIGEST>
```


# Configuración de un nodo

Archivos de configuración, topología P2P y parámetros clave para relay y block producer en mainnet. Cardano-node 11.x / Conway era.

Vamos a preparar los archivos de configuración que necesita cada nodo para arrancar y conectarse a la red principal de Cardano. Tenemos dos tipos de nodo: el **relay** (expuesto a internet) y el **block producer** (aislado, solo habla con tus relays).

***

## Estructura de directorios

Antes de descargar nada, creamos la estructura base:

```bash
mkdir -p $HOME/cardano/relay/config
mkdir -p $HOME/cardano/bp/config
mkdir -p $HOME/cardano/relay/db
mkdir -p $HOME/cardano/bp/db
```

{% hint style="info" %}
Usamos `$HOME` para evitar rutas hardcodeadas. Si prefieres una ubicación distinta (por ejemplo `/opt/cardano`), simplemente reemplaza `$HOME/cardano` en todos los comandos.
{% endhint %}

***

## Descargar los archivos de configuración

Los archivos oficiales de mainnet están en:

**`https://book.world.dev.cardano.org/environments/mainnet/`**

Descargamos cada archivo explícitamente:

```bash
cd $HOME/cardano/relay/config

wget https://book.world.dev.cardano.org/environments/mainnet/config.json
wget https://book.world.dev.cardano.org/environments/mainnet/byron-genesis.json
wget https://book.world.dev.cardano.org/environments/mainnet/shelley-genesis.json
wget https://book.world.dev.cardano.org/environments/mainnet/alonzo-genesis.json
wget https://book.world.dev.cardano.org/environments/mainnet/conway-genesis.json
wget https://book.world.dev.cardano.org/environments/mainnet/topology.json
```

{% hint style="warning" %}
Necesitamos los seis archivos. Desde el hard fork Chang, `conway-genesis.json` es obligatorio — el nodo no arranca sin él.
{% endhint %}

Luego copiamos los mismos archivos de génesis al BP (la topología será diferente):

```bash
cp $HOME/cardano/relay/config/*.json $HOME/cardano/bp/config/
```

***

## Archivos de génesis

No necesitamos modificar estos archivos. Son parámetros de red firmados y el nodo los verifica al arrancar:

| Archivo                | Qué contiene                                              |
| ---------------------- | --------------------------------------------------------- |
| `byron-genesis.json`   | Parámetros de la era Byron                                |
| `shelley-genesis.json` | Parámetros de Shelley (epoch length, slot duration, etc.) |
| `alonzo-genesis.json`  | Parámetros de smart contracts (Plutus)                    |
| `conway-genesis.json`  | Parámetros de gobernanza (Chang/Conway era)               |

***

## config.json — qué necesitamos cambiar

El archivo descargado tiene más de 100 campos. No lo reemplazamos entero — abrimos el que descargamos y tocamos los campos que nos interesan:

```bash
nano $HOME/cardano/relay/config/config.json
```

### Campos clave a revisar y ajustar

**P2P habilitado (obligatorio):**

```json
"EnableP2P": true
```

**Puerto de Prometheus** (métricas para Grafana):

```json
"hasPrometheus": ["127.0.0.1", 12798]
```

**Puerto EKG** (panel interno, útil para debug):

```json
"hasEKG": 12789
```

**Nivel mínimo de logs** — `Info` es suficiente en producción:

```json
"minSeverity": "Info"
```

**Rotación de logs:**

```json
"rotation": {
  "rpLogLimitBytes": 5000000,
  "rpMaxAgeHours": 24,
  "rpKeepFilesNum": 10
}
```

{% hint style="info" %}
Para el BP, podemos usar el mismo `config.json` del relay. La diferencia real está en la topología, no en la configuración del nodo.
{% endhint %}

***

## Topología

Aquí es donde relay y BP tienen configuraciones completamente distintas.

### Relay — P2P (formato actual)

El formato antiguo con `"Producers"` es legacy. Con P2P activo en mainnet, necesitamos el formato con `localRoots`, `publicRoots` y `bootstrapPeers`.

```bash
nano $HOME/cardano/relay/config/topology.json
```

{% tabs %}
{% tab title="RELAY — P2P" %}

```json
{
  "bootstrapPeers": [
    {"address": "backbone.cardano.iog.io", "port": 3501},
    {"address": "backbone.mainnet.emurgornd.com", "port": 3717}
  ],
  "localRoots": [
    {
      "accessPoints": [
        {"address": "IP-DE-TU-BP", "port": 3000}
      ],
      "advertise": false,
      "valency": 1
    }
  ],
  "publicRoots": [
    {
      "accessPoints": [
        {"address": "backbone.cardano.iog.io", "port": 3501}
      ],
      "advertise": false
    }
  ],
  "useLedgerAfterSlot": 128908821
}
```

{% endtab %}
{% endtabs %}

**Qué significa cada sección:**

* **`bootstrapPeers`** — peers confiables para el arranque inicial, antes de tener el ledger sincronizado.
* **`localRoots`** — peers que siempre queremos mantener conectados (nuestro BP). `advertise: false` significa que no anunciamos esta dirección a la red.
* **`publicRoots`** — peers públicos para descubrimiento.
* **`useLedgerAfterSlot`** — a partir de este slot, el nodo usa el ledger para descubrir peers. Dejamos el valor por defecto.

Reemplaza `IP-DE-TU-BP` con la IP privada de tu block producer.

{% hint style="warning" %}
Si tienes varios relays, añade cada uno en `localRoots` del otro relay con `advertise: true` para que tu pool sea descubrible en la red.
{% endhint %}

***

### Block Producer — topología simple

El BP solo necesita conectarse a sus propios relays. Sin peers públicos, sin bootstrapPeers:

{% tabs %}
{% tab title="BP — Topología" %}

```json
{
  "localRoots": [
    {
      "accessPoints": [
        {"address": "IP-DE-TU-RELAY-1", "port": 3000}
      ],
      "advertise": false,
      "valency": 1
    }
  ],
  "publicRoots": [],
  "useLedgerAfterSlot": -1
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
**El BP no debe tener conexión directa a internet ni a peers públicos.** Solo debe hablar con tus propios relays. Si tu BP es accesible desde fuera, estás exponiendo las claves operacionales.
{% endhint %}

***

## Sincronización inicial — usa Mithril

Sincronizar el nodo desde cero puede llevar varios días. En lugar de esperar, vamos a usar Mithril para descargar un snapshot verificado criptográficamente.

{% content-ref url="/pages/o0aYviFsObEfLdvShtxp" %}
[Bootstrap con Mithril](/primeros-pasos/mithril)
{% endcontent-ref %}

{% hint style="info" %}
Mithril es el método recomendado para la sincronización inicial. Reduce el tiempo de espera de días a menos de una hora.
{% endhint %}

***

## Verificar los archivos

Antes de continuar, confirmamos que tenemos todo lo necesario:

```bash
ls $HOME/cardano/relay/config/
# config.json  byron-genesis.json  shelley-genesis.json
# alonzo-genesis.json  conway-genesis.json  topology.json

ls $HOME/cardano/bp/config/
# config.json  byron-genesis.json  shelley-genesis.json
# alonzo-genesis.json  conway-genesis.json  topology.json
```

Con los archivos en su lugar, el siguiente paso es configurar los servicios de systemd.


# Ejecutar como un servicio

Configurar cardano-node como servicio de systemd en relay y block producer. Variables de entorno, logs con journalctl y comandos de gestión habituales.

Vamos a configurar los nodos como servicios de systemd. Así se inician automáticamente al arrancar el servidor y los gestionamos con `systemctl` como cualquier otro servicio del sistema.

***

## Variables de entorno

Cada nodo necesita saber dónde están sus archivos y qué puertos usar. En lugar de meter todo en el archivo de servicio, usamos archivos de entorno separados — es más limpio y fácil de cambiar sin tocar el servicio.

{% hint style="info" %}
En los ejemplos usamos `TU_USUARIO` como placeholder. Reemplázalo con tu nombre de usuario real (puedes verificarlo con `whoami`).
{% endhint %}

### Crear el directorio de configuración

```bash
sudo mkdir -p /etc/cardano
```

### Archivo de entorno — Relay

```bash
sudo nano /etc/cardano/relay.env
```

```bash
CARDANO_NODE_SOCKET_PATH=/home/TU_USUARIO/cardano/relay/db/node.socket
CONFIG=/home/TU_USUARIO/cardano/relay/config/config.json
TOPOLOGY=/home/TU_USUARIO/cardano/relay/config/topology.json
DB_PATH=/home/TU_USUARIO/cardano/relay/db
HOST_ADDR=0.0.0.0
PORT=3000
```

### Archivo de entorno — Block Producer

```bash
sudo nano /etc/cardano/bp.env
```

```bash
CARDANO_NODE_SOCKET_PATH=/home/TU_USUARIO/cardano/bp/db/node.socket
CONFIG=/home/TU_USUARIO/cardano/bp/config/config.json
TOPOLOGY=/home/TU_USUARIO/cardano/bp/config/topology.json
DB_PATH=/home/TU_USUARIO/cardano/bp/db
HOST_ADDR=0.0.0.0
PORT=3000
KES_KEY=/home/TU_USUARIO/cardano/bp/keys/kes.skey
VRF_KEY=/home/TU_USUARIO/cardano/bp/keys/vrf.skey
CERT=/home/TU_USUARIO/cardano/bp/keys/node.cert
```

***

## Servicio systemd — Relay

```bash
sudo nano /etc/systemd/system/RELAY.service
```

```ini
[Unit]
Description=Cardano Relay Node
After=network.target

[Service]
Type=simple
User=TU_USUARIO
EnvironmentFile=/etc/cardano/relay.env
ExecStart=/usr/local/bin/cardano-node run \
  --config $CONFIG \
  --topology $TOPOLOGY \
  --database-path $DB_PATH \
  --socket-path $CARDANO_NODE_SOCKET_PATH \
  --host-addr $HOST_ADDR \
  --port $PORT \
  +RTS -N -RTS
KillSignal=SIGINT
RestartKillSignal=SIGINT
StandardOutput=journal
StandardError=journal
SyslogIdentifier=RELAY
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

{% hint style="info" %}
`+RTS -N -RTS` le dice al runtime de Haskell que use todos los cores disponibles. En servidores dedicados está bien dejarlo así. Si el servidor comparte carga con otros procesos, puedes limitarlo con `-N2` o `-N4`.
{% endhint %}

***

## Servicio systemd — Block Producer

Arranca primero con la variante sin claves para verificar que el nodo sincroniza y conecta bien con los relays. Solo después activamos la forja de bloques.

```bash
sudo nano /etc/systemd/system/BP.service
```

{% tabs %}
{% tab title="BP — Con claves (producción)" %}

```ini
[Unit]
Description=Cardano Block Producer
After=network.target

[Service]
Type=simple
User=TU_USUARIO
EnvironmentFile=/etc/cardano/bp.env
ExecStart=/usr/local/bin/cardano-node run \
  --config $CONFIG \
  --topology $TOPOLOGY \
  --database-path $DB_PATH \
  --socket-path $CARDANO_NODE_SOCKET_PATH \
  --host-addr $HOST_ADDR \
  --port $PORT \
  --shelley-kes-key $KES_KEY \
  --shelley-vrf-key $VRF_KEY \
  --shelley-operational-certificate $CERT \
  +RTS -N -RTS
KillSignal=SIGINT
RestartKillSignal=SIGINT
StandardOutput=journal
StandardError=journal
SyslogIdentifier=BP
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

{% endtab %}

{% tab title="BP — Sin claves (verificación inicial)" %}

```ini
[Unit]
Description=Cardano Block Producer (sin claves)
After=network.target

[Service]
Type=simple
User=TU_USUARIO
EnvironmentFile=/etc/cardano/bp.env
ExecStart=/usr/local/bin/cardano-node run \
  --config $CONFIG \
  --topology $TOPOLOGY \
  --database-path $DB_PATH \
  --socket-path $CARDANO_NODE_SOCKET_PATH \
  --host-addr $HOST_ADDR \
  --port $PORT \
  +RTS -N -RTS
KillSignal=SIGINT
RestartKillSignal=SIGINT
StandardOutput=journal
StandardError=journal
SyslogIdentifier=BP
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Arranca primero con la variante sin claves. Confirma que el nodo sincroniza y que los peers del relay aparecen conectados. Solo entonces pasamos a la versión con claves.
{% endhint %}

***

## Activar y arrancar los servicios

Cada vez que creamos o modificamos un archivo `.service`, recargamos systemd:

```bash
sudo systemctl daemon-reload
```

Habilitamos el arranque automático y levantamos los servicios:

```bash
# Relay
sudo systemctl enable RELAY
sudo systemctl start RELAY

# Block Producer
sudo systemctl enable BP
sudo systemctl start BP
```

{% hint style="info" %}
`enable` hace que el servicio arranque al iniciar el servidor. `start` lo levanta ahora mismo sin necesidad de reiniciar.
{% endhint %}

***

## Ver los logs

Para seguir los logs en tiempo real usamos `journalctl`:

```bash
# Relay — logs en tiempo real
journalctl -fu RELAY

# Block Producer — logs en tiempo real
journalctl -fu BP
```

Últimas 100 líneas sin seguimiento continuo:

```bash
journalctl -u RELAY -n 100
```

Filtrar por fecha o errores:

```bash
journalctl -u RELAY --since "2024-01-15 10:00:00"
journalctl -u RELAY -p err
```

***

## Comandos de gestión habituales

```bash
# Estado del servicio
sudo systemctl status RELAY
sudo systemctl status BP

# Reiniciar (por ejemplo, tras cambiar la topología)
sudo systemctl restart RELAY

# Parar
sudo systemctl stop RELAY

# Recargar configuración de systemd tras modificar el .service
sudo systemctl daemon-reload
```

{% hint style="danger" %}
Antes de parar el BP para mantenimiento, confirma que el relay sigue activo y conectado. Si paras ambos a la vez, tu pool deja de ser visible en la red.
{% endhint %}

***

## Verificar que el socket existe

Una vez arrancado el nodo, verificamos que está funcionando:

```bash
ls -la $HOME/cardano/relay/db/node.socket

export CARDANO_NODE_SOCKET_PATH=$HOME/cardano/relay/db/node.socket
cardano-cli query tip --mainnet
```

Si `cardano-cli query tip` devuelve el slot actual de la cadena, el nodo está sincronizando correctamente.


# Keys y certificado del pool

Generar las claves frías, KES y VRF de un stake pool, y emitir el certificado operacional. Incluye cálculo del período KES actual y rotación de claves.

Las claves son el corazón de tu pool. Si las pierdes o las expones, pierdes el control del pool. Tómate este paso con calma.

{% hint style="danger" %}
**Máquina air-gapped obligatoria.** Las cold keys nunca deben tocar una máquina conectada a internet. Genera las cold keys y el contador de operaciones en una máquina completamente offline y mantenlas ahí permanentemente. Solo las sacas para firmar un nuevo certificado operacional, y vuelven offline de inmediato.
{% endhint %}

## Qué claves necesitas

| Clave                            | Dónde vive    | Para qué sirve                        |
| -------------------------------- | ------------- | ------------------------------------- |
| Cold key (node.skey / node.vkey) | Air-gapped    | Firma certificados operacionales      |
| KES key (kes.skey / kes.vkey)    | Nodo caliente | Firma bloques (caduca cada \~62 días) |
| VRF key (vrf.skey / vrf.vkey)    | Nodo caliente | Prueba de elección de slot            |
| Op-cert (node.cert)              | Nodo caliente | Vincula KES con cold key              |
| Counter (cold.counter)           | Air-gapped    | Evita replay attacks en op-certs      |

***

## 1. Generar las cold keys

En la máquina **air-gapped**:

```bash
cardano-cli node key-gen \
  --cold-verification-key-file $HOME/cold-keys/node.vkey \
  --cold-signing-key-file      $HOME/cold-keys/node.skey \
  --operational-certificate-issue-counter-file $HOME/cold-keys/cold.counter
```

Protege los archivos en cuanto los generes:

```bash
chmod 400 $HOME/cold-keys/node.skey
chmod 400 $HOME/cold-keys/cold.counter
```

{% hint style="warning" %}
El archivo `cold.counter` es tan crítico como la propia cold key. Cada vez que emites un op-cert, el contador se incrementa. Si emites un certificado con un contador inferior al actual en la cadena, el nodo queda invalidado. Guárdalo junto a las cold keys, siempre offline.
{% endhint %}

***

## 2. Generar las claves VRF

En la máquina **air-gapped**:

```bash
cardano-cli node key-gen-VRF \
  --verification-key-file $HOME/pool-keys/vrf.vkey \
  --signing-key-file      $HOME/pool-keys/vrf.skey
```

```bash
chmod 400 $HOME/pool-keys/vrf.skey
```

***

## 3. Generar las claves KES

En el **nodo caliente**:

```bash
cardano-cli node key-gen-KES \
  --verification-key-file $HOME/pool-keys/kes.vkey \
  --signing-key-file      $HOME/pool-keys/kes.skey
```

```bash
chmod 400 $HOME/pool-keys/kes.skey
```

Las claves KES caducan por diseño: cada período KES dura un número fijo de slots. Cuando caducan, el nodo deja de forjar bloques hasta que emites un nuevo op-cert.

***

## 4. Calcular el período KES actual

Necesitas saber en qué período KES estás para emitir el certificado correctamente. En el nodo caliente:

```bash
expr $(cardano-cli query tip --mainnet | jq .slot) / $(cat $HOME/cardano/relay/config/shelley-genesis.json | jq .slotsPerKESPeriod)
```

{% hint style="info" %}
El campo correcto es `.slot`, no `.slotNo`. El formato de salida del CLI cambió en versiones recientes y `.slotNo` ya no existe.
{% endhint %}

El resultado es un número entero, por ejemplo `4385`. Ese es el `--kes-period` que usarás en el siguiente paso.

***

## 5. Emitir el certificado operacional

Este paso requiere juntar el `kes.vkey` (del nodo caliente) con el `cold.counter` y `node.skey` (del air-gapped) en el mismo lugar — idealmente el air-gapped con el `kes.vkey` copiado temporalmente.

En la máquina **air-gapped**:

```bash
cardano-cli node issue-op-cert \
  --kes-verification-key-file      $HOME/pool-keys/kes.vkey \
  --cold-signing-key-file          $HOME/cold-keys/node.skey \
  --operational-certificate-issue-counter-file $HOME/cold-keys/cold.counter \
  --kes-period                     <KES_PERIOD_ACTUAL> \
  --out-file                       $HOME/pool-keys/node.cert
```

Sustituye `<KES_PERIOD_ACTUAL>` por el número que calculaste antes.

Después de firmar:

* El `cold.counter` se incrementa automáticamente — no lo toques manualmente.
* Copia el `node.cert` resultante al nodo caliente.
* Las cold keys y el counter vuelven offline de inmediato.

```bash
chmod 400 $HOME/pool-keys/node.cert
```

***

## 6. Configurar el nodo para usar las claves

En el archivo de servicio del BP, referencia las tres claves calientes:

```bash
cardano-node run \
  ...
  --shelley-kes-key          $HOME/pool-keys/kes.skey \
  --shelley-vrf-key          $HOME/pool-keys/vrf.skey \
  --shelley-operational-certificate $HOME/pool-keys/node.cert
```

***

## Cuándo renovar el op-cert

Cardano mainnet tiene `slotsPerKESPeriod = 129600` y `maxKESEvolutions = 62`. Un op-cert dura aproximadamente **62 días**. Cuando el período KES del certificado supera el máximo, el nodo para de forjar.

Puedes verificar cuánto tiempo te queda en cualquier momento:

```bash
cardano-cli query kes-period-info \
  --mainnet \
  --op-cert-file $HOME/pool-keys/node.cert
```

Proceso de renovación:

1. Genera nuevas claves KES en el nodo caliente.
2. Calcula el período KES actual.
3. Lleva el `kes.vkey` al air-gapped.
4. Emite nuevo op-cert con `node issue-op-cert`.
5. Copia el nuevo `node.cert` al nodo caliente y reinicia el nodo.

{% hint style="warning" %}
Nunca reutilices un par de claves KES para emitir un segundo op-cert. Genera claves KES nuevas cada vez que renuevas el certificado.
{% endhint %}

***

## Resumen de permisos

```bash
chmod 400 $HOME/cold-keys/node.skey
chmod 400 $HOME/cold-keys/cold.counter
chmod 400 $HOME/pool-keys/vrf.skey
chmod 400 $HOME/pool-keys/kes.skey
chmod 400 $HOME/pool-keys/node.cert
```

Los `.skey` y el counter son siempre 400, sin excepciones.


# Direcciones de payment y stake

Generar claves de pago y stake, construir las direcciones correspondientes, y registrar la stake address en mainnet. Conway era / cardano-cli 10+.

Antes de registrar el pool necesitas dos cosas: una dirección de pago para cubrir las transacciones y depósitos, y una dirección de stake que vincularás al pool como pledge.

***

## 1. Generar las claves de pago

```bash
cardano-cli address key-gen \
  --verification-key-file $HOME/keys/payment.vkey \
  --signing-key-file      $HOME/keys/payment.skey
```

```bash
chmod 400 $HOME/keys/payment.skey
```

***

## 2. Generar las claves de stake

```bash
cardano-cli stake-address key-gen \
  --verification-key-file $HOME/keys/stake.vkey \
  --signing-key-file      $HOME/keys/stake.skey
```

```bash
chmod 400 $HOME/keys/stake.skey
```

***

## 3. Construir las direcciones

### Dirección de pago (con staking vinculado)

```bash
cardano-cli address build \
  --payment-verification-key-file $HOME/keys/payment.vkey \
  --stake-verification-key-file   $HOME/keys/stake.vkey \
  --mainnet \
  --out-file $HOME/keys/payment.addr
```

### Dirección de stake

```bash
cardano-cli stake-address build \
  --stake-verification-key-file $HOME/keys/stake.vkey \
  --mainnet \
  --out-file $HOME/keys/stake.addr
```

Guarda los valores:

```bash
cat $HOME/keys/payment.addr
# addr1qx...

cat $HOME/keys/stake.addr
# stake1u...
```

***

## 4. Crear el certificado de registro de stake

```bash
cardano-cli stake-address registration-certificate \
  --stake-verification-key-file $HOME/keys/stake.vkey \
  --key-reg-deposit-amt 2000000 \
  --out-file $HOME/tx/stake.cert
```

{% hint style="info" %}
**Era Conway (cardano-cli 10+):** el flag `--key-reg-deposit-amt` es obligatorio. El depósito es **2 ADA (2 000 000 lovelace)** y se recupera si cancelas el registro de stake en el futuro.
{% endhint %}

***

## 5. Fondear la dirección de pago

Transfiere ADA a la dirección `payment.addr` antes de continuar. Necesitas fondos suficientes para:

* Depósito de registro de stake: 2 ADA
* Depósito de registro del pool: 500 ADA
* Fees de transacciones: \~2–3 ADA en total
* Pledge (lo que hayas decidido comprometer)

{% hint style="warning" %}
**Mínimo operativo recomendado: 504 ADA** en la dirección de pago antes de proceder con el registro del pool.
{% endhint %}

Una vez transferido, consulta el UTxO para verificar:

```bash
cardano-cli query utxo \
  --address $(cat $HOME/keys/payment.addr) \
  --mainnet
```

La salida tendrá este aspecto:

```
                           TxHash                                 TxIx        Amount
--------------------------------------------------------------------------------------
441c5b06...22ee0065     0        49992783811 lovelace + TxOutDatumNone
```

Anota el `TxHash` y el `TxIx` — los necesitarás para construir la transacción.

***

## 6. Registrar la dirección de stake

### Consultar los parámetros del protocolo

```bash
cardano-cli query protocol-parameters \
  --mainnet \
  --out-file $HOME/tx/protocol.json
```

### Construir la transacción

```bash
cardano-cli transaction build-raw \
  --tx-in <TXHASH>#<TXIX> \
  --tx-out $(cat $HOME/keys/payment.addr)+<CAMBIO> \
  --ttl <SLOT_LIMITE> \
  --fee <FEE> \
  --certificate-file $HOME/tx/stake.cert \
  --out-file $HOME/tx/tx.raw
```

{% hint style="info" %}
**¿Por qué `build-raw` y no `build`?** El comando `cardano-cli transaction build` auto-balancea la transacción y es más cómodo, pero requiere un nodo sincronizado accesible. `build-raw` es más explícito y te obliga a entender exactamente qué estás firmando. Ambos son válidos.
{% endhint %}

### Calcular el fee

```bash
cardano-cli transaction calculate-min-fee \
  --tx-body-file      $HOME/tx/tx.raw \
  --tx-in-count       1 \
  --tx-out-count      1 \
  --witness-count     2 \
  --mainnet \
  --protocol-params-file $HOME/tx/protocol.json
```

Reconstruye la transacción con el fee real y el cambio correcto:

```
CAMBIO = UTXO_LOVELACE - 2000000 (depósito) - FEE
```

### Firmar

```bash
cardano-cli transaction sign \
  --tx-body-file      $HOME/tx/tx.raw \
  --signing-key-file  $HOME/keys/payment.skey \
  --signing-key-file  $HOME/keys/stake.skey \
  --mainnet \
  --out-file $HOME/tx/tx.signed
```

### Enviar

```bash
cardano-cli transaction submit \
  --tx-file $HOME/tx/tx.signed \
  --mainnet
```

***

## Verificar el registro

Espera unos segundos y comprueba:

```bash
cardano-cli query stake-address-info \
  --address $(cat $HOME/keys/stake.addr) \
  --mainnet
```

Si el registro fue exitoso verás la dirección con `rewardAccountBalance` (inicialmente 0).

***

## Flujo completo resumido

```
Generar payment keys
       ↓
Generar stake keys
       ↓
Construir payment.addr y stake.addr
       ↓
Fondear payment.addr (mínimo ~504 ADA)
       ↓
Crear stake.cert (con --key-reg-deposit-amt 2000000)
       ↓
Construir → Firmar → Enviar tx con stake.cert
       ↓
Verificar con query stake-address-info
```


# Registrar pool

Crear metadatos, generar el certificado de registro del pool, y enviar la transacción de registro en mainnet. Coste mínimo 170 ADA / Conway era.

Tienes las claves, tienes las direcciones, tienes fondos. Ahora registras el pool en la cadena. El proceso implica tres cosas: crear los metadatos, generar el certificado de registro, y enviarlo en una transacción junto con el certificado de delegación del pledge.

***

## 1. Preparar los metadatos del pool

Crea el archivo `meta.json`:

```json
{
  "name": "NombreDetuPool",
  "description": "Descripción breve del pool, máximo 255 caracteres.",
  "ticker": "TICK",
  "homepage": "https://tupool.io"
}
```

Reglas que aplica la red:

* `ticker`: 3–5 caracteres, mayúsculas y números.
* `name`: máximo 50 caracteres.
* `description`: máximo 255 caracteres.
* `homepage`: URL válida con HTTPS.

### Metadatos extendidos (recomendado)

Los exploradores y wallets leen los metadatos extendidos para mostrar información adicional. Crea `meta-extra.json`:

```json
{
  "info": {
    "url_png_icon_64x64": "https://tupool.io/icon.png",
    "url_png_logo": "https://tupool.io/logo.png",
    "location": "ES",
    "social": {
      "twitter_handle": "tupool"
    }
  }
}
```

Sube ambos archivos a una URL estable y calcula el hash del `meta.json`:

```bash
cardano-cli stake-pool metadata-hash \
  --pool-metadata-file meta.json
```

Anota el hash resultante — lo necesitarás en el certificado.

{% hint style="warning" %}
La URL del metadata debe ser estable y accesible en todo momento. Cualquier cambio en el contenido invalida el hash y requiere actualizar el certificado del pool.
{% endhint %}

***

## 2. Crear el certificado de registro del pool

```bash
cardano-cli stake-pool registration-certificate \
  --cold-verification-key-file          $HOME/cold-keys/node.vkey \
  --vrf-verification-key-file           $HOME/pool-keys/vrf.vkey \
  --pool-pledge                         <PLEDGE_EN_LOVELACE> \
  --pool-cost                           170000000 \
  --pool-margin                         0.01 \
  --pool-reward-account-verification-key-file $HOME/keys/stake.vkey \
  --pool-owner-stake-verification-key-file    $HOME/keys/stake.vkey \
  --mainnet \
  --pool-relay-ipv4                     <IP_DEL_RELAY> \
  --pool-relay-port                     3000 \
  --metadata-url                        https://tupool.io/meta.json \
  --metadata-hash                       <HASH_DEL_META> \
  --out-file $HOME/tx/pool-registration.cert
```

{% hint style="info" %}
**Coste mínimo del pool:** el protocolo exige un mínimo de **170 ADA (170 000 000 lovelace)** como coste fijo por época. Este valor bajó en 2022 (era 340 ADA).

**Depósito de registro:** se retienen **500 ADA (500 000 000 lovelace)** al registrar el pool. Se devuelven si retiras el pool correctamente.
{% endhint %}

***

## 3. Crear el certificado de delegación del pledge

Para que el pledge cuente, tu stake address tiene que estar delegada al propio pool:

```bash
cardano-cli stake-address stake-delegation-certificate \
  --stake-verification-key-file $HOME/keys/stake.vkey \
  --cold-verification-key-file  $HOME/cold-keys/node.vkey \
  --out-file $HOME/tx/delegation.cert
```

{% hint style="info" %}
**Era Conway / cardano-cli 10+:** el subcomando correcto es `stake-address stake-delegation-certificate`. En versiones anteriores del CLI era `stake-address delegation-certificate`.
{% endhint %}

***

## 4. Construir y enviar la transacción de registro

### Consultar UTxO

```bash
cardano-cli query utxo \
  --address $(cat $HOME/keys/payment.addr) \
  --mainnet
```

```
                           TxHash                                 TxIx        Amount
--------------------------------------------------------------------------------------
441c5b06...22ee0065     0        49992783811 lovelace + TxOutDatumNone
```

### Construir la transacción

Esta transacción incluye dos certificados: el de registro del pool y el de delegación.

```bash
cardano-cli transaction build-raw \
  --tx-in <TXHASH>#<TXIX> \
  --tx-out $(cat $HOME/keys/payment.addr)+<CAMBIO> \
  --ttl <SLOT_LIMITE> \
  --fee <FEE> \
  --certificate-file $HOME/tx/pool-registration.cert \
  --certificate-file $HOME/tx/delegation.cert \
  --out-file $HOME/tx/tx-pool.raw
```

El cambio se calcula así:

```
CAMBIO = UTXO_LOVELACE - 500000000 (depósito pool) - FEE
```

### Calcular fee

```bash
cardano-cli transaction calculate-min-fee \
  --tx-body-file         $HOME/tx/tx-pool.raw \
  --tx-in-count          1 \
  --tx-out-count         1 \
  --witness-count        3 \
  --mainnet \
  --protocol-params-file $HOME/tx/protocol.json
```

Son 3 witnesses: payment key, stake key, y cold key.

### Firmar

```bash
cardano-cli transaction sign \
  --tx-body-file      $HOME/tx/tx-pool.raw \
  --signing-key-file  $HOME/keys/payment.skey \
  --signing-key-file  $HOME/keys/stake.skey \
  --signing-key-file  $HOME/cold-keys/node.skey \
  --mainnet \
  --out-file $HOME/tx/tx-pool.signed
```

{% hint style="warning" %}
Para firmar esta transacción necesitas la cold key. Lleva el `tx-pool.raw` a la máquina air-gapped, firma ahí con las tres claves, y trae solo el `tx-pool.signed` de vuelta al nodo caliente.
{% endhint %}

### Enviar

```bash
cardano-cli transaction submit \
  --tx-file $HOME/tx/tx-pool.signed \
  --mainnet
```

***

## 5. Obtener el Pool ID

```bash
cardano-cli stake-pool id \
  --cold-verification-key-file $HOME/cold-keys/node.vkey \
  --output-format hex
```

Guarda este valor. Es el identificador permanente de tu pool.

***

## 6. Verificar el registro

```bash
cardano-cli query pool-state \
  --stake-pool-id <POOL_ID> \
  --mainnet
```

Si el pool está registrado verás los parámetros que configuraste: coste, margen, pledge, relays y hash de metadatos.

{% hint style="info" %}
**¿No aparece nada?** El registro entra en vigor al inicio de la siguiente época. Si acabas de enviar la transacción y estás en mitad de una época, espera hasta que cambie.
{% endhint %}

***

## 7. Aparición en explorers y wallets

{% hint style="info" %}
Tu pool comenzará a aparecer en exploradores como Cardanoscan, PoolTool o AdaPoolsOrg en el transcurso de la época actual o la siguiente. Las wallets pueden tardar **hasta 2 épocas** (\~10 días) en listar el pool para delegación.
{% endhint %}

***

## Flujo completo resumido

```
Crear meta.json + meta-extra.json → subir a URL estable
           ↓
Calcular metadata hash
           ↓
Crear pool-registration.cert (cold key en air-gapped)
           ↓
Crear delegation.cert (stake → pool)
           ↓
Construir tx con ambos certificados
           ↓
Firmar con payment + stake + cold key (en air-gapped)
           ↓
Enviar tx desde nodo caliente
           ↓
Verificar con query pool-state
           ↓
Pool activo al inicio de la siguiente época
```


# Renovar KES keys

Cómo renovar las claves KES y emitir un nuevo certificado operacional antes de que expiren. Incluye cómo verificar cuántos períodos quedan.

Las claves KES (Key Evolving Signature) tienen una vida útil limitada. En mainnet duran aproximadamente **62 días**. Si expiran sin que las renueves, tu block producer deja de firmar bloques.

{% hint style="warning" %}
Todo lo que involucre claves frías debe hacerse en la máquina air-gapped, sin conexión a internet. Nunca muevas las cold keys a un equipo conectado.
{% endhint %}

***

## Verificar cuándo vencen tus KES

Antes de ponerte a renovar, verifica cuántos períodos te quedan:

```bash
cardano-cli query kes-period-info \
  --mainnet \
  --op-cert-file $HOME/pool-keys/node.cert
```

La salida te muestra el período actual, el período en que emitiste el certificado y cuántos períodos de KES quedan disponibles. Cuando veas que te quedan menos de 10, es momento de renovar.

{% hint style="info" %}
Pon un recordatorio en el calendario **dos semanas antes** de la fecha de vencimiento. No esperes al último momento.
{% endhint %}

***

## Obtener el período KES actual

En el block producer, calcula el período:

```bash
expr $(cardano-cli query tip --mainnet | jq .slot) / $(cat $HOME/cardano/relay/config/shelley-genesis.json | jq .slotsPerKESPeriod)
```

El resultado es un número entero como `4385`. Ese es el `--kes-period` que usarás al generar el nuevo certificado.

***

## Generar las nuevas claves KES

En el **block producer**:

```bash
cardano-cli node key-gen-KES \
  --verification-key-file $HOME/pool-keys/kes.vkey \
  --signing-key-file      $HOME/pool-keys/kes.skey
```

Copia `kes.vkey` a la máquina air-gapped para emitir el nuevo certificado operacional.

***

## Generar el nuevo certificado operacional

En la **máquina air-gapped**, con las cold keys accesibles:

```bash
cardano-cli node issue-op-cert \
  --kes-verification-key-file      $HOME/pool-keys/kes.vkey \
  --cold-signing-key-file          $HOME/cold-keys/node.skey \
  --operational-certificate-issue-counter-file $HOME/cold-keys/cold.counter \
  --kes-period                     <KES_PERIOD_ACTUAL> \
  --out-file                       $HOME/pool-keys/node.cert
```

Esto incrementa el `cold.counter`. Guarda el contador actualizado.

{% hint style="danger" %}
Nunca copies las cold keys (`node.skey`) al block producer ni a ningún equipo conectado a internet.
{% endhint %}

***

## Copiar los archivos al block producer

Transfiere de vuelta al block producer:

* `kes.skey` (las nuevas claves KES)
* `node.cert` (el nuevo certificado)

***

## Reiniciar el servicio y verificar

```bash
sudo systemctl restart BP
```

Revisa los logs para confirmar que el nodo arrancó con el nuevo certificado:

```bash
journalctl -fu BP
```

Confirma el estado del nuevo certificado:

```bash
cardano-cli query kes-period-info \
  --mainnet \
  --op-cert-file $HOME/pool-keys/node.cert
```

***

## Resumen del proceso

```
Verificar períodos restantes con kes-period-info
           ↓
Calcular KES period actual (slot / slotsPerKESPeriod)
           ↓
Generar nuevas kes.skey + kes.vkey en el nodo caliente
           ↓
Copiar kes.vkey al air-gapped
           ↓
Emitir nuevo node.cert con cold key (air-gapped)
           ↓
Copiar kes.skey + node.cert al block producer
           ↓
sudo systemctl restart BP
           ↓
Verificar con journalctl y kes-period-info
```


# Actualizar parámetros del pool

Cómo actualizar pledge, fees, márgenes, pool owner o metadata sin retirar el pool. Basta con re-registrar el certificado con los nuevos valores.

Cualquier parámetro del pool — pledge, margen, coste fijo, relays, metadata, o la lista de pool owners — se actualiza enviando un nuevo certificado de registro con los valores modificados. El pool sigue activo durante todo el proceso.

{% hint style="info" %}
No pagas el depósito de 500 ADA de nuevo. Solo pagas los fees normales de la transacción (\~0.2–0.5 ADA).
{% endhint %}

***

## Casos de uso habituales

| Qué quieres cambiar        | Qué necesitas                                           |
| -------------------------- | ------------------------------------------------------- |
| Margen (%)                 | Nuevo cert de registro                                  |
| Coste fijo                 | Nuevo cert de registro                                  |
| Pledge (aumentar o bajar)  | Nuevo cert + mover los ADA a la stake address del owner |
| URL o hash de metadata     | Nuevo cert de registro                                  |
| Relays (IP, DNS, puerto)   | Nuevo cert de registro                                  |
| Pool owner (stake address) | Nuevo cert de registro                                  |

***

## Proceso general

El proceso es idéntico al registro inicial del pool, con los valores que quieres cambiar actualizados en el certificado.

### 1. Generar el nuevo certificado de registro

En la máquina **air-gapped** (necesitas la cold key):

```bash
cardano-cli stake-pool registration-certificate \
  --cold-verification-key-file          $HOME/cold-keys/node.vkey \
  --vrf-verification-key-file           $HOME/pool-keys/vrf.vkey \
  --pool-pledge                         <NUEVO_PLEDGE_EN_LOVELACE> \
  --pool-cost                           <NUEVO_COSTE_EN_LOVELACE> \
  --pool-margin                         <NUEVO_MARGEN> \
  --pool-reward-account-verification-key-file $HOME/keys/stake.vkey \
  --pool-owner-stake-verification-key-file    $HOME/keys/stake.vkey \
  --mainnet \
  --pool-relay-ipv4                     <IP_DEL_RELAY> \
  --pool-relay-port                     3000 \
  --metadata-url                        https://tupool.io/meta.json \
  --metadata-hash                       <HASH_DEL_META> \
  --out-file $HOME/tx/pool-update.cert
```

{% hint style="warning" %}
Incluye **todos** los parámetros, no solo los que cambian. Un certificado de registro reemplaza completamente al anterior — si omites los relays, el pool queda sin relays registrados.
{% endhint %}

### 2. Construir y enviar la transacción

```bash
cardano-cli transaction build \
  --mainnet \
  --tx-in <UTXO> \
  --change-address $(cat $HOME/keys/payment.addr) \
  --certificate-file $HOME/tx/pool-update.cert \
  --witness-override 3 \
  --out-file $HOME/tx/tx-update.raw
```

Firma con payment key, stake key y cold key:

```bash
cardano-cli transaction sign \
  --tx-body-file      $HOME/tx/tx-update.raw \
  --signing-key-file  $HOME/keys/payment.skey \
  --signing-key-file  $HOME/keys/stake.skey \
  --signing-key-file  $HOME/cold-keys/node.skey \
  --mainnet \
  --out-file $HOME/tx/tx-update.signed

cardano-cli transaction submit \
  --tx-file $HOME/tx/tx-update.signed \
  --mainnet
```

### 3. Verificar el cambio

```bash
cardano-cli query pool-state \
  --stake-pool-id <POOL_ID> \
  --mainnet
```

Los cambios entran en vigor al inicio de la **siguiente época**.

***

## Casos especiales

### Cambiar la metadata

Si cambias el contenido del `meta.json`, el hash cambia. Necesitas:

1. Actualizar el archivo en la URL pública.
2. Recalcular el hash: `cardano-cli stake-pool metadata-hash --pool-metadata-file meta.json`
3. Generar nuevo cert con el nuevo hash y la nueva URL si cambió.

{% hint style="warning" %}
Si cambias el contenido del archivo sin actualizar el hash en el certificado, los exploradores mostrarán error de verificación y no mostrarán los metadatos del pool.
{% endhint %}

### Cambiar el pledge

Cambiar el `--pool-pledge` en el certificado es solo una declaración. Para que el pledge sea efectivo, la stake address del pool owner debe tener delegados al menos esa cantidad de ADA al inicio de cada época. Si el pledge declarado supera el saldo delegado, el pool no recibe recompensas ese epoch.

### Añadir o quitar relays

Puedes registrar relays por IP o por DNS:

```bash
# Por IP
--pool-relay-ipv4 1.2.3.4 --pool-relay-port 3000

# Por hostname DNS
--pool-relay-port 3001 --pool-relay-host relay.tupool.io

# Varios relays: repite el flag por cada uno
--pool-relay-ipv4 1.2.3.4 --pool-relay-port 3000 \
--pool-relay-host relay.tupool.io --pool-relay-port 3001
```

### Cambiar el pool owner

El pool owner es la stake address que recibe las recompensas del operador. Para cambiarlo, incluye la nueva `--pool-owner-stake-verification-key-file` en el certificado. La transacción debe ir firmada por la nueva stake key además de la cold key y la payment key.


# Votar como SPO (Conway)

Cómo votar en governance actions de Cardano como operador de stake pool (SPO). Era Conway / CIP-1694. Incluye nota sobre registro como DRep.

Desde el hard fork Chang (era Conway), los stake pools tienen voz en la gobernanza de Cardano. Como SPO, puedes votar sobre **governance actions** usando tu cold key. No necesitas registrarte como DRep — tu voto como SPO es automáticamente elegible por el stake activo de tu pool.

{% hint style="info" %}
El peso de tu voto como SPO es proporcional al **stake activo** de tu pool en la época en que se registra el voto. Un pool con más delegadores tiene más peso.
{% endhint %}

***

## Tipos de governance actions donde vota el SPO

No todos los tipos de governance action requieren o incluyen el voto de los SPOs. Los SPOs votan en:

| Governance action         | SPO vota                  |
| ------------------------- | ------------------------- |
| Hard Fork Initiation      | ✅ Sí                      |
| Protocol Parameter Update | ✅ Sí (algunos parámetros) |
| No Confidence             | ✅ Sí                      |
| Update Committee          | ✅ Sí                      |
| New Constitution          | ✅ Sí                      |
| Info Action               | ✅ Sí (señalización)       |
| Treasury Withdrawal       | ❌ No (solo DReps y CC)    |

***

## 1. Ver las governance actions activas

```bash
cardano-cli query gov-state --mainnet | jq '.proposals'
```

Cada propuesta tiene un `txId` y un `govActionIx` (índice) que necesitarás para votar.

Para ver solo las acciones pendientes de forma más legible:

```bash
cardano-cli query gov-state --mainnet \
  | jq '.proposals | to_entries[] | {id: .key, action: .value.proposalProcedure.govAction.tag, expires: .value.expiresAfterEpoch}'
```

***

## 2. Crear el voto

En la máquina **air-gapped** (necesitas la cold key):

```bash
cardano-cli governance vote create \
  --yes \
  --governance-action-tx-id <TXID_DE_LA_PROPUESTA> \
  --governance-action-index <INDICE_DE_LA_PROPUESTA> \
  --cold-verification-key-file $HOME/cold-keys/node.vkey \
  --out-file $HOME/tx/spo.vote
```

Opciones de voto:

* `--yes` — a favor
* `--no` — en contra
* `--abstain` — abstención

{% hint style="info" %}
Puedes votar varias veces sobre la misma propuesta antes de que expire — el último voto registrado en cadena es el que cuenta.
{% endhint %}

***

## 3. Enviar el voto en una transacción

De vuelta en el nodo caliente, construye la transacción incluyendo el voto:

```bash
cardano-cli transaction build \
  --mainnet \
  --tx-in <UTXO> \
  --change-address $(cat $HOME/keys/payment.addr) \
  --vote-file $HOME/tx/spo.vote \
  --witness-override 2 \
  --out-file $HOME/tx/tx-vote.raw
```

Firma con payment key y cold key:

```bash
cardano-cli transaction sign \
  --tx-body-file      $HOME/tx/tx-vote.raw \
  --signing-key-file  $HOME/keys/payment.skey \
  --signing-key-file  $HOME/cold-keys/node.skey \
  --mainnet \
  --out-file $HOME/tx/tx-vote.signed

cardano-cli transaction submit \
  --tx-file $HOME/tx/tx-vote.signed \
  --mainnet
```

***

## 4. Verificar el voto

```bash
cardano-cli query gov-state --mainnet \
  | jq --arg pool "<POOL_ID>" '.proposals | to_entries[] | .value.dRepVotes, .value.spoVotes | to_entries[] | select(.key | contains($pool))'
```

O busca tu pool ID directamente en [gov.tools](https://gov.tools) o [cardanoscan.io](https://cardanoscan.io) en la sección de governance.

***

## Dónde hacer seguimiento de las propuestas

* [**gov.tools**](https://gov.tools) — portal oficial de gobernanza de Cardano, muestra propuestas activas, votaciones y estado
* [**Cardanoscan**](https://cardanoscan.io) — sección Governance
* [**Pool.pm**](https://pool.pm) — información de pools y gobernanza

***

## ¿Qué pasa si no voto?

La abstención implícita (no votar) tiene el mismo efecto que `--abstain` en la mayoría de los casos — no suma ni resta al quórum requerido. Sin embargo, para algunas acciones críticas como Hard Fork Initiation, se requiere que un porcentaje mínimo del stake total vote a favor. Si los SPOs no participan activamente, acciones importantes pueden no alcanzar el quórum.

***

## ¿Registrarme también como DRep?

Como SPO ya puedes votar sin registro adicional. El rol de **DRep** (Delegated Representative) es separado y permite que los delegadores te cedan su voto de gobernanza además de su stake. Si quieres registrarte también como DRep:

```bash
# Generar claves DRep
cardano-cli governance drep key-gen \
  --verification-key-file $HOME/drep-keys/drep.vkey \
  --signing-key-file      $HOME/drep-keys/drep.skey

# Certificado de registro DRep (depósito: 500 ADA)
cardano-cli governance drep registration-certificate \
  --drep-verification-key-file $HOME/drep-keys/drep.vkey \
  --key-reg-deposit-amt 500000000 \
  --out-file $HOME/tx/drep-reg.cert
```

Incluye el certificado en una transacción normal. El depósito de 500 ADA se recupera si cancelas el registro DRep más adelante.

{% hint style="info" %}
Registrarte como DRep es voluntario y es un compromiso adicional — los delegadores que te elijan como DRep esperan que votes activamente en todas las propuestas. No es obligatorio para operar un pool.
{% endhint %}


# Metadata y presencia en explorers

Cómo asegurarse de que tu pool aparece correctamente en Cardanoscan, PoolTool, AdaPools y wallets. Metadata estándar, extended metadata y verificación.

Que tu pool aparezca bien en los exploradores y wallets no es automático — depende de que los metadatos estén bien formados, en una URL estable y con el hash correcto registrado en cadena.

***

## El archivo meta.json

Es el único archivo de metadata que va referenciado directamente en el certificado de registro del pool. Tiene un tamaño máximo de **512 bytes** y debe cumplir exactamente con el esquema:

```json
{
  "name": "TOPO",
  "description": "Cardano stake pool operated by TOPO Labs.",
  "ticker": "TOPO",
  "homepage": "https://topopool.com"
}
```

Reglas estrictas:

* `ticker`: 3–5 caracteres, **solo mayúsculas y números**, sin espacios ni símbolos
* `name`: máximo 50 caracteres
* `description`: máximo 255 caracteres
* `homepage`: URL válida con HTTPS

Calcula el hash después de cualquier modificación:

```bash
cardano-cli stake-pool metadata-hash --pool-metadata-file meta.json
```

Si el hash no coincide con el registrado en cadena, **todos los exploradores mostrarán error** y ocultarán la metadata del pool.

***

## Extended metadata (meta-extra.json)

Los metadatos extendidos no están limitados a 512 bytes ni referenciados directamente en cadena. Los exploradores los buscan en una URL convencional. El estándar más adoptado es el de [CIP-0006](https://cips.cardano.org/cip/CIP-0006):

```json
{
  "info": {
    "url_png_icon_64x64": "https://topopool.com/icon.png",
    "url_png_logo": "https://topopool.com/logo.png",
    "location": "AR",
    "countryCode": "AR",
    "social": {
      "twitter_handle": "topopool",
      "telegram_handle": "topopool",
      "github_handle": "avilsmeier",
      "discord_handle": ""
    },
    "about": {
      "me": "Descripción más larga del operador del pool.",
      "server": "Infraestructura dedicada en nube europea.",
      "company": "TOPO Labs"
    }
  },
  "when": "2024-01-01T00:00:00Z",
  "cip": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0006/schema.json"
}
```

### Cómo vincular los extended metadata al pool

Añade la URL al `meta.json` original con el campo `extended`:

```json
{
  "name": "TOPO",
  "description": "Cardano stake pool operated by TOPO Labs.",
  "ticker": "TOPO",
  "homepage": "https://topopool.com",
  "extended": "https://topopool.com/meta-extra.json"
}
```

{% hint style="warning" %}
Agregar el campo `extended` cambia el contenido del `meta.json`, por lo tanto cambia el hash. Necesitas recalcular el hash y re-registrar el pool con el nuevo hash.
{% endhint %}

***

## Imágenes del pool

Los exploradores buscan las imágenes en las URLs que declares en el extended metadata. Requisitos habituales:

| Campo                | Tamaño               | Formato                    |
| -------------------- | -------------------- | -------------------------- |
| `url_png_icon_64x64` | Exactamente 64×64 px | PNG con fondo transparente |
| `url_png_logo`       | Al menos 200×200 px  | PNG                        |

Sirve los archivos con `Content-Type: image/png` y desde HTTPS.

***

## Verificar el registro en cadena

Comprueba que el hash registrado en la cadena coincide con el hash real del archivo:

```bash
# Hash del archivo actual
cardano-cli stake-pool metadata-hash --pool-metadata-file meta.json

# Hash registrado en cadena
cardano-cli query pool-state --stake-pool-id <POOL_ID> --mainnet \
  | jq '.poolParams.metadata.metadataHash'
```

Si son iguales, estás bien.

***

## Registrar en agregadores de pools

Además de la metadata en cadena, algunos servicios usan bases de datos propias que requieren registro manual o verificación:

### PoolTool

Registra tu pool en [pooltool.io](https://pooltool.io) — requiere crear una cuenta y reclamar el pool. Permite añadir información adicional, alertas de bloques y estadísticas avanzadas.

### AdaPools

[adapools.org](https://adapools.org) lee los extended metadata automáticamente. Si los metadatos no aparecen, verifica que la URL del archivo sea accesible públicamente y que el JSON sea válido.

### Cardanoscan

Carga los metadatos directamente desde la cadena y la URL registrada. Si el hash no coincide, muestra un aviso de error en la página del pool.

### SMASHpool

Los SMASHpool (Stake pool Metadata Aggregation Servers) son servicios que indexan y verifican la metadata de los pools. Las wallets como Daedalus, Yoroi y Lace los usan para mostrar información de los pools. Los principales:

* IOG SMASH: `https://smash.cardano-mainnet.iohk.io`
* CF SMASH (Cardano Foundation): disponible en varios endpoints

Si tu metadata no aparece en wallets tipo Daedalus, puede ser que el SMASH haya bloqueado tu pool por contenido inapropiado o errores repetidos de hash. Puedes verificarlo consultando directamente al SMASH:

```bash
curl https://smash.cardano-mainnet.iohk.io/api/v1/metadata/<POOL_ID>/<METADATA_HASH>
```

***

## Checklist de metadata

```
✅ meta.json < 512 bytes
✅ ticker en mayúsculas, 3-5 chars
✅ URL del meta.json accesible con HTTPS
✅ Hash registrado en cadena = hash del archivo actual
✅ meta-extra.json válido y accesible
✅ Imágenes PNG en las URLs declaradas
✅ Pool reclamado en PoolTool (opcional pero recomendado)
✅ Verificar en Cardanoscan que no hay error de hash
```


# Retirar un pool

Cómo retirar un stake pool de mainnet. Certificado de deregistración, recuperación del depósito de 500 ADA, y desregistro de stake address.

Si has tomado la decisión de cerrar tu stake pool, el proceso es ordenado. Aquí te explico cómo hacerlo correctamente.

{% hint style="info" %}
Anuncia el retiro a tus delegadores con suficiente antelación. No tienen por qué enterarse el mismo día que el pool desaparece. Un aviso con unas semanas de margen es lo mínimo que puedes hacer por ellos.
{% endhint %}

***

## Cuándo se hace efectivo el retiro

El retiro no es inmediato. Al registrar el certificado de deregistración, especificas una época futura (`retirement_epoch`). El valor máximo permitido es la época actual más `eMax`:

```bash
cardano-cli query protocol-parameters --mainnet | jq .eMax
```

Elige una época que le dé tiempo a tus delegadores de mover su stake antes de que el pool desaparezca.

***

## Obtener la época actual

```bash
cardano-cli query tip --mainnet
```

Busca el campo `epoch` en la salida.

***

## Crear el certificado de deregistración

Necesitas la cold key del pool. Este paso se hace en la **máquina air-gapped**:

```bash
cardano-cli stake-pool deregistration-certificate \
  --cold-verification-key-file $HOME/cold-keys/node.vkey \
  --epoch <EPOCA_RETIRO> \
  --out-file $HOME/tx/pool-dereg.cert
```

***

## Construir y firmar la transacción

De vuelta en el nodo caliente:

```bash
cardano-cli transaction build \
  --mainnet \
  --tx-in <UTXO> \
  --change-address $(cat $HOME/keys/payment.addr) \
  --certificate-file $HOME/tx/pool-dereg.cert \
  --witness-override 2 \
  --out-file $HOME/tx/tx-dereg.raw
```

Firma en la máquina air-gapped con la clave de pago y la cold key:

```bash
cardano-cli transaction sign \
  --tx-body-file      $HOME/tx/tx-dereg.raw \
  --signing-key-file  $HOME/keys/payment.skey \
  --signing-key-file  $HOME/cold-keys/node.skey \
  --mainnet \
  --out-file $HOME/tx/tx-dereg.signed
```

Envía desde el nodo caliente:

```bash
cardano-cli transaction submit \
  --mainnet \
  --tx-file $HOME/tx/tx-dereg.signed
```

***

## Recuperar el depósito del pool

Los 500 ADA que depositaste al registrar el pool te serán devueltos a tu `stake.addr` aproximadamente **2 épocas después** de que el retiro se haga efectivo. No requiere ninguna acción adicional.

{% hint style="info" %}
El depósito llega a la dirección de stake, no a la dirección de pago. Asegúrate de que tu wallet esté mirando esa dirección.
{% endhint %}

***

## Desregistrar la stake address (opcional)

Si ya no vas a usar esa stake address para nada más, puedes desregistrarla y recuperar el depósito de 2 ADA:

```bash
cardano-cli stake-address deregistration-certificate \
  --stake-verification-key-file $HOME/keys/stake.vkey \
  --out-file $HOME/tx/stake-dereg.cert
```

Incluye este certificado en una transacción firmada con `stake.skey` y `payment.skey`. Los 2 ADA del depósito se acreditan en la misma transacción.


# Prometheus y Grafana

Instalar Prometheus, Node Exporter y Grafana para monitorear tu stake pool. Incluye el dashboard TOPO⚡ listo para importar.

Vamos a levantar un stack de monitoreo completo que te da visibilidad en tiempo real sobre el estado de tus nodos: métricas de cardano-node, sistema (CPU, RAM, disco, red) y métricas de pool (stake, delegadores, bloques, ROA).

***

## Arquitectura del setup

```
cardano-node ──── puerto 12798 ─────┐
                                    ├──► Prometheus ──► Grafana ──► Dashboard TOPO⚡
node_exporter ─── puerto 9100 ──────┘
pool-exporter ─── (opcional) ───────┘
```

El servidor de monitoreo puede ser el mismo relay o una VM separada. Si lo ponés en el mismo relay, Prometheus scrapea localhost; si es una VM aparte, abrís los puertos de métricas solo hacia esa IP.

{% hint style="info" %}
En esta guía asumimos que el servidor de monitoreo corre en la misma máquina que el relay, o que tenés acceso a la IP privada del relay desde el servidor de monitoreo.
{% endhint %}

***

## 1. Verificar la configuración de cardano-node

El nodo ya expone métricas si el `config.json` tiene configurados estos campos:

```json
"hasPrometheus": ["127.0.0.1", 12798],
"hasEKG": 12789
```

Verificamos qué endpoint tiene las métricas:

```bash
# Puerto Prometheus (legacy tracing — lo más común)
curl -s http://127.0.0.1:12798 | head -5

# Puerto EKG (JSON — nuevo tracing backend o fallback)
curl -s http://127.0.0.1:12789 | jq '.cardano.node.metrics' 2>/dev/null | head -10
```

Si el puerto **12798** responde con líneas tipo `cardano_node_metrics_epoch_int 523`, usá ese como scrape target en Prometheus (es lo que hacemos en esta guía).

Si 12798 está vacío y todo está en **12789**, el nodo usa el nuevo tracing backend (`cardano-tracer`). En ese caso el scrape target en prometheus.yml debe apuntar al puerto que `cardano-tracer` exponga para Prometheus — típicamente también 12798 pero servido por el tracer, no por el nodo directamente. El resultado en Grafana es el mismo.

{% hint style="warning" %}
El bind de `hasPrometheus` está en `127.0.0.1` — solo accesible localmente. Si el servidor de monitoreo es una VM separada, cambia a `0.0.0.0` y agrega la IP del servidor de monitoreo al firewall.
{% endhint %}

***

## 2. Instalar Node Exporter

Node Exporter expone métricas del sistema operativo: CPU, RAM, disco, red y tiempo de sincronización NTP.

```bash
# Descargar la última versión
NODE_EXPORTER_VERSION="1.8.2"
wget https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
tar xzf node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
sudo cp node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter /usr/local/bin/
```

Crear el servicio systemd:

```bash
sudo tee /etc/systemd/system/node_exporter.service > /dev/null << 'EOF'
[Unit]
Description=Node Exporter
After=network.target

[Service]
Type=simple
User=TU_USUARIO
ExecStart=/usr/local/bin/node_exporter \
  --collector.systemd \
  --collector.processes \
  --web.listen-address=127.0.0.1:9100
StandardOutput=journal
StandardError=journal
SyslogIdentifier=node_exporter
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable node_exporter
sudo systemctl start node_exporter
```

Verificar:

```bash
curl -s http://127.0.0.1:9100/metrics | grep node_cpu | head -5
```

***

## 3. Instalar Prometheus

```bash
PROMETHEUS_VERSION="2.53.0"
wget https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz
tar xzf prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz
sudo cp prometheus-${PROMETHEUS_VERSION}.linux-amd64/{prometheus,promtool} /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
```

### Configuración de Prometheus

```bash
sudo tee /etc/prometheus/prometheus.yml > /dev/null << 'EOF'
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'cardano'
    static_configs:
      - targets:
          - 'localhost:12798'
        labels:
          alias: 'RELAY'
      # Si tienes BP accesible:
      # - targets: ['IP-BP:12798']
      #   labels:
      #     alias: 'CORE'

  - job_name: 'node'
    static_configs:
      - targets:
          - 'localhost:9100'
        labels:
          alias: 'RELAY'
      # - targets: ['IP-BP:9100']
      #   labels:
      #     alias: 'CORE'
EOF
```

{% hint style="info" %}
El campo `alias` en los labels es el que usa el dashboard TOPO⚡ para distinguir entre nodos. Usa `RELAY` para el relay y `CORE` para el block producer.
{% endhint %}

Crear el servicio systemd:

```bash
sudo tee /etc/systemd/system/prometheus.service > /dev/null << 'EOF'
[Unit]
Description=Prometheus
After=network.target

[Service]
Type=simple
User=TU_USUARIO
ExecStart=/usr/local/bin/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/var/lib/prometheus \
  --storage.tsdb.retention.time=90d \
  --web.listen-address=127.0.0.1:9090
StandardOutput=journal
StandardError=journal
SyslogIdentifier=prometheus
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

sudo chown -R TU_USUARIO:TU_USUARIO /var/lib/prometheus
sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus
```

Verificar que Prometheus levantó y puede scrape los targets:

```bash
curl -s http://127.0.0.1:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, state: .health}'
```

***

## 4. Instalar Grafana

```bash
sudo apt-get install -y apt-transport-https software-properties-common
wget -q -O - https://apt.grafana.com/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/grafana.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" \
  | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y grafana

sudo systemctl daemon-reload
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
```

Grafana queda en el **puerto 3000**. Para acceder desde tu máquina local, abrí un túnel SSH:

```bash
ssh -L 3000:localhost:3000 tu_usuario@IP-DEL-SERVIDOR
```

Luego abrí `http://localhost:3000` en el browser. Login por defecto: `admin` / `admin`.

{% hint style="warning" %}
No expongas el puerto 3000 a internet. Usá siempre el túnel SSH o un proxy inverso con autenticación.
{% endhint %}

***

## 5. Configurar Prometheus como datasource en Grafana

1. En Grafana: **Configuration** → **Data sources** → **Add data source**
2. Selecciona **Prometheus**
3. URL: `http://localhost:9090`
4. Clic en **Save & test** — debe aparecer "Data source is working"

***

## 6. Importar el dashboard TOPO⚡

El dashboard incluye:

| Panel                      | Qué muestra                                            |
| -------------------------- | ------------------------------------------------------ |
| Epoch / Block Height / Tip | Estado actual de la cadena                             |
| KES Expiration             | Tiempo restante hasta vencimiento de KES               |
| Pool Performance           | % de bloques forjados vs asignados                     |
| Saturation                 | % de saturación del pool                               |
| CPU / RAM / Disk / Network | Recursos del sistema por nodo                          |
| Mempool                    | Transacciones y bytes en mempool                       |
| Block delay / Late blocks  | Salud de la red P2P                                    |
| P2P Connections            | Conexiones por tipo (duplex, unidirectional, incoming) |
| Stake Metrics / ROA        | Stake activo, delegadores, retorno                     |
| Time Sync                  | Sincronización NTP — crítico para la forja de bloques  |

### Cómo importar

1. En Grafana: **Dashboards** → **Import**
2. Clic en **Upload JSON file**
3. Selecciona el archivo `topo-dashboard.json` (disponible en este repositorio en `kb/monitoreo/`)
4. En **prometheus**, selecciona el datasource que acabás de crear
5. Clic en **Import**

***

## 7. Métricas custom del pool

Los paneles de **Stake Metrics**, **Delegators**, **Blocks Minted**, **Saturation**, **Rank** y **ROA** usan métricas que no vienen del nodo directamente — vienen de un script que consulta la API de Koios y expone los datos vía un exporter personalizado.

Las métricas son:

```
saturation        delegators        blocks_lifetime
blocks_epoch      blocks_est_epoch  roa / roa_short
stake             stake_active      pledged
position          tx_submit_count   tx_submit_fail_count
```

Si estos paneles aparecen vacíos, instalá el **pool-exporter**: un script bash que consulta Koios y escribe las métricas en un archivo `.prom` que node\_exporter ya sirve en `:9100`. Sin puerto extra ni cambios en `prometheus.yml`. Ver guía completa: [Pool Exporter (Koios → Prometheus)](/monitoreo/pool-exporter).

***

## 8. Alertas básicas recomendadas

El dashboard ya tiene condiciones de alerta pre-configuradas para:

* CPU > 75% sostenido por 5 minutos
* RAM > 16 GB
* Chain density < 4% (nodo fuera de sync)
* Time sync > 5 segundos (problema NTP grave)

Para recibir las alertas por email o Telegram, configurá un **Contact point** en Grafana: **Alerting** → **Contact points** → **Add contact point**.

***

## Checklist final

```
✅ cardano-node expone métricas en :12798
✅ node_exporter corriendo en :9100
✅ Prometheus scrapeando ambos (ver /targets)
✅ Grafana instalado y accesible via túnel SSH
✅ Datasource Prometheus configurado y funcionando
✅ Dashboard TOPO⚡ importado
✅ Verificar que KES Expiration muestra tiempo correcto
✅ Verificar que CPU/RAM/Disk muestran datos del relay
```


# Pool Exporter (Koios → Prometheus)

Script bash que consulta Koios y escribe métricas del pool para que node\_exporter las sirva a Prometheus. Sin dependencias extra salvo jq.

Los paneles de **Stake Metrics**, **Delegators**, **Blocks**, **Saturation** y **ROA** del dashboard TOPO⚡ usan métricas que no vienen del nodo — son datos de la blockchain que solo están disponibles vía consulta a la API.

Este exporter es un script bash que consulta **Koios** (gratis, sin API key) cada 60 segundos y escribe un archivo `.prom` que node\_exporter lee y sirve junto con las métricas del sistema. Sin puerto extra, sin scrape job extra en Prometheus.

***

## Arquitectura

```
Koios API
    │
    ▼ (cada 60s vía systemd timer)
pool-exporter.sh ──► /var/lib/node_exporter/textfile/pool_metrics.prom
                                    │
                                    ▼ (node_exporter --collector.textfile)
                              Prometheus :9090
                                    │
                                    ▼
                              Grafana dashboard TOPO⚡
```

Las métricas del pool aparecen en el mismo endpoint `:9100/metrics` que ya scrapea Prometheus — sin cambios en `prometheus.yml`.

***

## Dependencias

```bash
# curl y awk vienen de serie en Ubuntu
# jq es el único paquete a instalar
sudo apt install -y jq
```

***

## Instalación

### 1. Habilitar textfile collector en node\_exporter

Editá el servicio de node\_exporter para agregar el flag `--collector.textfile.directory`:

```bash
sudo mkdir -p /var/lib/node_exporter/textfile

# Editar /etc/systemd/system/node_exporter.service
# Agregar la línea al ExecStart:
#   --collector.textfile.directory=/var/lib/node_exporter/textfile
```

El bloque `ExecStart` queda así:

```ini
ExecStart=/usr/local/bin/node_exporter \
  --collector.systemd \
  --collector.processes \
  --web.listen-address=127.0.0.1:9100 \
  --collector.textfile.directory=/var/lib/node_exporter/textfile
```

```bash
sudo systemctl daemon-reload
sudo systemctl restart node_exporter
```

### 2. Instalar el script

```bash
sudo cp pool-exporter.sh /usr/local/bin/pool-exporter.sh
sudo chmod +x /usr/local/bin/pool-exporter.sh
```

El script está en `kb/monitoreo/pool-exporter.sh` de este repositorio.

### 3. Crear el servicio y el timer systemd

Reemplazá `pool1...` con el bech32 ID de tu pool:

```bash
cardano-cli stake-pool id --cold-verification-key-file cold.vkey --output-format bech32
```

Crear el **servicio** (oneshot — se ejecuta y termina):

```bash
sudo tee /etc/systemd/system/pool-exporter.service > /dev/null << 'EOF'
[Unit]
Description=TOPO Pool Metrics — consulta Koios y escribe .prom
After=network-online.target

[Service]
Type=oneshot
User=TU_USUARIO
Environment="POOL_BECH32_ID=pool1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Environment="TEXTFILE_DIR=/var/lib/node_exporter/textfile"
ExecStart=/usr/local/bin/pool-exporter.sh
StandardOutput=journal
StandardError=journal
SyslogIdentifier=pool-exporter
EOF
```

Crear el **timer** (dispara cada 60 segundos):

```bash
sudo tee /etc/systemd/system/pool-exporter.timer > /dev/null << 'EOF'
[Unit]
Description=TOPO Pool Metrics — cada 60 segundos

[Timer]
OnBootSec=30
OnUnitActiveSec=60

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable pool-exporter.timer
sudo systemctl start pool-exporter.timer
```

### 4. Verificar

Ejecutar manualmente la primera vez para confirmar que funciona:

```bash
sudo -u TU_USUARIO POOL_BECH32_ID=pool1xxx \
  TEXTFILE_DIR=/var/lib/node_exporter/textfile \
  /usr/local/bin/pool-exporter.sh
```

Verificar el archivo generado:

```bash
cat /var/lib/node_exporter/textfile/pool_metrics.prom
```

Deberías ver:

```
# HELP saturation Pool saturation ratio 0-1
# TYPE saturation gauge
saturation 0.0023
# HELP delegators Number of delegators
# TYPE delegators gauge
delegators 14
...
```

Verificar que node\_exporter las expone:

```bash
curl -s http://127.0.0.1:9100/metrics | grep -E '^(saturation|delegators|stake|blocks|roa)'
```

{% hint style="info" %}
No hace falta tocar `prometheus.yml`. El job de `node` que ya existe scrapea el `:9100` donde ahora también aparecen las métricas del pool.
{% endhint %}

***

## Variables de entorno

| Variable         | Default                           | Descripción                                 |
| ---------------- | --------------------------------- | ------------------------------------------- |
| `POOL_BECH32_ID` | —                                 | **Requerido.** `pool1...`                   |
| `KOIOS_API`      | `https://api.koios.rest/api/v1`   | Cambiar a `preview.koios.rest` para testnet |
| `TEXTFILE_DIR`   | `/var/lib/node_exporter/textfile` | Directorio que lee node\_exporter           |

***

## Métricas expuestas

| Métrica             | Fuente Koios          | Unidad    |
| ------------------- | --------------------- | --------- |
| `saturation`        | `live_saturation`     | ratio 0–1 |
| `delegators`        | `live_delegators`     | número    |
| `stake`             | `active_stake`        | lovelace  |
| `stake_active`      | `live_stake`          | lovelace  |
| `pledged`           | `live_pledge`         | lovelace  |
| `blocks_lifetime`   | `block_count`         | número    |
| `blocks_epoch`      | `block_cnt` (history) | número    |
| `blocks_est_epoch`  | calculado¹            | número    |
| `roa` / `roa_short` | calculado²            | ratio     |

**¹** `blocks_est_epoch = (active_stake / total_active_stake) × 21600`\
21600 = slots\_per\_epoch × active\_slot\_coefficient = 432000 × 0.05 (mainnet).

**²** `roa = (pool_fees + delegator_rewards) / active_stake × 73`\
73 épocas ≈ 1 año. El ROA sube durante el epoch a medida que se acumulan rewards.

***

## Logs

```bash
journalctl -u pool-exporter.service
# o seguir el timer
systemctl list-timers pool-exporter.timer
```

Si Koios falla (mantenimiento, timeout), el script termina con error, el timer lo reintenta al siguiente ciclo y el `.prom` previo se conserva — Grafana no muestra saltos a cero.


# Conectar wallet a nodo de TOPO⚡

Cómo conectar tu wallet a un endpoint de submit personalizado para difundir transacciones a través de tu propio nodo.

Algunas wallets permiten especificar un endpoint de submit personalizado para enviar transacciones a través de tu propio nodo en lugar de usar la infraestructura del proveedor de la wallet. Es útil si quieres control total sobre la difusión de tus transacciones.

{% hint style="info" %}
Nami fue adquirida y descontinuada como producto independiente. Si eras usuario de Nami, **Eternl** es la alternativa más completa para este caso de uso. CCVault es ahora Eternl.
{% endhint %}

***

## Wallets que soportan endpoint personalizado

A día de hoy las wallets que permiten configurar un submit API propio son:

* **Eternl** — configurable en los ajustes de red del panel avanzado
* **Typhon** — disponible en preferencias avanzadas
* **Lace** — disponible en algunas versiones; verifica en los ajustes de red

Consulta la documentación de tu wallet para localizar exactamente dónde se configura, ya que la interfaz cambia entre versiones.

***

## Formato del endpoint

El endpoint de submit expuesto por el componente de submit de tu nodo tiene este formato:

```
http://HOST:8090/api/submit/tx
```

Sustituye `HOST` por la IP o dominio donde está corriendo tu nodo. Si la wallet está en la misma máquina, usa `127.0.0.1`.

{% hint style="warning" %}
No expongas el puerto 8090 a internet sin autenticación. Si necesitas acceder desde fuera de tu red local, usa una VPN o un proxy inverso con autenticación.
{% endhint %}

***

## Qué hace esto exactamente

Cuando la wallet usa tu endpoint, las transacciones firmadas se envían primero a tu nodo, que las difunde al resto de la red. El resultado final es el mismo, pero tienes visibilidad inmediata en los logs de tu nodo y no dependes de terceros para el submit.


# Migrar pledge a Ledger Nano

Cómo migrar el pledge de un stake pool a una hardware wallet (Ledger/Trezor) usando cardano-hw-cli. Guía actualizada para Conway era.

Usar una hardware wallet para custodiar las claves de pledge añade una capa de seguridad significativa. El proceso implica exportar las claves de verificación del dispositivo, construir las direcciones correspondientes y re-registrar el pool con el nuevo pledge.

{% hint style="danger" %}
Nunca introduzcas la frase semilla de tu hardware wallet en ningún ordenador. Si alguien te pide que lo hagas por cualquier motivo, es un intento de robo. La frase semilla solo existe en papel, en un lugar seguro.
{% endhint %}

***

## Requisitos previos

* Hardware wallet (**Ledger** o **Trezor**) con la aplicación **Cardano** instalada. Instala siempre la última versión disponible desde el gestor oficial del dispositivo (Ledger Live o Trezor Suite).
* **cardano-hw-cli**: descarga la última versión disponible en los [releases de GitHub](https://github.com/vacuumlabs/cardano-hw-cli/releases). No uses versiones antiguas; los comandos y el formato de salida cambian entre versiones.
* **cardano-cli** instalado y funcionando.

***

## Flujo general

### 1. Exportar las claves de verificación del hardware wallet

Conecta el dispositivo y, con la aplicación Cardano abierta en el dispositivo, exporta las claves de verificación de pago y stake. El comando exacto puede variar según la versión de `cardano-hw-cli`; consulta el README del release que hayas descargado:

```bash
cardano-hw-cli address key-gen \
  --path 1852H/1815H/0H/0/0 \
  --verification-key-file hw-payment.vkey \
  --hw-signing-file hw-payment.hwsfile

cardano-hw-cli address key-gen \
  --path 1852H/1815H/0H/2/0 \
  --verification-key-file hw-stake.vkey \
  --hw-signing-file hw-stake.hwsfile
```

{% hint style="info" %}
Los flags y la sintaxis exacta dependen de la versión instalada. Revisa `cardano-hw-cli --help` o la documentación del release antes de ejecutar.
{% endhint %}

### 2. Construir las direcciones

Con las claves de verificación exportadas, construye la dirección de pago y la dirección de stake:

```bash
cardano-cli stake-address build \
  --stake-verification-key-file hw-stake.vkey \
  --mainnet \
  --out-file hw-stake.addr

cardano-cli address build \
  --payment-verification-key-file hw-payment.vkey \
  --stake-verification-key-file   hw-stake.vkey \
  --mainnet \
  --out-file hw-payment.addr
```

### 3. Registrar la stake address

Si la stake address del hardware wallet no está registrada en cadena, necesitas registrarla antes de usarla como pledge:

```bash
cardano-cli stake-address registration-certificate \
  --stake-verification-key-file hw-stake.vkey \
  --key-reg-deposit-amt 2000000 \
  --out-file hw-stake-reg.cert
```

Incluye este certificado en una transacción y fírmala con `cardano-hw-cli`. La firma con hardware wallet requiere que el dispositivo esté conectado y que apruebes la transacción en pantalla del dispositivo.

### 4. Re-registrar el pool con el nuevo pledge

Genera un nuevo certificado de registro del pool apuntando a la nueva stake address como pledge y envía la transacción. Este paso requiere la cold key del pool (máquina air-gapped) y la firma del hardware wallet para la parte de stake.

{% hint style="warning" %}
Hasta que la transacción de re-registro sea confirmada y la delegación de la nueva dirección esté activa, el pledge puede aparecer como insatisfecho en los exploradores. Es temporal.
{% endhint %}

El flujo completo de firma con hardware wallet para transacciones de certificados está documentado en el repositorio de `cardano-hw-cli`. Dado que los detalles cambian entre versiones, consulta siempre la documentación del release que estés usando.


# Votar en Catalyst con wallet de pledge (deprecado)

Guía rápida para registrar tu wallet de pledge CLI para votar en Catalyst, realizar en máquina segura ya que requiere manipular las llaves del pledge.

{% hint style="danger" %}
Este proceso implica manipular tus llaves de payment y stake en un nodo **online**. Por favor extreme las medidas de precaución y utilice una máquina segura.
{% endhint %}

## Instalar voter-registration-tool

Nos permitirá preparar la transacción para registrar nuestra wallet

```
cd ~/src
git clone https://github.com/input-output-hk/voting-tools
cd voting-tools
cabal update
cabal build
cp $(find . -name voter-registration -executable -type f) ~/.local/bin/
```

## Instalar vit-kedqr

Lo utilizaremos para generar el código QR para la app mobile de Catalyst

```
cd ~/src
wget https://github.com/input-output-hk/vit-kedqr/releases/download/v0.0.1/vit-kedqr_Linux_x86_64.tar.gz
tar -xvzf vit-kedqr_Linux_x86_64.tar.gz
cp vit-kedqr_Linux_x86_64/vit-kedqr ~/.local/bin/
```

## Instalar jcli

Lo utilizaremos para generar nuestras key para la votación.

```
wget https://github.com/input-output-hk/jormungandr/releases/download/v0.9.3/jormungandr-0.9.3-x86_64-unknown-linux-gnu-generic.tar.gz
tar -xvzf jormungandr-0.9.3-x86_64-unknown-linux-gnu-generic.tar.gz
cp jcli ~/.local/bin/
```

## Generar llaves

```
cd ~/src/voting-tools
jcli key generate --type ed25519extended > catalyst-vote.skey
jcli key to-public < catalyst-vote.skey > catalyst-vote.pkey
```

## Generar archivo de transacción firmado

{% hint style="danger" %}
Aquí asumimos que todos los archivos se encuentran en el mismo directorio. Recuerda que toda operación con estas llaves debe hacerse en una maquina offline y segura.
{% endhint %}

```
voter-registration  --sign --payment-signing-key ~/cardano-node/operator/operator.skey \
    --payment-address $(cat ~/cardano-node/operator/operator.addr) \
    --vote-public-key catalyst-vote.pkey \
    --stake-signing-key ~/cardano-node/pool-keys/stake.skey \
    --mainnet \
    --mary-era \
    --cardano-mode \
    --out-file vote-registration.tx
```

## Someter transacción

```
cardano-cli transaction submit --cardano-mode \
    --mainnet \
    --tx-file vote-registration.tx
```

## Generar código QR

Ahora generamos un código QR que podremos escanear desde la app de "Catalyst Voting" en nuestro celular. Debemos usar el mismo PIN de 4 dígitos que utilizaremos en el móvil (a elección del usuario) y opcionalmente podemos guardar el QR agregando el parámetro `-output=QR.png`.

```
vit-kedqr -input catalyst-vote.skey -pin=1234 -output=QR.png
```


