Lo que harás
Cada entrada de una transacción de Bitcoin tiene un campo nSequence de 32 bits. En transacciones con versión 2 o superior, BIP 68 puede interpretar parte de ese campo como un bloqueo de tiempo relativo. La entrada solo pasa a ser válida después de cierta cantidad de bloques o de intervalos de 512 segundos, contados desde la salida que gasta.
En esta guía crearás un pequeño decodificador y codificador en Python. Probarás demoras por bloques, demoras por tiempo, la bandera de desactivación, tipos de demora incompatibles y el rango máximo. La prueba utiliza únicamente enteros sintéticos. No crea claves, no gasta monedas, no se conecta a un nodo y no transmite ninguna transacción.
El bloqueo relativo resulta útil en protocolos como canales de pago y rutas de recuperación, pero un entero correcto es solo una parte de una transacción válida. También importan las condiciones del script, la versión de la transacción, el historial de confirmación, la política de mempool y el estado de la cadena.
Requisitos previos
Necesitas:
- Python 3.10 o posterior
- un editor de texto y una terminal
- familiaridad básica con enteros hexadecimales y máscaras de bits
La prueba se verificó con la biblioteca estándar de Python. Las referencias de consenso se comprobaron contra Bitcoin Core v32.1, publicado el 28 de octubre de 2026. No necesitas Bitcoin Core para ejecutar el cálculo local.
Comprende el campo antes de codificarlo
BIP 68 asigna varios significados a los bits de nSequence:
- El bit 31 es la bandera de desactivación. Si está activo, el bloqueo relativo de BIP 68 no se aplica a esa entrada.
- El bit 22 selecciona la unidad. En cero significa bloques. En uno significa intervalos de 512 segundos.
- Los 16 bits inferiores contienen el valor relativo.
- Los demás bits no forman parte del valor relativo y no deben interpretarse como una demora adicional.
La máscara de 16 bits limita la demora por bloques a 65.535 bloques. El mayor valor temporal es 65.535 multiplicado por 512 segundos, es decir, 33.553.920 segundos. La forma temporal es deliberadamente aproximada. No puede expresar con exactitud una cantidad arbitraria de segundos.
Bitcoin Core aplica los bloqueos de secuencia únicamente cuando la versión de la transacción es al menos 2. Su código de consenso compara un bloqueo por bloques con la altura de la salida que se está gastando. Para un bloqueo temporal, utiliza el tiempo pasado mediano del bloque anterior al bloque que confirmó la salida. Eso no equivale al reloj de pared actual.
Crea el decodificador
Guarda estas constantes y la función en bip68_relative_locktime.py:
SEQUENCE_LOCKTIME_DISABLE_FLAG = 1 << 31
SEQUENCE_LOCKTIME_TYPE_FLAG = 1 << 22
SEQUENCE_LOCKTIME_MASK = 0x0000FFFF
SEQUENCE_LOCKTIME_GRANULARITY = 9
def decode_sequence(sequence: int) -> dict:
if not 0 <= sequence <= 0xFFFFFFFF:
raise ValueError("sequence must fit in an unsigned 32-bit integer")
if sequence & SEQUENCE_LOCKTIME_DISABLE_FLAG:
return {"enabled": False, "kind": "disabled"}
units = sequence & SEQUENCE_LOCKTIME_MASK
if sequence & SEQUENCE_LOCKTIME_TYPE_FLAG:
return {
"enabled": True,
"kind": "time",
"units": units,
"seconds": units << SEQUENCE_LOCKTIME_GRANULARITY,
}
return {
"enabled": True,
"kind": "blocks",
"units": units,
"blocks": units,
}
El orden importa. Comprueba el bit 31 antes de interpretar los bits inferiores. El valor final habitual 0xffffffff tiene activos todos los bits bajos, pero desactiva el bloqueo relativo. Si solo leyeras los 16 bits inferiores, informarías por error una demora de 65.535 unidades.
Para valores temporales, desplazar nueve bits a la izquierda equivale a multiplicar por 512. Por lo tanto, un valor almacenado de 8 representa 4.096 segundos, no 8 segundos.
Codifica demoras por bloques y por tiempo
Una demora por bloques cabe directamente en los 16 bits inferiores:
def encode_blocks(blocks: int) -> int:
if not 0 <= blocks <= 0xFFFF:
raise ValueError("blocks must be between 0 and 65535")
return blocks
Para un tiempo mínimo solicitado, redondea hacia arriba al siguiente intervalo de 512 segundos:
def encode_seconds(minimum_seconds: int) -> int:
if minimum_seconds < 0:
raise ValueError("minimum_seconds cannot be negative")
quantum = 1 << 9
units = (minimum_seconds + quantum - 1) // quantum
if units > 0xFFFF:
raise ValueError("requested delay exceeds BIP 68's time range")
return (1 << 22) | units
Redondear hacia abajo podría permitir el gasto antes del mínimo solicitado. Por ejemplo, una hora son 3.600 segundos. Siete intervalos representan 3.584 segundos, demasiado poco. Ocho intervalos representan 4.096 segundos, así que el mínimo codificado pasa a ser 68 minutos y 16 segundos.
Esta regla de redondeo es adecuada cuando el valor de entrada es una demora mínima. Si decodificas una transacción existente, informa el intervalo codificado exacto en lugar de sustituirlo por una aproximación más cómoda.
Ejecuta comprobaciones desechables
La prueba del repositorio evalúa estos casos:
assert decode_sequence(encode_blocks(144))["blocks"] == 144
one_hour = encode_seconds(3600)
assert decode_sequence(one_hour)["seconds"] == 4096
maximum = (1 << 22) | 0xFFFF
assert decode_sequence(maximum)["seconds"] == 33_553_920
assert decode_sequence(0xFFFFFFFF)["enabled"] is False
Ejecútala con:
python3 bip68_relative_locktime.py
Los resultados esperados incluyen:
- 144 bloques codificados como
0x00000090 - una hora solicitada codificada como ocho unidades temporales, que producen 4.096 segundos
- el máximo valor temporal codificado como
0x0040ffff 0xffffffffinformado como desactivado- una solicitud superior a 65.535 bloques rechazada en vez de truncada
- un requisito por bloques rechazado como incompatible con un candidato temporal
La comprobación de tipo es importante al razonar sobre OP_CHECKSEQUENCEVERIFY. Un entero bruto mayor no es necesariamente un bloqueo compatible. Las banderas de bloques y tiempo deben describir el mismo tipo antes de comparar sus valores enmascarados.
Relaciona el valor con el comportamiento de la transacción
Codificar un valor de secuencia no demuestra que una transacción futura será aceptada. Comprueba todo lo siguiente al aplicar el resultado:
- La transacción que gasta utiliza versión 2 o superior.
- La entrada seleccionada tiene el bit 31 en cero.
- La salida gastada cuenta con la altura o el historial temporal de confirmación necesarios para la evaluación.
- Un script que use
OP_CHECKSEQUENCEVERIFYsolicita un tipo compatible, por bloques o por tiempo. - Todas las demás entradas también han madurado según sus propios bloqueos de secuencia.
- La transacción cumple las reglas de consenso y la política actual del nodo.
BIP 112 da a OP_CHECKSEQUENCEVERIFY una función dentro del script. El código de operación compara el operando con el campo nSequence de la entrada y falla ante tipos incompatibles o valores insuficientes. No espera ni cuenta tiempo por sí mismo. BIP 68 proporciona la interpretación de la transacción que usa la validación de bloqueos de secuencia.
Para una cartera o implementación de protocolo, prueba con una cadena regtest desechable antes de utilizar la lógica con fondos reales. Mina bloques controlados, registra la altura de la salida, intenta gastar antes de la madurez y vuelve a intentarlo después del intervalo requerido. Esta guía no hizo esa prueba con un nodo, así que no afirma aceptación en mempool ni en bloque.
Solución de problemas
La demora decodificada es cero
Cero es un valor enmascarado válido. No añade una demora relativa, aunque siguen vigentes otras reglas de transacción y script. Confirma que no esperabas otra entrada o un orden de bytes diferente.
Una solicitud de una hora se convierte en 4.096 segundos
Es lo esperado. Los valores temporales de BIP 68 tienen una granularidad de 512 segundos. El codificador redondea hacia arriba para que el mínimo representado no sea menor que el solicitado.
Un valor muy grande aparece como desactivado
Inspecciona primero el bit 31. Valores como 0xffffffff excluyen la entrada de la evaluación de BIP 68 aunque sus 16 bits inferiores no sean cero.
Una comparación CSV falla aunque el número candidato sea mayor
Compara la bandera de tipo y luego los valores de 16 bits enmascarados. Un candidato temporal no puede satisfacer un operando de script basado en bloques, ni uno basado en bloques puede satisfacer un operando temporal.
La transacción sigue sin ser final
Los bloqueos relativos de secuencia son solo una fuente de restricciones de finalidad. Comprueba el nLockTime absoluto, todas las entradas, la madurez de coinbase cuando corresponda, la ejecución de scripts, la política de comisiones y la vista actual de la cadena del nodo.
Límites y siguiente paso
La prueba valida operaciones de bits, redondeo, rangos y controles negativos frente a las definiciones publicadas de los BIP y las constantes de Bitcoin Core v32.1. No analiza transacciones serializadas, no inspecciona una UTXO real, no ejecuta Script, no corre la suite funcional de Bitcoin Core y no envía nada a una mempool. Además, el tiempo pasado mediano implica que una demora temporal es una medición de la cadena de consenso, no una promesa sobre una hora del reloj.
Utiliza el decodificador como ayuda de revisión, no como autorización para gastar. En código de producción, conserva los nombres de constantes del proyecto original, añade el contexto de versión y UTXO, y reproduce el comportamiento en regtest antes de manejar valor.
Fuentes primarias
- BIP 68: bloqueo relativo mediante números de secuencia aplicados por consenso
- BIP 112: CHECKSEQUENCEVERIFY
- Constantes de secuencia de transacciones en Bitcoin Core v32.1
- Implementación de consenso de bloqueos de secuencia en Bitcoin Core v32.1
- Prueba funcional de BIP 68 en Bitcoin Core v32.1
- Publicación de Bitcoin Core v32.1
