DEV Community

Cover image for [II - IOTA Development]: Configuración y puesta en marcha del nodo Hornet
alvarogardev
alvarogardev

Posted on

[II - IOTA Development]: Configuración y puesta en marcha del nodo Hornet

Después de ver en el primer capítulo la instalación de todas las herramientas básicas que iremos necesitando durante nuestra aventura, vamos a empezar con la puesta en marcha de un nodo Hornet para tener nuestra red shimmer local.

Hornet, es un software desarrollado por la Fundación IOTA, escrito en Go y es el nodo que implementa la funcionalidad completa de los últimos avances de la red, como es actualmente la actualización Stardust.

Puesta en marcha del nodo Hornet local

Lo primero vamos a crear un espacio de trabajo para todos los ficheros de configuración de nuestra red privada.

~$ mkdir ~/iota-dev/private-network
Enter fullscreen mode Exit fullscreen mode

dentro de ese directorio iremos creando todos los ficheros de configuración para poder tener nuestro nodo hornet operativo.

./config.json

Ese fichero contiene toda la configuración para nuestro nodo hornet, dejo por aquí el enlace a la wiki de iota con todos los parámetros de configuración posibles, también podemos hacer un hornet -h --full y obtenemos un listado de todos los parámetros posibles actualizados.

{
  "node": {
    "alias": "ALVAROGAR DEV"
  },
  "protocol": {
    "targetNetworkName": "alvarogar-dev",
    "milestonePublicKeyCount": 2,
    "baseToken": {
      "name": "TestCoin",
      "tickerSymbol": "TEST",
      "unit": "TEST",
      "subunit": "testies",
      "decimals": 6,
      "useMetricPrefix": false
    },
    "publicKeyRanges": [
      {
        "key": "ed3c3f1a319ff4e909cf2771d79fece0ac9bd9fd2ee49ea6c0885c9cb3b1248c",
        "start": 0,
        "end": 0
      },
      {
        "key": "f6752f5f46a53364e2ee9c4d662d762a81efd51010282a75cd6bd03f28ef349c",
        "start": 0,
        "end": 0
      }
    ]
  },
  "participation": {
    "db": {
      "path": "participationdb"
    } 
  },
  "db": {
    "path": "privatedb"
  },
  "p2p": {
    "db": {
      "path": "p2pstore"
    }
  },
  "snapshots": {
    "fullPath": "snapshots/full_snapshot.bin",
    "deltaPath": "snapshots/delta_snapshot.bin",
    "downloadURLs": []
  },
  "restAPI": {
    "publicRoutes": [
      "/health",
      "/api/*"
    ],
    "protectedRoutes": [],
    "pow": {
      "enabled": true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

./Dockerfile

Este fichero es el que se encarga de crear la imagen con todos los plugins de hornet, se pueden modificar las versiones de las imágenes usadas para hornet y los plugins inx.

FROM iotaledger/hornet:2.0.0-rc.4 AS hornet
FROM iotaledger/inx-indexer:1.0-rc AS indexer
FROM iotaledger/inx-faucet:1.0-rc AS faucet
FROM iotaledger/inx-dashboard:1.0-rc AS dashboard
FROM iotaledger/inx-mqtt:1.0-rc AS mqtt
FROM iotaledger/inx-spammer:1.0-rc AS spammer
FROM iotaledger/inx-coordinator:1.0-rc AS coordinator
FROM iotaledger/inx-poi:1.0-rc AS poi
FROM iotaledger/inx-participation:1.0-rc AS participation

FROM debian:11

# hornet-1 API
EXPOSE 14265/tcp

# hornet-1 dashboard
EXPOSE 8081/tcp

# hornet-1 INX
EXPOSE 9029/tcp

# faucet
EXPOSE 8091/tcp

RUN mkdir /app
WORKDIR /app

# Prepare supervisor
RUN apt update && apt install -y supervisor parallel
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf


# Copy the inx apps dir into HORNET image
COPY --from=hornet /app /app/hornet-1
COPY --from=hornet /app /app/hornet-2
COPY --from=indexer /app /app/indexer
COPY --from=faucet /app /app/faucet
COPY --from=dashboard /app /app/dashboard
COPY --from=mqtt /app /app/mqtt
COPY --from=spammer /app /app/spammer
COPY --from=coordinator /app /app/coordinator
COPY --from=poi /app /app/poi
COPY --from=participation /app /app/participation

# Overwrite default config
COPY config.json /app/hornet-1/config.json
COPY config.json /app/hornet-2/config.json

# Create snapshots
COPY protocol_parameters.json /app/protocol_parameters.json
RUN mkdir /app/hornet-1/snapshots

RUN /app/hornet-1/hornet tool snap-gen \
    --protocolParametersPath=/app/protocol_parameters.json \
    --mintAddress=tst1qq2kvnu9pqzptkggrpqrvltvagccsh6aj2fkdhla7p3lrsy9dwhdzu5l2ye \
    --outputPath=/app/hornet-1/snapshots/full_snapshot.bin

RUN cp -R /app/hornet-1/snapshots /app/hornet-2/

# Bootstrap network
RUN mkdir /app/coordinator/state
RUN COO_PRV_KEYS=651941eddb3e68cb1f6ef4ef5b04625dcf5c70de1fdc4b1c9eadb2c219c074e0ed3c3f1a319ff4e909cf2771d79fece0ac9bd9fd2ee49ea6c0885c9cb3b1248c,0e324c6ff069f31890d496e9004636fd73d8e8b5bea08ec58a4178ca85462325f6752f5f46a53364e2ee9c4d662d762a81efd51010282a75cd6bd03f28ef349c /app/hornet-1/hornet tool bootstrap-private-tangle \
    --configFile=/app/hornet-1/config.json \
    --snapshotPath=/app/hornet-1/snapshots/full_snapshot.bin \
    --databasePath=/app/hornet-1/privatedb \
    --cooStatePath=/app/coordinator/state/coordinator.state


CMD ["/usr/bin/supervisord"]
Enter fullscreen mode Exit fullscreen mode

./protocol_parameters.json

Este fichero lo vamos a usar para generar un snapshot para la red privada mediante hornet tool snap-gen. Si se ejecuta un nodo Hornet por primera vez, se necesita iniciarlo con una instantánea completa. Hornet la descarga automáticamente de fuentes de confianza. Para este caso vamos a generarla con la herramienta snap-gen. más info

{
    "version": 2,
    "networkName": "alvarogar-dev",
    "bech32HRP": "tst",
    "minPoWScore": 0,
    "belowMaxDepth": 15,
    "rentStructure": {
        "vByteCost": 500,
        "vByteFactorData": 1,
        "vByteFactorKey": 10
    },
    "tokenSupply": "2779530283277761"
}
Enter fullscreen mode Exit fullscreen mode

./supervisord.conf

Este es el fichero de configuración para supervisor, es un gestor de procesos que facilita el manejo de procesos en ejecución por largo tiempo, en este caso lo usamos para gestionar los logs e inicializar hornet y todos sus plugins.

[unix_http_server]
file=/var/run/supervisor.sock

[supervisord]
logfile=/var/log/supervisor/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=error
pidfile=/var/run/supervisord.pid
user=root
nodaemon=true
minfds=8192
childlogdir=/var/log/supervisor/

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock

[program:hornet-1]
command=/app/hornet-1/hornet -c config.json --p2p.bindMultiAddresses=/ip4/0.0.0.0/tcp/15600 --restAPI.bindAddress=0.0.0.0:14265 --p2p.identityPrivateKey=1f46fad4f538a031d4f87f490f6bca4319dfd0307636a5759a22b5e8874bd608f9156ba976a12918c16a481c38c88a7b5351b769adc30390e93b6c0a63b09b79 --p2p.peers=/ip4/127.0.0.1/tcp/15601/p2p/12D3KooWCKwcTWevoRKa2kEBputeGASvEBuDfRDSbe8t1DWugUmL --p2p.peerAliases=hornet-2 --inx.enabled=true --inx.bindAddress=0.0.0.0:9029 
directory = /app/hornet-1
stdout_logfile=/var/log/supervisor/hornet-1.log
redirect_stderr=true
priority=1

[program:hornet-2]
command=/app/hornet-2/hornet -c config.json --p2p.bindMultiAddresses=/ip4/0.0.0.0/tcp/15601 --restAPI.bindAddress=0.0.0.0:14266 --p2p.identityPrivateKey=a06b288ce7fc3b6f1e716f6f7d72050b53417aae4b305a68883550a3bb28597f254b082515a79391a7f13009b4133851a0c4d48e0e948809c3b46ff3e2500b4f --p2p.peers=/ip4/127.0.0.1/tcp/15600/p2p/12D3KooWSagdVaCrS14GeJhM8CbQr41AW2PiYMgptTyAybCbQuEY --p2p.peerAliases=hornet-1
directory = /app/hornet-2
stdout_logfile=/var/log/supervisor/hornet-2.log
redirect_stderr=true
priority=2

[program:inx-coordinator]
command=/app/coordinator/inx-coordinator --coordinator.stateFilePath=state/coordinator.state --coordinator.interval=1s --coordinator.blockBackups.enabled=false
environment=COO_PRV_KEYS="651941eddb3e68cb1f6ef4ef5b04625dcf5c70de1fdc4b1c9eadb2c219c074e0ed3c3f1a319ff4e909cf2771d79fece0ac9bd9fd2ee49ea6c0885c9cb3b1248c,0e324c6ff069f31890d496e9004636fd73d8e8b5bea08ec58a4178ca85462325f6752f5f46a53364e2ee9c4d662d762a81efd51010282a75cd6bd03f28ef349c"
directory = /app/coordinator
stdout_logfile=/var/log/supervisor/inx-coordinator.log
redirect_stderr=true
priority=3

[program:inx-spammer]
command=/app/spammer/inx-spammer  --spammer.autostart=true --spammer.bpsRateLimit=5
autorestart=true
startsecs=10
directory = /app/spammer
stdout_logfile=/var/log/supervisor/inx-spammer.log
redirect_stderr=true
priority=4

[program:inx-dashboard]
command=/app/dashboard/inx-dashboard --dashboard.bindAddress=0.0.0.0:8081 --dashboard.auth.passwordHash=577eb97f8faf2af47ff957b00827d6bfe9d05b810981e3073dc42553505282c1 --dashboard.auth.passwordSalt=e5d8d0bd3bb9723236177b4713a11580c55b69a51e7055dd11fa1dad3b8f6d6c
autorestart=true
startsecs=10
directory = /app/dashboard
stdout_logfile=/var/log/supervisor/inx-dashboard.log
redirect_stderr=true
priority=5

[program:inx-faucet]
command=/app/faucet/inx-faucet --faucet.bindAddress=0.0.0.0:8091 --faucet.amount=100000000000 --faucet.smallAmount=10000000000 --faucet.maxAddressBalance=200000000000 --faucet.rateLimit.enabled=false
environment=FAUCET_PRV_KEY="887844b1e6bf9ca9e0b57584656add4370dbb49a8cb79e2e3032229f30fd80359e3df559ad0de8e5fa019b9ea46d1ee40879f3f3f74594a3306de9dfd43dcd25"
autorestart=true
startsecs=10
directory = /app/faucet
stdout_logfile=/var/log/supervisor/inx-faucet.log
redirect_stderr=true
priority=6

[program:inx-indexer]
command=/app/indexer/inx-indexer
autorestart=true
startsecs=10
directory = /app/indexer
stdout_logfile=/var/log/supervisor/inx-indexer.log
redirect_stderr=true
priority=7

[program:inx-mqtt]
command=/app/mqtt/inx-mqtt
autorestart=true
startsecs=10
directory = /app/mqtt
stdout_logfile=/var/log/supervisor/inx-mqtt.log
redirect_stderr=true
priority=8

[program:inx-poi]
command=/app/poi/inx-poi
autorestart=true
startsecs=10
directory = /app/poi
stdout_logfile=/var/log/supervisor/inx-poi.log
redirect_stderr=true
priority=9

[program:inx-participation]
command=/app/participation/inx-participation
autorestart=true
startsecs=10
directory = /app/participation
stdout_logfile=/var/log/supervisor/inx-participation.log
redirect_stderr=true
priority=11


# This a workaround to label all the logs to be able to have
# a single log-stream in docker and know from which service it came

[program:hornet-logging]
command=parallel --tagstring "{/.}:" --line-buffer tail -f {} ::: hornet-1.log hornet-2.log inx-coordinator.log
user=root
directory=/var/log/supervisor/
startsecs=10
autostart=true
autorestart=true
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true

[program:inx-logging]
command=parallel --tagstring "{/.}:" --line-buffer tail -f {} ::: inx-indexer.log inx-spammer.log inx-faucet.log inx-mqtt.log inx-poi.log inx-participation.log
user=root
directory=/var/log/supervisor/
startsecs=10
autostart=true
autorestart=true
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
Enter fullscreen mode Exit fullscreen mode

./docker-compose.yml

Este es el fichero que docker compose va a utilizar para levantar nuestros servicios dockerizados, concretamente nuestra imagen de hornet creada a partir del Dockerfile anterior. También exponemos una serie de puertos para poder conectarnos desde fuera del container, concretamente son:

  • API 14265/tcp
  • Dashboard 8081/tcp
  • INX 9029/tcp
  • Faucet 8091/tcp
version: "3.9"
services:
  hornet:
    container_name: hornet
    build:
      dockerfile: Dockerfile
    image: hornet:dev
    stop_grace_period: 5m
    ports:
      - "14265:14265/tcp"
      - "8081:8081/tcp"
      - "8091:8091/tcp"
      - "9029:9029/tcp"
Enter fullscreen mode Exit fullscreen mode

Incializando nuestro nodo hornet

Una vez hemos creado todos esos ficheros dentro de nuestra carpeta /private-network y teniendo docker y docker compose instalado ejecutamos dentro de ese directorio lo siguiente:

~$ docker compose up
Enter fullscreen mode Exit fullscreen mode

este comando lo que va a hacer es construir la imagen de nuestro hornet y va a levantar un contenedor con esa imagen y toda la configuración que le hemos dicho mediante el fichero Dockerfile, podemos comprobar que todo funciona correctamente accediendo al dashboard en http://localhost:8081 o a la faucet en http://localhost:8091 o podemos conectar nuestra firefly a través del Hornet API en el host http://localhost:14265.
Si hacemos cualquier cambio en cualquiera de los ficheros deberemos parar el contenedor y ejecutar docker compose build para volver a crear la imagen con los nuevos cambios.

Image description

Image description

Espero que os haya gustado y sobre todo que os haya servido, para el próximo capítulo veremos como crear un cluster de 2 nodos wasp formando un committee y dentro de poco smart contracts!!.

Dejad vuestros comentarios y aprendamos juntos. Gracias!

Top comments (2)

Collapse
 
eluis_uckban profile image
Luis Almendra Jauriatt

Muchas Gracias por el articulo, hasta aqui, todo funcionando como se dice. Saludos

Collapse
 
jesusasensio profile image
Jesus Asensio Arroyo

Muchas gracias, muy bien explicado.
Deseando ver el siguiente capitulo de los nodos wasp