Minar con Nerdminer en Testnet4

Nerdminer (https://github.com/BitMaker-hub/NerdMiner_v2) es un proyecto educacional de código abierto que en teoría te permite minar bitcoin con un dispositivo hardware dedicado DIY (do it yourself) basado en un chip ESP32.
Un nerdminer es capaz de generar del orden de los 75 Khashes por segundo. En los tiempos que corren es virtualmente imposible llegar a obtener una recomensa de bloque con un hashrate de este orden de magnitud, por lo que en realidad debemos entender este proyecto como un punto de partida para aprender más sobre minería y ensamblaje de este tipo de dispositivos.
No obstante yo no me quedaba tranquilo teniendo conectado un dispositivo tan chulo, dedicado a una tarea que claramente nunca va a poder acomenter, por lo que pense, ¿por qué no ponerlo a minar en testnet donde el hashrate es mas bajo y tal vez tenga alguna oportunidad?, ¿por qué no apoyar la nueva testnet4 ? Y entonces fue cuando di con este artículo de Lunaticoin: Minar en solitario en la nueva Testnet4, y me puse manos a la obra a intentar hacerlo funcional con mi Nerdminer.

Preparativos

Para el proyecto he utilizado:
    Nerdminer, que se encargará del calculo de los hashes y de enviarlos al pool y que ya tenía previamente ensablado y flasheado con el último firmware disponible en el repositorio Github del proyecto.
    Rasberry Pi 3B, que ejecutará el nodo bitcoin y el pool de minería
    Tarjeta SD card de 32 Gbytes nos proporcionará suficiente espacio para almacenar la cadena de bloques de Testnet4 (a fecha de escritura la particion root de la RPI esta a un 40%, unos 8 Gbytes).
Hacer correr el nodo con este setup ha supuesto tener que hacer algunas consideraciones especiales:
En primer lugar he utilizado la imagen Raspberry Pi OS Lite de 64 bits (versión Debian 12 Bookworm), ya que no voy a utilizar la parte de interfaz grafica. Hay mil manuales sobre como se selecciona y flashea una SD card con Raspberry Pi Imager asi que no los voy a repetir.
La segunda consideración es que la compilación de bitcoin core en una RPI 3B nos llevará unas 12 horas, por lo que se hace necesario tener un terminal virtual donde dejar el proceso corriendo sin riesgo de que se interrumpa si la sesión se corta por inactividad, para lo que he instalado tmux:
sudo apt-get install tmux
Todos los comandos indicados se ejecutan con el usuario pi a excepción de que indique que haya que cambiar de usuario con el correspondiente comando sudo su - <usuario>.
La última consideración a tener en cuenta es compilar deshabilitando todas las opciones no necesarias, para lo que me he basado en este artículo de Damian Mee: https://medium.com/@meeDamian/bitcoin-full-node-on-rbp3-revised-88bb7c8ef1d1, en lugar de seguir el de Luna para esta parte.

Compilación e instalación de bitcoin core para testnet4

En primer lugar instalamos las dependencias necesarias para poder compilar:
sudo apt install git build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libminiupnpc-dev libzmq3-dev jq
A continuación clonamos el repositorio Github de bitcoin core y cambiamos a la rama donde estan las modificaciones para testnet4 (del artículo de Luna):
git clone https://github.com/bitcoin/bitcoin.git
cd bitcoin/src
git fetch origin pull/29775/head:2024-04-testnet-4-fix
git checkout 2024-04-testnet-4-fix
cd ..
Realizamos la configuración del makefile eliminando el wallet y otros componentes que no necesitaremos
./autogen.sh
./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" --enable-cxx --without-gui --disable-shared --with-pic --disable-tests --disable-bench --enable-upnp-default --disable-wallet
En este punto estamos listos para compilar y como nos va a llevar unas 12 horas creamos una sesion de terminal virtual con tmux y dentro de ésta lanzamos la compilación:
tmux
make
Verificamos que empieza a compilar bien. Para poder cerrar el terminal y dejarlo funcionando, tecleamos Crtl+b y despues d, saliendo de tmux. Ahora podremos salir del terminal con exit. Si al cabo de unas horas queremos ver como va, podemos volver a conectar a la RPI y teclear:
tmux attach
Y volveremos a conectar con la sesión que esta haciendo la compilación en el punto por el que vaya. Podemos repetir este proceso tantas veces como queramos. Una vez haya terminado de compilar, instalamos bitcoin core bajo /usr/local/bin y ya podremos cerrar tmux:
sudo make install
exit

Configuración de bitcoin core para testnet 4

Siguiendo el tutorial de Luna, ahora nos toca ejecutar por primera vez bitcoind pero en mi caso prefiero configurar el sistema al estilo de RaspiBolt (la otra fuente en la que me he inspirado, ver https://raspibolt.org/), por lo que crearemos un usuario bitcoin para ejecutar los servicios:
sudo adduser --gecos "" --disabled-password bitcoin
Ahora sí, arrancamos bitcoind por primera vez, con usuario bitcoin:
sudo su - bitcoin
bitcoind -testnet4
Cuando veamos que está sincronizando la cadena de bloques pulsamos Crtl+c para abortar.
Ahora vamos a configurar bitcoind, para lo que descargamos rpcauth y generamos la contraseña de rpc que después añadiremos al fichero de configuracion bitcoin.conf
cd .bitcoin
wget https://raw.githubusercontent.com/bitcoin/bitcoin/master/share/rpcauth/rpcauth.py
python3 rpcauth.py bitcoin micontraseña
Este último comando nos dará algo como esto. Debemos copiar la linea que comienza por rpcauth= para añadiela sobre el fichero de configuración que se indica mas abajo:
String to be appended to bitcoin.conf:
rpcauth=bitcoin:8c910a0f7a74f2937b333dfb4a5132f7$c9934412a8ccf48a50f8f8f648d961e93b2f3c90cdff8b590d562afd476e7ff8
Your password:
micontraseña
Creamos el fichero bitcoin.conf (recordad que seguimos en /home/bitcoin/.bitcoin y estamos con usuario bitcoin):
vi bitcoin.conf
Pegamos el siguiente contenido:
testnet4=1
txindex=1
server=1
[testnet4]
rpcport=5000
rpcallowip=127.0.0.1
rpcbind=0.0.0.0
rpcauth=<usuario y contraseña codificada que nos dio el anterior comando>
Salimos del editor y ejecutamos por segunda vez bitcoind pero ahora le vamos a pedir que indexe la cadena de bloques de testnet4, algo que lleva unos pocos minutos a fecha de escritura (si queremos esto lo podriamos hacer desde un tmux tambien, pero de momento no se hace necesario):
bitcoind -reindex
Una vez ha terminado y vemos progress=1.000000 abortamos con Ctrl+c y nos disponemos a dejar el proceso preparado para que arranque automáticamente en cada inicio de la RPI. Cerramos la sesión del usuario bitcoin y seguimos con el usuario pi:
exit
sudo vi /etc/systemd/system/bitcoind.service
Y copiaremos el siguiente script, inspirado en el de RaspiBolt, pero modificado para la ruta del fichero cookie en testnet4:
# RaspiBolt: systemd unit for bitcoind
# /etc/systemd/system/bitcoind.service

[Unit]
Description=Bitcoin daemon
After=network.target

[Service]

# Service execution
###################

ExecStart=/usr/local/bin/bitcoind -daemon \
                                  -pid=/run/bitcoind/bitcoind.pid \
                                  -conf=/home/bitcoin/.bitcoin/bitcoin.conf \
                                  -datadir=/home/bitcoin/.bitcoin \
                                  -startupnotify="chmod g+r /home/bitcoin/.bitcoin/testnet4/.cookie"

# Process management
####################
Type=forking
PIDFile=/run/bitcoind/bitcoind.pid
Restart=on-failure
TimeoutSec=300
RestartSec=30

# Directory creation and permissions
####################################
User=bitcoin
UMask=0027

# /run/bitcoind
RuntimeDirectory=bitcoind
RuntimeDirectoryMode=0710

# Hardening measures
####################
# Provide a private /tmp and /var/tmp.
PrivateTmp=true

# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full

# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true

# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true

# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true

[Install]
WantedBy=multi-user.target
Habilitamos el arranque en el inicio y arrancamos el servicio de bitcoind:
sudo systemctl enable bitcoind.service
sudo systemctl start bitcoind.service
Por último solo nos falta hacer que el usuario pi pueda ejectutar bitcoin-cli y ver trazas para lo que haremos lo siguiente:
sudo adduser pi bitcoin
sudo chmod -R 0750 /home/bitcoin
sudo find /home/bitcoin/.bitcoin/ -type d -exec chmod 750 {} \; && sudo find /home/bitcoin/.bitcoin/ -type f -exec chmod 640 {} \;
sudo ln -s /home/bitcoin/.bitcoin/ .bitcoin
Este último comando es necesario en Debian 12, ya que los directorios home se crean sin permiso de lectura para el grupo y querremos acceder con el usuario pi a los logs y al fichero cookie de autenticacion del cliente bitcoin bitcoin-cli:
Podremos ver los logs en dos sitios: en journalctl y en el directorio de ejecución de bitcoin donde hay informacion mas detallada:
journalctl -f -u bitcoind.service
tail -f /home/bitcoin/.bitcoin/testnet4/debug.log

Instalación del servidor de pool de minería ckpool

Instalaremos ckpool-solo, herramienta de pool de minería que soporta "solo mining", utilizada en el pool oficial del proyecto: https://nerdminers.org. Expone una interfaz stratum hacia los mineros (a la que se puede conectar un nerdminer o cualquier otro minero como bitaxe, cpuminer, etc.) y se conecta a nuestro nodo bitcoin core para obtener los bloques y transmitirle los hashes:
git clone https://github.com/golden-guy/ckpool-solo.git
cd ckpool-solo
git branch -a
Este último comando lista las ramas disponibles: nos quedamos con la rama nerdminer_v2, que tiene los cambios necesarios para definir el nivel de dificutad de entrada al pool mínimo para que nuestro nerdminer pueda enviar sus shares:
git checkout nerdminer_v2
./autogen.sh
./configure
make
sudo make install
Configuramos el pool para que se conecte a nuestro nodo local de bitcoin core, indicandole el puerto donde debe escuchar, direccion de nuestra billetera de tesnet4 que habremos obtenido por ejemplo creandonos un wallet sobre testnet4 con Sparrow Wallet (https://sparrowwallet.com, opcion restart in testnet4 disponible desde Sparrow Wallet 1.9.1). La direccion es necesaria aquí en caso de que no lo ejecutemos en modo "solo mining", que no va a ser el caso. En nuestro caso cada minero especificara su direccion al conectarse por stratum, pero por si lo queremos cambiar en un futuro igualmente vamos a ponerla aquí:
sudo vi /etc/ckpool.conf
Pegamos este contenido (modificando la dirección de la billetera testnet4 en btcaddress y donaddress asi como el bitsig con nuestros propios datos):
{
  "btcd": [
    {
      "url": "127.0.0.1:5000",
      "cookie": "/home/bitcoin/.bitcoin/testnet4/.cookie",
      "notify": false
    }
  ],
  "btcaddress": "mnyssP3kWZt9CR8UyUKipzaqAr4Pu5iyzV",
  "donaddress": "mnyssP3kWZt9CR8UyUKipzaqAr4Pu5iyzV",
  "donrate": 1,
  "btcsig": "/mined by Carlos/",
  "blockpoll": 100,
  "nonce1length": 4,
  "nonce2length": 8,
  "update_interval": 30,
  "version_mask": "1fffe000",
  "serverurl": [
    "0.0.0.0:3333"
  ],
  "mindiff" : 0.000000001,
  "startdiff" : 0.000000001,
  "maxdiff": 0,
  "logdir": "/home/bitcoin/.ckpool"
}
Nótese que los niveles de dificultad mindiff y startdiff estan puestos en un 1 con 8 ceros decimales por delante, para permitir que el nerdminer envíe sus shares al pool.
Con usuario bitcoin, arrancamos el pool desde linea de comandos, para comprobar que funciona:
sudo su - bitcoin 
ckpool --config /etc/ckpool.conf --btcsolo
Veremos algo así:
Pararemos el proceso ckpool con Ctrl+c. Para arrancar el servicio ckpool automáticamente en cada inicio del sistema debemos crear el fichero de arranque de systemd. Primero cerramos la sesion del usuario bitcoin para seguir con pi :
exit
sudo vi /etc/systemd/system/ckpool.service
Y pondremos el siguiente contenido (hack rapido para que arranque y pare automaticamente a continuacion de bitcoind, seguramente puede ser mejorado):
# /etc/systemd/system/ckpool.service

[Unit]
Description=Ckpool daemon
Wants=bitcoind.service
After=bitcoind.service

[Service]
ExecStart=/usr/local/bin/ckpool --config /etc/ckpool.conf --btcsolo

# Process management
####################
Type=simple
Restart=always
TimeoutSec=120
RestartSec=30
KillMode=process

# Directory creation and permissions
####################################
User=bitcoin

[Install]
WantedBy=multi-user.target
Habilitamos el arranque en el inicio del servicio y lo arrancamos:
sudo systemctl enable ckpool.service
sudo systemctl start ckpool.service
Podremos ver los logs en dos sitios: en journalctl y en el directorio de ejecucion de ckpool donde hay informacion mas detallada:
journalctl -f -u ckpool.service
tail -f /home/bitcoin/.ckpool/ckpool.log

Configuración del nerdminer

Visto que el pool arranca correctamente, conectamos el nerdminer a la alimentación USB. Si ya lo teníamos configurado de antes para otro pool, pulsaremos el botón superior a la derecha de la pantalla (dejando el cargador USB a la derecha) durante 5 segundos para borrar la configuración y volver a parametrizarlo desde cero.
Aparecerá en pantalla un codigo QR y unas intrucciones indicandonos que nos conectemos (con un movil aunque tambien se podría hacer desde un ordenador) al punto de acceso wifi NerdMinerAP con pasword MineYourCoins. Nos conectamos y accedemos a la URL de configuración que estará en http://192.168.4.1. Pulsamos sobre "Configure WiFi" e introducimos los parámetros de nuestra wifi, la dirección IP y puerto donde hemos arrancado el pool de testnet4 (la que tenga nuestra Raspberry Pi en la red local) y la dirección bitcoin de nuestra billetera Sparrow, para la que queremos minar:
Tras pulsar "Save" el nerdminer se reiniciará y mostrata la pantalla principal con el hashrate y las estadísticas de minado ¡Enhorabuena! ya estás minando, con un dispositivo dedicado a ello, y apoyando la testnet4.