跳至主要內容
高級

OP_CHECKLOCKTIMEVERIFY

了解 OP_CLTV 絕對時間鎖操作碼,實現基於區塊高度或時間戳的交易鎖定。

10 分鐘

OP_CHECKLOCKTIMEVERIFY (OP_CLTV) 是 BIP-65 引入的絕對時間鎖操作碼, 允許在腳本中強制執行 nLockTime,確保輸出在特定時間或區塊高度之前無法花費。

基本概念

OP_CLTV 功能:
- 驗證交易的 nLockTime >= 腳本指定值
- 確保交易在指定時間/高度之前無效
- 與 nLockTime 協同工作

使用場景:
- 定時釋放資金
- HTLC 超時機制
- 繼承計劃
- 支付通道超時

// 操作碼編號: 0xb1 (177)
// 原本是 OP_NOP2,軟分叉升級為 CLTV

時間類型

nLockTime 有兩種模式:

區塊高度模式 (值 < 500000000):
- 值表示區塊高度
- 交易在該高度之前無效
- 例: 850000 表示區塊 850000

Unix 時間戳模式 (值 >= 500000000):
- 值表示 Unix 時間戳
- 交易在該時間之前無效
- 例: 1704067200 表示 2024-01-01 00:00:00 UTC

// 分界值 500000000 大約對應 1985 年
// 比特幣創始區塊是 2009 年,所以不會混淆

重要: 腳本值和 nLockTime 必須使用相同類型

腳本示例

簡單時間鎖

// 在區塊 850000 之後才能花費
<850000>
OP_CHECKLOCKTIMEVERIFY
OP_DROP
<pubkey>
OP_CHECKSIG

// 執行流程:
1. 推入 850000 到堆疊
2. CLTV 檢查 nLockTime >= 850000
3. 如果 nLockTime < 850000,交易無效
4. DROP 移除堆疊頂部的 850000
5. 正常簽名驗證

// 花費此輸出的交易必須設置:
// nLockTime >= 850000
// nSequence < 0xFFFFFFFF (啟用 nLockTime)

Unix 時間戳鎖

// 2025-01-01 之後才能花費
// Unix timestamp: 1735689600

<1735689600>
OP_CHECKLOCKTIMEVERIFY
OP_DROP
<pubkey>
OP_CHECKSIG

// 注意: 時間使用區塊的 MTP (Median Time Past)
// 不是實際當前時間
// MTP 是過去 11 個區塊時間戳的中位數

帶備用路徑的時間鎖

// 雙路徑: 立即多簽或延遲單簽
OP_IF
    // 路徑 A: 2-of-3 多簽可立即花費
    2 <pubkey1> <pubkey2> <pubkey3> 3 OP_CHECKMULTISIG
OP_ELSE
    // 路徑 B: 單簽需要等待
    <850000>
    OP_CHECKLOCKTIMEVERIFY
    OP_DROP
    <backup_pubkey>
    OP_CHECKSIG
OP_ENDIF

使用場景:
- 正常情況使用多簽(公司支付)
- 緊急情況等待後使用備用密鑰(繼承)

HTLC 中的應用

// Hash Time Locked Contract

OP_IF
    // Hash 路徑: 知道原像可領取
    OP_HASH160
    <payment_hash>
    OP_EQUALVERIFY
    <receiver_pubkey>
OP_ELSE
    // 超時路徑: 超時後退款
    <timeout_block>
    OP_CHECKLOCKTIMEVERIFY
    OP_DROP
    <sender_pubkey>
OP_ENDIF
OP_CHECKSIG

工作原理:
1. 接收者知道 preimage 可以立即領取
2. 如果接收者不領取,發送者超時後可退款
3. 這是閃電網路跨鏈支付的基礎

驗證規則

OP_CLTV 驗證邏輯:

1. 堆疊檢查
   - 堆疊不能為空
   - 頂部值不能為負數

2. 類型一致性
   - 腳本值 < 500000000 且 nLockTime < 500000000 (都是區塊)
   - 腳本值 >= 500000000 且 nLockTime >= 500000000 (都是時間)
   - 類型不匹配則失敗

3. 值比較
   - nLockTime >= 腳本值

4. nSequence 檢查
   - 輸入的 nSequence 不能是 0xFFFFFFFF
   - 否則 nLockTime 被忽略

