Buscando un bloque

Introducción

Recientemente, se me presentó la duda de qué estrategias usan los mineros de Bitcoin para generar el "nonce".

Ya que si todos lo buscan de forma secuencial, siempre ganaría el más rápido y si se busca de forma aleatoria podría ser muy ineficiente y provocar colisiones.
En el presente documento, intento desgranar de forma sencilla, estas cuestiones, haciendo un breve repaso de la minería de Bitcoin.

¿Qué es el nonce?

El proceso de minería, de forma muy resumida, consiste en:
    Reunir las transacciones que se quieren incluir en el siguiente bloque y generar el merkle root de las mismas
    Añadir el resto de información que se va a incluir en la cabecera de bloque, como marca de tiempo, versión, hash de la cabecera del bloque anterior, etc. formando la plantilla de bloque
    Aplicar repetidamente la función hash SHA-256, modificando el nonce en cada ejecución, para generar hashes completamente distintos hasta dar con un bloque válido según la dificultad actual
Nonce en la cabecera de bloque
Donde el nonce, es un campo situado en la cabecera de bloque, de 4 bytes, donde incluir un valor arbitrario. ¿Solo 32 bits? 🤔

¿Quién genera el nonce?

El nonce es generado por el mismo software minero que está generando los hashes.
Hoy en día, lo común es que la plantilla de bloque la genere el pool de minería, la distribuye entre los mineros, y son estos mineros los encargados de modificar el nonce hasta dar con el bloque buscado.
Estos mineros, actualmente son ASICs. Chips especializados en realizar los hashes variando el nonce.

Estrategias de generación de nonce

Las principales estrategias son:
    Generación aleatoria
      A priori, la más lógica, pero se podrían dar colisiones, lo que sería un desperdicio de computación
      Depende de la calidad del algoritmo y de la entropía usada
    Generación incremental
      Incrementar el valor de uno en uno
      A priori no tiene mucho sentido y es donde se podría pensar que siempre ganaría el más rápido. Pero remarco lo de "a priori"
    Algoritmos hibridos

Mi error y principal conclusión

Con lo visto hasta aquí, mi primer error era pensar que todo estaba en el nonce.
Con solo 32 bits, un ASIC actual podría probar todos los valores posibles en menos de un segundo, y con la dificultad actual, no encontrar el bloque buscado a pesar de probar todos los nonce posibles. De hecho, esto sería lo más normal.
Y no solo eso, y aquí mi principal equivocación: perfectamente todos los mineros podrían recorrer todo el nonce de forma secuencial, y no por ello va a ganar el más rápido, puesto que el nonce se está modificando sobre una plantilla de bloque que en cada minero puede dar un hash completamente distinto, por cualquier mínimo bit distinto en todo el conjunto de datos.
¿Entonces?
Existen otros campos que el ASIC o software minero puede modificar:
    Timestamp (Cada segundo que pasa, cambia. Cada segundo que pasa todo cambia 🤯)
    Versión (Solo una parte del número de versión se puede modificar)
    Cierta parte de la transacción de Coinbase. ExtraNonce *
Y por supuesto, por parte de quien genera la plantilla (pool), también se podría modificar:
    Otras partes de la transacción de Coinbase. ExtraNonce *
    Transacciones y orden de las mismas
Sobre la transacción de Coinbase, realmente no existe el ExtraNonce como tal. Son datos arbitrarios (hasta 100 bytes) en el espacio para el script, y se llama así de forma extra oficial, ExtraNonce.
Estos datos pertenecen a una transacción más, por lo que no forma parte de la cabecera de bloque en si, pero afecta a la misma porque modifica el merkle root.

Conclusión

