Guide

Decodifica un bloqueo de tiempo relativo de Bitcoin con Python

Lee y construye valores nSequence de BIP 68 para bloqueos relativos por bloques y por tiempo, con una prueba desechable en Python y límites claros.

9 min de lecturaTransacciones
Decodifica un bloqueo de tiempo relativo de Bitcoin con Python

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
  • 0xffffffff informado 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:

  1. La transacción que gasta utiliza versión 2 o superior.
  2. La entrada seleccionada tiene el bit 31 en cero.
  3. La salida gastada cuenta con la altura o el historial temporal de confirmación necesarios para la evaluación.
  4. Un script que use OP_CHECKSEQUENCEVERIFY solicita un tipo compatible, por bloques o por tiempo.
  5. Todas las demás entradas también han madurado según sus propios bloqueos de secuencia.
  6. 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

Etiquetado

Boletín

Bitcoin, sin ruido

Qué ha pasado en Bitcoin, qué cambia de verdad, y las fuentes para que puedas comprobarnos. Un número cada vez, directo a tu correo.

  • Un correo por número, nunca una secuencia automática
  • Sin píxeles de seguimiento y sin compartir direcciones
  • Baja desde cualquier número con un clic

Recibe el próximo número

Un correo por número, sin píxeles de seguimiento, y te puedes dar de baja desde cualquiera de ellos. No compartimos tu dirección. Política de privacidad