
Tiempo de lectura aprox: 4 minutos, 28 segundos
Antecedentes
Con la versión 24.0 del cliente Bitcoin Core, se introdujeron varias mejoras y cambios. Uno de ellos ha sido y está siendo muy polémico, con diferencia de opiniones entre personas muy activas dentro del panorama Bitcoin. Nos referimos a la opción «mempoolfullrbf», está opción se puede activar desde el fichero de configuración de nuestro nodo o pasándola como parámetro a la hora de iniciarlo, pero ¿qué es exactamente lo que hacemos al activar esta función?
Un poco de historia
Las primeras versiones de Bitcoin. desde la 0.1 hasta la 0.3.11 implementaban un reemplazo de transacciones basado en el versionado, había un campo de versión en la transacción, en caso de que un nodo recibiera una versión superior a la almacenada en su mempool esta era reemplazada.
En la versión 0.3.12(año 2010) Satoshi deshabilitó esta característica.
En mayo de 2013 Peter Todd presentó un planteamiento inicial de RBF.
En 2015 comenzaron las conversaciones sobre el reemplazo de transacciones no confirmadas, hubo una versión de Bitcoin Core (v0.11) parcheada para aceptar el reemplazo de transacciones pero la primera propuesta fue FSS-RBF (First Seen Safe Replace By Fee).
La lógica detrás de esta propuesta era, reemplazar transacciones no confirmadas si la nueva transacción con una comisión mayor paga a los mismos outputs con igual o mayor importe. Esto protegía la lógica de first seen ya que no se podían modificar los output.
Tras esta, se hizo otra, se planteaba adoptar FSS-RBF hasta una fecha concreta (5 de Abril de 2016) en la que se activaría FULL-RBF
Como está sucediendo ahora, la propuesta fue polémica y tuvo muchas y muy importantes voces en contra Coinbase aceptaba transacciones no confirmadas y básicamente los argumentos de 2015 son los mismos que estamos viendo en 2022. Si FULL-RBF se activaba, los comercios dejarían de aceptar transacciones sin confirmar. Finalmente se cerró el PR a la espera de otros cambios que afectaban a la mempool y que, una vez implementados obligarían a cambiar el código propuesto.
En Octubre de 2015, de nuevo Peter Todd propuso OPT-IN RBF (BIP-0125) basado en el campo nSequence. Esta propuesta cuadró y se puso como hito para la versión 0.12.0. En esta política las transacciones que un nodo reemplaza van marcadas como reemplazables utilizando el campo sequence de los input de la transacción.
Esta ha sido la política por defecto en los nodos Bitcoin Core hasta la versión actual 24.0.
La propuesta
En junio de este año Antoine Riard propuso activar Full-RBF en la versión 24.0 de Bitcoin Core. Se plantean varios problemas nuevos de la política OPT-IN RBF que afectan a Lightning Network, Coinjoin, … Esta propuesta se acompañó de un PR que introducía la opción mempoolfullrbf en los ajustes de Bitcoin Core
Finalmente este cambio fue añadido en la versión 24.0 de Bitcoin Core. Por defecto mempoolfullrbf está desactivado y es el operador del nodo el que debe activarlo si quiere que su nodo sea Full-RBF.
El conflicto
Como he comentado, básicamente el conflicto que se produjo en 2013 se está repitiendo en 2022. Los comercios y servicios que aceptan transacciones sin confirmar han levantado la voz en contra de la posibilidad de que la red Bitcoin vaya hacía un modelo Full-RBF. En este pull request que abrió John Carvalho creo que están resumidas las 2 posturas. Si habéis leído los pull request de 2015 veréis que son muy, muy similares.
A nivel técnico la discusión, como hemos visto, lleva muchos años.
Las 2 posturas son respetables.
El experimento
¿Y si monitorizamos 2 nodos con diferente política de reemplazo? ¿Qué diferencias habrá? ¿Veremos reemplazos de transacciones no marcadas? ¿Cual se incluirá en un bloque? Vamos a intentar dar respuesta a todas estas preguntas.
La infraestructura
Monitorizaremos la mempool de 2 nodos, ambos con la versión 24.0 del cliente Bitcoin Core, ambos con la misma configuración a excepción del parámetro «mempoolfullrbf» que en uno de ellos está activada.
El procedimiento
Bitcoin.conf
Activo las siguientes opciones de debug en ambos nodos:
# [debug]
# Enable mempool logging
debug=mempool
# Enable mempool rejection logging
debug=mempoolrej
Los scripts
He creado un pequeño script (mempool.py) que monitoriza las entradas, rechazos y reemplazos en la mempool del nodo, cada nodo corre una copia del script y ha monitorizado 24 horas (el día 2 de Diciembre de 2022). Este script almacena la información en una base de datos sqlite para facilitar el posterior tratamiento de los datos. Podéis encontrar el script y la BBDD vacía aquí.
El script se lanza desde el directorio home o aquel en el que esté el directorio .bitcoin ya que se nutre del fichero debug.log.
Para determinar que una transacción está marcada como reemplazable (BIP-0125) necesitamos comprobar el campo sequence de todos los input ya que si cualquiera de ellos está marcado, la transacción completa es reemplazable.
Una vez que tenemos control de las transacciones que nuestro nodo acepta en la mempool y si están marcadas como reemplazables, lo único que nos queda es monitorizar los reemplazos que ocurren. Para ello basta con monitorizar las líneas que se refieran a los reemplazos y guardar la tx original y la tx de reemplazo.
Una vez finalizada la adquisición de datos podemos sacar algunas conclusiones pero necesitamos un dato más para poder tener una visión más clara de lo que ha ocurrido en nuestra mempool, ese dato es, ¿qué transacciones se han confirmado? Sabiendo esto podemos intuir hasta qué punto la red está aceptando FULL-RBF como política.
Para ello he creado un segundo script confirmed.py que añadirá el dato. Este script tiene que pasar por todas las transacciones aceptadas por lo que va a tardar. Mucho. Pero hemos venido a jugar.
Para comprobar si está confirmado utilizo el propio nodo contando las confirmaciones que tiene la transacción, si tiene más de 0 la considero confirmada.
Ya tenemos 2 BBDD con un montón de datos. Ahora toca tratarlos. Vamos con el…
BDMN (Big Data Management of the Node)
Consultas SQL
Actualizar la tabla de transacciones reemplazadas
Lo primero es actualizar la tabla de transacciones reemplazadas con el dato que hemos sacado con el script de confirmed. Lanzamos esta query:
UPDATE Replaced set Mined=(SELECT Accepted.Mined from Accepted where Accepted.TXID=Replaced.Original_tx)
Las transacciones de reemplazo pueden, a su vez, ser reemplazadas, en estos casos ninguna de las 2 transacciones se habrá confirmado vamos a etiquetar estos casos con la siguiente consulta SQL:
UPDATE Replaced SET Mined="none" where Replaced.New_tx in (SELECT DISTINCT Replaced.Original_tx from Replaced)
Y finalmente plantamos un 2 en el campo mined a las filas que siguen en «null» para que quede mejor, en este caso la transacción confirmada ha sido la de reemplazo.
UPDATE Replaced SET Mined="2" where Mined IS NULL
Extracción de datos
Cuantas transacciones ha aceptado mi nodo durante la monitorización
select count(TXID) FROM Accepted
Cuantas transacciones han sido reemplazadas
select count(Original_tx) FROM Replaced
Cuantas transacciones marcadas con RBF han sido reemplazadas
select count(TXID) FROM Accepted WHERE RBF<4294967295 AND Accepted.TXID in (SELECT Original_tx FROM Replaced)
Cuantas transacciones NO marcadas con RBF han sido reemplazadas
select count(TXID) FROM Accepted WHERE RBF>=4294967295 AND Accepted.TXID in (SELECT Original_tx FROM Replaced)
Cuantas transacciones No marcadas con RBF han sido reemplazadas y minadas
SELECT Original_tx from Replaced WHERE Mined=2 AND Original_tx in(SELECT TXID from Accepted where TXID in (SELECT Original_tx from (SELECT Original_tx from Replaced GROUP by New_tx HAVING count(New_tx)=1)) AND RBF>=4294967295)
Los datos
Nodo Full-RBF | Nodo Opt-in RBF | |
TX aceptadas | 286476 | 286302 |
TX RBF | 172703 | 172575 |
TX NO RBF | 113773 | 113727 |
TX reemplazadas | 10981 | 10767 |
TX RBF reemplazadas | 10679 | 10643 |
TX no RBF reemplazadas | 263 | 88* |
TX no RBF sin ascendentes (reemplazadas y confirmadas) | 12 | 0 |
Explicación de los datos
Las 88 transacciones reemplazadas no marcadas como reemplazables en el nodo Opt-in-RBF se deben a que tenían ascendentes si marcados como reemplazables. Al reemplazar el ascendente se reemplazan todos sus descendientes por la tx que ha reemplazado al ascendente.
Conclusiones
El nodo Full-RBF ha reemplazado 177 transacciones marcadas como no reemplazables, de esas 177, 12 han acabado confirmadas. Esto indica que hay nodos Full-RBF en la red pero todavía la política dominante es OPT-IN RBF.
El debate continua, y ahora es cuestión de los usuarios de Bitcoin señalizando su preferencia en sus nodos determinar la aceptación de FULL-RBF.