Tras lo visto, es evidente que ya no tiene tanta relevancia como pensaba el algoritmo de generación de nonce, al menos no de forma individual. Y la generación incremental ya no es tan absurda, puesto que el nonce es solo una pieza más entre todas las que se pueden mover.
En este punto, entramos en un terreno pantanoso, de software cerrado de los ASIC y de cómo funcionan los pools de forma interna, información que seguiré buscando.
Con todo este caldo de cultivo, tanto los pools como los fabricantes de chips, tienen gran cantidad de variables para intentar ser mejores al resto.
Algunos posibles enfoques que se me han ocurrido o he ido viendo en comentarios de bitcointalk o bitcoin.stackexchange son los siguientes:
    Por parte de los pools, tienen que encontrar mecanismos para nunca mandar la misma plantilla de bloque a dos mineros distintos, evitando hacer el mismo trabajo dos veces.
      Esto ya lo apuntaba @z6Mkt...9Wv9o en el AfterPod del L227, y efectivamente dio en el clavo.
      Mi primer pensamiento es que mandaran distintos nonce o grupos de nonce a cada minero, repartiendo los 4.294.967.295 nonce entre los mineros disponibles. Por lo que he visto se llegó a hacer así en algunos casos, pero parece que ya no es habitual.
      Parece que la práctica más habitual actualmente, es usar el "ExtraNonce 1", ciertos bytes del script de la transacción de coinbase, que a modo de convenio el minero no puede tocar, sirviendo estos bytes al pool, como identificador del minero, y por lo tanto como seguro para no hashear dos veces los mismos datos.
      Al minero le quedan otros bytes del script de la transacción de coinbase, "
      Extra Nonce 2", que sí puede cambiar, en combinación con el nonce y el timestamp.
    Por parte de los mineros, el algoritmo ahora es mucho más complejo, con cuatro posibles variables en lugar de una. Y aquí es donde son especialistas los ASICs, y es por donde me gustaría seguir mi investigación. Se me ocurre que se ejecuten procesos en distintos hilos de ejecución, y en cada hilo, generar un ExtraNonce 2 de forma aleatoria, recalcular el merkle root, y con la cabecera generada recorrer los 32 bits del nonce de forma secuencial, cambiando el timestamp a cada segundo. Si cada hilo no puede hacer todo esto en menos de un segungo, se levantan los máximos hilos posibles y ya estaría. Si cada hilo procesa esto en menos de un segundo, hay que seguir pensando ...

Nota sobre el AsicBoost

Buscando información sobre el episodio del AsicBoost de 2017, he descubierto que para realizar un hash SHA256, hay que dividir la información de entrada en fragmentos (chunks) de 64 bytes. El encabezado de bloque tiene 80 bytes, por lo que hay que hashearlo en 2 veces.
Cabecera de bloque
El AsicBoost se basa en esto, y es la técnica de mantener uno de los dos fragmentos fijo, y realizar cambios y hashes solo en el otro fragmento, ahorrando trabajo.
El campo de 4 bytes de versión está en uno de los fragmentos, y el nonce de 4 bytes en el otro.
Hay dos tipos, el abierto y el encubierto.
AsicBoost abierto
    Se utilizan como nonce los bytes de versión, modificando el hash total, pero haciendo varios intentos sin modificar el segundo fragmento.
AsicBoost encubierto
    Este es más complejo, y se aprovecha de que los 32 bytes del merkle root están divididos en ambos fragmentos. 28 en el primero y 4 en el segundo.
    Se modifican las transacciones, pero de cierta manera que no se modifiquen los últimos 4 bytes del merkle root que pertenecen al segundo fragmento.
    Esta es la técnica que, aunque es menos eficiente que el abierto, es más eficiente que no hacerlo, y no era facil de detectar, dando ventaja a los mineros que lo hacían de forma oculta.

Desde 2018, momento en que parece ser que se compró la patente y se colocó en un fondo defensivo de patentes, en los bloques se indica si se usa o no el abierto.
Y por otro lado, tras la activación de SegWit, ya no se podría realizar el encubierto, al menos no de forma tan eficiente, y sobre todo, no de forma tan oculta. Sería muy sospechoso porque la única forma que queda para hacerlo pasa por minar bloques vacíos o muy pequeños.