En este artículo
Cuándo es «antes de tiempo»
«No se puede gastar antes del bloque 900.000». La frase es corta y es casi cierta. Pero ¿quién lo impide, el script o la red? ¿Se puede gastar en el bloque 900.000 o solo en el siguiente? ¿Y qué pasa si el plazo se pone en segundos en vez de en bloques? Esta entrada responde con el detalle que pide una referencia. Qué es Bitcoin Script se cuenta en su propia entrada. Cómo se usan los plazos en una billetera (wallet) de recuperación, en billeteras con timelock. Aquí está el mecanismo.
Cuatro piezas, no dos
Se habla de «CLTV y CSV», pero un timelock son dos campos de la transacción y dos opcodes que los comprueban.
- nLockTime. Campo de 32 bits de la transacción. Bloqueo absoluto, por altura o por tiempo. No viene de ningún BIP: es de consenso desde Bitcoin 0.2 (2009).
- nSequence. Campo de 32 bits de cada entrada. Bloqueo relativo, en bloques o en unidades de 512 s (BIP-68).
- OP_CHECKLOCKTIMEVERIFY (CLTV). Opcode del script. Absoluto (BIP-65).
- OP_CHECKSEQUENCEVERIFY (CSV). Opcode del script. Relativo (BIP-112).
Los campos son los que aplica la red. Los opcodes son el modo de exigir, desde el script de una moneda, que la transacción que la gaste declare un bloqueo suficiente. BIP-65 describe nLockTime como lo que impide minar una transacción «until either a certain block height, or block time, has been reached». BIP-68 le da a nSequence un significado de consenso: una entrada firmada sigue siendo inválida durante un plazo después de que se confirme la salida que gasta.
Altura o tiempo: el umbral de 500.000.000
Un mismo campo de 32 bits sirve para dos cosas. Bitcoin Core fija en script.h la constante LOCKTIME_THRESHOLD en 500.000.000. Por debajo, el valor es una altura de bloque. Desde ahí, una marca de tiempo Unix en segundos. El comentario del código fecha el umbral en el 5 de noviembre de 1985, así que cualquier fecha real queda por encima y cualquier altura previsible, por debajo.
El valor máximo es LOCKTIME_MAX = 0xFFFFFFFF. El código lo explica así: un lock time marca «the last invalid timestamp», de modo que con 0xFFFFFFFF la transacción no es válida nunca, salvo que todas sus entradas tengan nSequence final (se explica más abajo).
La mediana de tiempo (BIP-113)
Cuando el bloqueo es por tiempo, no se compara con la hora del bloque que incluye la transacción. Se compara con la mediana de los 11 bloques anteriores (Median Time Past, MTP). Esa mediana nunca retrocede. El motivo que da BIP-113 es quitar al minero el incentivo de mentir sobre la hora para cobrar antes las comisiones de transacciones bloqueadas por tiempo.
La regla vale para todas las transacciones, también la coinbase. Y tiene un coste que el propio BIP reconoce: las transacciones bloqueadas por tiempo tardan «approximately an hour longer» en poder confirmarse, porque la mediana de 11 bloques va unos cinco o seis bloques por detrás de la hora real.
Codificación de nSequence
BIP-68 reparte los 32 bits de nSequence así:
- Bit 31 (
SEQUENCE_LOCKTIME_DISABLE_FLAG): si está puesto, nSequence no tiene significado de consenso. - Bit 22 (
SEQUENCE_LOCKTIME_TYPE_FLAG): si está puesto, el valor cuenta unidades de 512 segundos. Si no, bloques. - Bits 0 a 15 (máscara
0x0000ffff): el valor. - Bits 16 a 21 y 23 a 30: sin uso hoy. BIP-68 deja los primeros para ampliar la granularidad o el plazo máximo por soft fork. Los segundos no significan nada mientras el bit 31 esté a 0.
La unidad de 512 s sale de 2⁹ (SEQUENCE_LOCKTIME_GRANULARITY = 9). BIP-68 la eligió porque un bloque tarda de media 600 s, y así el mismo número de bits cubre más o menos el mismo tiempo en los dos modos.
Dos ejemplos, por cuenta propia a partir del BIP. Un plazo de 144 bloques es nSequence 0x00000090. Un plazo de un día por tiempo son 86.400 s entre 512, que da 168,75 unidades. La fórmula del BIP, (1<<22) | (nTime >> 9), trunca a 168 unidades (86.016 s), menos de un día. Para no quedarse corto hay que redondear hacia arriba: 169 unidades, 0x004000A9, que son 86.528 s.
Los topes salen de los 16 bits. En bloques, 65.535, unos 455 días a 600 s por bloque (BIP-68 habla de «1.25 years»). En tiempo, 65.535 × 512 = 33.553.920 s, unos 388 días. El comentario de BIP-68 da nTime < 33,554,431 y «1.06 years», y alguna librería usa ese 33.554.431 como tope. El mayor valor que se puede representar de verdad es 33.553.920. El Conversor de timelocks hace estas conversiones y lee un nSequence o un nLockTime ya escrito.
Las reglas de BIP-68 no se aplican al nSequence de la entrada de la coinbase.
El script no lee el reloj
Un script no puede preguntar «¿qué altura tiene la cadena?». Lo que hace CLTV o CSV es comparar un número del script con un campo de la transacción que lo gasta. Hay dos comprobaciones distintas, en dos sitios.
Primera: el script. En interpreter.cpp, CheckLockTime falla si el tipo del valor (altura o tiempo, a cada lado del umbral) no coincide con el de nLockTime, si el valor es mayor que el nLockTime de la transacción o si la entrada que gasta tiene nSequence final. CheckSequence falla si la versión de la transacción es menor que 2, si la entrada tiene el bit 31 puesto, si el tipo no coincide o si el valor, enmascarado con TYPE_FLAG | MASK, supera al de la entrada. Si el bit 31 del valor del script está puesto, CSV actúa como un NOP.
Segunda: el consenso de bloque. Comprueba que la cadena ya ha pasado lo que la transacción declara. De nLockTime se ocupa IsFinalTx; de nSequence, SequenceLocks.
BIP-65 lo resume así: «By comparing the argument to CHECKLOCKTIMEVERIFY against the nLockTime field, we indirectly verify that the desired block height or block time has been reached». En los créditos atribuye a Gregory Maxwell la idea de comparar con el nLockTime de la transacción y no con la altura o la hora actuales. BIP-112 dice lo mismo para nSequence («we indirectly verify a desired minimum age»). Una consecuencia, que aquí se da como explicación y no como cita: el script se evalúa solo con datos de la propia transacción. El script pone un suelo al bloqueo que la transacción tiene que declarar, y la red impide minarla antes de que la cadena llegue a lo declarado.
Ni CLTV ni CSV sacan el valor de la pila (en el código de referencia de BIP-65, «nLockTime -- nLockTime»), y por eso los scripts ponen DROP detrás. La razón es la activación: los dos ocupan un antiguo OP_NOP, y un nodo sin actualizar tiene que terminar con la misma pila que uno actualizado.
Primer bloque válido
Absoluto. Código de IsFinalTx (tx_verify.cpp): si nLockTime es 0, la transacción es final. Si no, es final cuando nLockTime < (nLockTime < 500.000.000 ? altura del bloque : MTP del bloque anterior). La comparación es estricta: nLockTime marca el último instante inválido. Con nLockTime = 900.000 por altura, la transacción entra como pronto en el bloque 900.001. Por tiempo, hace falta que nLockTime sea menor que el MTP del bloque anterior al que la incluye. En la mempool, CheckFinalTxAtTip usa la altura de la punta más uno y el MTP de la punta.
Con CLTV de valor T, la transacción necesita un nLockTime de al menos T y del mismo tipo. El primer bloque posible es el T+1 por altura, o el primero cuyo bloque anterior tenga un MTP mayor que T. Es decir, el script dice «a partir de T» y la transacción puede entrar un bloque después.
Relativo. SequenceLocks parte de la confirmación de la moneda que se gasta. Por altura, el primer bloque válido es la altura de confirmación más n: una moneda confirmada en el bloque 850.000 con nSequence de 144 se puede gastar desde el 850.144. Con n = 0 no hay restricción. Con n = 1, la transacción no puede entrar en el mismo bloque que la moneda. Por tiempo, el reloj no arranca en la hora de ese bloque, sino en el MTP del bloque anterior al que confirmó la moneda, y la transacción vale cuando ese tiempo más n × 512 s no supera el MTP del bloque anterior al que la incluye.
Cada entrada lleva su propio bloqueo relativo. La transacción queda bloqueada por el más exigente, tomando el máximo de las alturas y de los tiempos. Las entradas con el bit 31 puesto no cuentan.
Requisitos que se olvidan
- nLockTime solo cuenta si alguna entrada tiene nSequence distinto de 0xffffffff. El comentario de
IsFinalTxlo dice: si todas son finales, «nLockTime is ignored». Por esoCheckLockTimefalla si la entrada que gasta es final. Basta con mirar esa entrada, en palabras del código: «Testing if this vin is not final is sufficient». - BIP-68 y CSV exigen versión 2 o superior. En
CheckSequence:if (txTo->version < 2) return false. La versión por defecto de Core es 2 (CURRENT_VERSION). - Un mismo nSequence sirve a tres cosas. Activa nLockTime, señala el reemplazo de RBF según BIP-125 (los nodos con Bitcoin Core 28.0 o posterior aceptan reemplazos sin señal; la 29.0 quitó la opción de desactivarlo) y, si el bit 31 está a 0, impone un plazo relativo.
MAX_SEQUENCE_NONFINAL(0xfffffffe) activa nLockTime y CLTV, pero tiene el bit 31 puesto, así que BIP-68 queda desactivado.
2038 y los límites de older()
CLTV no tiene problema de 2038. Los opcodes numéricos de Script limitan los números a 4 bytes (de −2³¹+1 a 2³¹−1). El comentario de CLTV en Core explica que, con ese límite, habría un problema de 2038 «even though the nLockTime field in transactions themselves is uint32 which only becomes meaningless after the year 2106». Por eso CLTV y CSV aceptan operandos de 5 bytes. nLockTime llega a 2³²−1 = 4.294.967.295, que es el 7 de febrero de 2106 a las 06:28:15 UTC (cuenta propia). BIP-65 habla de 5 bytes válidos «until 2**32-1» y el código actual de «2**39-1, well beyond the 2**32-1 limit of the nLockTime field»: son dos límites distintos, el del campo y el del número de 5 bytes, y el efecto es el mismo.
Donde sí aparece 2038 es en Miniscript. BIP-379 limita after(n) y older(n) a 1 ≤ n < 2³¹, y los fragmentos de tipo B dejan en la pila un valor de hasta 4 bytes. Un after() por tiempo no pasa, pues, de 2.147.483.647: el 19 de enero de 2038 a las 03:14:07 UTC (cuenta propia). La app Android de Nunchuk, por ejemplo, avisa ante fechas de 2038 en adelante y propone pasar a bloqueo por altura. Detalles de Miniscript en su entrada.
older() admite más de lo que el consenso lee. BIP-379 acepta n hasta 2³¹, pero el consenso solo mira el bit 22 y los 16 bits bajos. El caso de older(262800), que se queda en 656 bloques, está en la entrada de Miniscript. Dos casos más extremos salen directamente de CheckSequence: older(65536) (0x10000) queda en 0 tras enmascarar y no bloquea nada, y older(4194304) (0x400000) es modo tiempo con 0 unidades, así que tampoco. La unidad no depende del tamaño de n, sino del bit 22: older(4194304) lo tiene puesto y cuenta en unidades de 512 s, pero older(8388752) (0x800090) no lo tiene: pese a ser un número enorme, cuenta en bloques, y en solo 144. El Conversor de timelocks avisa de estos casos en el modo «Leer un nSequence o un nLockTime».
Para qué se usan
Lightning (BOLT 3). La rama de retardo de to_local es OP_IF <revocationpubkey> OP_ELSE to_self_delay OP_CHECKSEQUENCEVERIFY OP_DROP <local_delayedpubkey> OP_ENDIF OP_CHECKSIG, y se gasta con nSequence igual a to_self_delay. Es CSV porque el retardo se cuenta desde que la commitment se confirma, y así la otra parte tiene siempre el mismo plazo para castigar un estado revocado. BIP-112 explica por qué CLTV no vale: con un bloqueo absoluto, «the channel has a deadline that cannot be pushed back without hitting the blockchain».
La rama de timeout de un HTLC recibido usa en cambio <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP, absoluto, porque todos los saltos de una ruta comparten el mismo reloj. El HTLC ofrecido no lleva CLTV en el script: se cobra con una transacción HTLC-timeout prefirmada por la otra parte con locktime: cltv_expiry, y es ese campo, no un opcode, el que impide adelantarse. La HTLC-success lleva locktime: 0. Con option_anchors, los scripts de HTLC añaden 1 OP_CHECKSEQUENCEVERIFY OP_DROP. La lógica de los pagos enrutados está en HTLC y la de los canales en canales de pago.
BOLT 3 tiene un truco que muestra cómo se combinan los campos. La commitment esconde el número de commitment ofuscado repartido entre dos sitios: el locktime lleva 0x20 en los 8 bits altos y el nSequence de la entrada lleva 0x80. Con 0x20 arriba, el locktime vale al menos 536.870.912, una fecha de 1987 (cuenta propia) siempre pasada, así que no bloquea nada. Con 0x80 arriba, el bit 31 queda puesto y BIP-68 no se aplica, pero como no es 0xffffffff, nLockTime sigue activo.
Recuperación diferida. Una rama con clave de respaldo más older() o after(). La diferencia técnica es la que ya se ha visto: CSV da un reloj por UTXO, que empieza en cada confirmación, y CLTV una fecha común para todas las monedas. El refresco, los plazos y los casos reales están en billeteras con timelock.
Bóvedas. El retardo entre anunciar un gasto y completarlo es un bloqueo relativo. BIP-345 (OP_VAULT) lo hacía con <spend-delay> OP_CHECKSEQUENCEVERIFY en la hoja de trigger. Su estado a 7 de octubre de 2026 es Closed, con BIP-443 propuesto como sustituto. BIP-443 (OP_CHECKCONTRACTVERIFY, de Salvatore Ingala) está en Draft y cita OP_VAULT como aplicación. Ninguna está activa. Sin covenants, una bóveda se puede montar con transacciones prefirmadas más CSV. Los propios BIP citan otros usos: escrow con abogado a tres meses y billeteras de doble factor (BIP-65), escrow con timeout de 30 días y sidechains (BIP-112).
Anti fee sniping. Sin que el usuario lo sepa, la mayoría de transacciones de la billetera de Bitcoin Core ya llevan un nLockTime por altura. DiscourageFeeSniping (wallet/spend.cpp) lo pone igual a la altura actual y, en 1 de cada 10 casos, lo retrasa hasta 99 bloques por privacidad. No lo hace si quien crea la transacción fija su propio nLockTime o el nSequence de alguna entrada. Si el nodo va retrasado, pone 0 para no dejar una «nLockTime fingerprint» única. Exige que ninguna entrada sea final: solo usa 0xfffffffe o 0xfffffffd (el de RBF), y los dos tienen el bit 31 puesto, así que BIP-68 queda desactivado.
Cómo llegaron: activación
Los cuatro cambios fueron soft forks: CLTV y CSV redefinieron OP_NOP2 y OP_NOP3, que antes no hacían nada, de modo que los nodos antiguos siguen aceptando lo que los nuevos validan. Por eso esta entrada vive en gobernanza, junto al proceso de activación de cambios.
- BIP-65 se activó con IsSuperMajority con bloques de versión 4 (umbrales de 750 y 950 de cada 1000). Bitcoin Core fija la altura en 388.381 (
BIP65Height), cuyo bloque lleva la hora del 14 de diciembre de 2015, 17:24:44 UTC (mempool.space, 7 de octubre de 2026). Llegó a los nodos con Bitcoin Core 0.11.2 (13 de noviembre de 2015) y 0.10.4, antes de activarse; en la rama principal entró para la 0.12.0. - BIP-68, 112 y 113 se desplegaron juntos por BIP9, con el bit 0 y fecha de inicio del 1 de mayo de 2016. Core fija la altura en 419.328 (
CSVHeight), con la hora del 4 de julio de 2016, 23:16:01 UTC (mempool.space, 7 de octubre de 2026). Entraron en Core 0.12.1 y están «buried» desde la 0.19.0.
Los cuatro BIP constan como Deployed (repositorio de BIPs, 7 de octubre de 2026). La explicación del despliegue conjunto la dan los propios BIP: BIP-68, 112 y 113 «must be deployed simultaneously».
Qué significa esto para ti
Si lees un script con timelocks, hazte tres preguntas. Primera: ¿es campo o es opcode, absoluto o relativo? Segunda: ¿qué tipo es (altura o tiempo) y en qué unidad? Tercera: ¿qué tiene que declarar la transacción que lo gaste (versión, nSequence, nLockTime)? Con eso se evitan los fallos habituales. Un plazo que cuenta desde otro momento del que crees, un plazo en segundos que sale corto por el truncado, un older() que no bloquea nada, o una transacción de versión 1 que ignora CSV.
Y si vas a depositar fondos detrás de un timelock, comprueba el plazo real en el Conversor de timelocks antes de enviar nada, y prueba el gasto en una red de pruebas. Un timelock no limita adónde va el dinero, solo cuándo puede gastarse por una rama.
Errores habituales
- Creer que CLTV impide gastar hasta que la cadena llegue a X. El opcode compara con el nLockTime de la transacción; quien impide minarla antes de tiempo es la comprobación de bloque (
IsFinalTx). Con T = 900.000, el primer bloque válido es el 900.001. - Pensar que CSV cuenta desde que se crea o se envía la transacción. Cuenta desde que se confirma la salida que se gasta: su altura, o el MTP del bloque anterior en modo tiempo.
- Creer que el bloqueo por tiempo usa la hora del bloque. Usa la mediana de los 11 bloques anteriores (BIP-113), que va cerca de una hora por detrás.
- Suponer que nLockTime se aplica siempre. Se ignora si todas las entradas tienen nSequence 0xffffffff. Y BIP-68 y CSV se ignoran o fallan con versión 1, y BIP-68 no se aplica si la entrada tiene el bit 31 puesto.
- Calcular el modo tiempo como 65.535 × 600 s. La unidad es de 512 s, y la fórmula del BIP trunca hacia abajo: un día son 169 unidades, no 168.
- Creer que el 2038 es un problema de CLTV. CLTV acepta operandos de 5 bytes y nLockTime llega a 2106. El límite de 2038 viene de Miniscript (n < 2³¹) y de cualquier aritmética de 4 bytes.
- Creer que
older()admite cualquier número hasta 2³¹. La sintaxis sí, pero el consenso solo lee el bit 22 y los 16 bits bajos.older(65536)no bloquea nada. - Confundir un timelock con un covenant o con OP_VAULT. CLTV y CSV no restringen el destino del dinero, solo cuándo puede gastarse por una rama.
Conceptos relacionados
Fuentes primarias
- Peter Todd, «BIP-65: OP_CHECKLOCKTIMEVERIFY» (2014)
- Friedenbach, BtcDrak, Dorier y kinoshitajona, «BIP-68: Relative lock-time using consensus-enforced sequence numbers» (2015)
- BtcDrak, Friedenbach y Lombrozo, «BIP-112: CHECKSEQUENCEVERIFY» (2015)
- Kerin y Friedenbach, «BIP-113: Median time-past as endpoint for lock-time calculations» (2015)
- Wuille, Poelstra, Kanjalkar, Poinsot y Chow, «BIP-379: Miniscript» (rango de after y older)
- Bitcoin Core, src/script/interpreter.cpp (CheckLockTime y CheckSequence)
- Bitcoin Core, src/consensus/tx_verify.cpp (IsFinalTx y SequenceLocks)
- Bitcoin Core, src/primitives/transaction.h (banderas de nSequence y versión)
- Bitcoin Core, src/script/script.h (LOCKTIME_THRESHOLD)
- Bitcoin Core, src/validation.cpp (CheckFinalTxAtTip)
- Bitcoin Core, doc/bips.md (versiones que incorporan cada BIP)
- Bitcoin Core, src/kernel/chainparams.cpp (BIP65Height y CSVHeight)
- Bitcoin Core 0.11.2, notas de la versión (13 de noviembre de 2015)
- Bitcoin v0.2.0, main.cpp (AcceptBlock: «contains a non-final transaction»)
- Bitcoin Core 28.0, notas de la versión (full-RBF por defecto)
- Bitcoin Core, src/wallet/spend.cpp (DiscourageFeeSniping)
- BOLT 3, «Bitcoin Transaction and Script Formats»
- BIP-345, «OP_VAULT» (Closed)
- Ingala, «BIP-443: OP_CHECKCONTRACTVERIFY» (Draft)
- mempool.space, API de bloques (hora del bloque 388.381)
- mempool.space, API de bloques (hora del bloque 419.328)
- Nunchuk Android, OnChainSetUpTimelockViewModel.kt (aviso de 2038)