// 偽代碼
def verify_cltv(stack_top, tx):
    if stack_top < 0:
        return False

    lock_time = tx.nLockTime

    # 類型檢查
    if (stack_top < 500000000) != (lock_time < 500000000):
        return False

    # 值檢查
    if lock_time < stack_top:
        return False

    # 序列檢查
    if tx.inputs[current_input].nSequence == 0xFFFFFFFF:
        return False

    return True

與 nLockTime 的關係

nLockTime 和 OP_CLTV 的區別:

nLockTime (交易級別):
- 交易字段
- 可以被發送者任意設置
- 對接收者沒有保證

OP_CLTV (腳本級別):
- 鎖定在輸出腳本中
- 強制花費交易必須設置足夠的 nLockTime
- 對接收者有密碼學保證

示例:
1. Alice 創建輸出: CLTV 850000 後才能花費
2. Bob 想花費此輸出
3. Bob 必須創建 nLockTime >= 850000 的交易
4. 該交易在區塊 850000 之前無法被礦工確認
5. Alice 獲得時間鎖保證

實際應用案例

支付通道超時

// 簡單支付通道退款機制

資金鎖定腳本:
OP_IF
    // 雙方同意: 立即結算
    2 <alice_key> <bob_key> 2 OP_CHECKMULTISIG
OP_ELSE
    // 超時: Alice 可以取回資金
    <timeout>
    OP_CHECKLOCKTIMEVERIFY
    OP_DROP
    <alice_key>
    OP_CHECKSIG
OP_ENDIF

使用流程:
1. Alice 鎖定 1 BTC 到通道
2. Alice 和 Bob 可以隨時雙簽結算
3. 如果 Bob 消失,Alice 等待超時後取回資金

繼承計劃

// 數字遺產規劃

繼承腳本:
OP_IF
    // 所有者隨時可用
    <owner_pubkey>
    OP_CHECKSIG
OP_ELSE
    // 繼承人在 2 年後可用
    <two_years_later>
    OP_CHECKLOCKTIMEVERIFY
    OP_DROP
    <heir_pubkey>
    OP_CHECKSIG
OP_ENDIF

運作方式:
1. 所有者正常使用自己的密鑰
2. 定期將資金移動到新的類似腳本(重置計時器)
3. 如果所有者失能,繼承人等待 2 年後可取回
4. "心跳機制" 證明所有者仍活躍

編程示例

// Python: 創建 CLTV 腳本

from bitcoin.core.script import *
import struct

def create_cltv_script(locktime, pubkey):
    """創建簡單 CLTV 腳本"""
    return CScript([
        locktime,
        OP_CHECKLOCKTIMEVERIFY,
        OP_DROP,
        pubkey,
        OP_CHECKSIG
    ])

def create_htlc_script(payment_hash, receiver_key, sender_key, timeout):
    """創建 HTLC 腳本"""
    return CScript([
        OP_IF,
            OP_HASH160,
            payment_hash,
            OP_EQUALVERIFY,
            receiver_key,
        OP_ELSE,
            timeout,
            OP_CHECKLOCKTIMEVERIFY,
            OP_DROP,
            sender_key,
        OP_ENDIF,
        OP_CHECKSIG
    ])

# 使用
locktime = 850000
script = create_cltv_script(locktime, pubkey)

# 花費時設置交易
tx.nLockTime = 850000
tx.vin[0].nSequence = 0xFFFFFFFE  # 啟用 nLockTime

安全考量

  • 類型一致:確保腳本和 nLockTime 使用相同類型
  • MTP 延遲:時間模式使用 MTP,比實際時間晚約 1 小時
  • nSequence:必須 < 0xFFFFFFFF 才能啟用 nLockTime
  • 重放攻擊:時間鎖過後,舊簽名仍然有效
  • 區塊重組:高度可能因重組而改變

歷史背景

BIP-65 歷史:

2014 年: Peter Todd 提出 BIP-65
2015 年 12 月: 軟分叉啟用 (區塊 388381)

OP_NOP2 → OP_CHECKLOCKTIMEVERIFY:
- 舊節點: 視為 NOP,不做任何事
- 新節點: 強制執行時間鎖驗證
- 向後兼容的軟分叉升級

意義:
- 首次在腳本層面支持時間鎖
- 為閃電網路和智能合約奠定基礎
- 證明了軟分叉升級 Script 的可行性

相關概念

  • BIP-65:OP_CHECKLOCKTIMEVERIFY 規範
  • nLockTime:交易級別的時間鎖
  • OP_CSV:相對時間鎖(BIP-112)
  • MTP:中位時間過去(BIP-113)
  • HTLC:哈希時間鎖合約
已複製連結
已複製到剪貼簿