高級
OP_CHECKSEQUENCEVERIFY
了解 OP_CSV 相對時間鎖操作碼,實現基於區塊數或時間的交易延遲。
12 分鐘
OP_CHECKSEQUENCEVERIFY (OP_CSV) 是 BIP-112 引入的相對時間鎖操作碼, 允許腳本驗證輸入的 nSequence 值,實現相對於交易確認時間的延遲機制。 這是閃電網路等二層協議的關鍵基礎設施。
基本概念
OP_CSV vs OP_CLTV:
OP_CHECKLOCKTIMEVERIFY (CLTV):
- 絕對時間鎖
- "這筆交易在區塊 850000 之後才能花費"
- "這筆交易在 2025-01-01 之後才能花費"
OP_CHECKSEQUENCEVERIFY (CSV):
- 相對時間鎖
- "這筆交易在輸入被確認後 144 個區塊才能花費"
- "這筆交易在輸入被確認後 1 天才能花費"
關鍵區別:
- CLTV: 基於絕對時間/高度
- CSV: 基於輸入 UTXO 確認後的相對時間 BIP-68 和 BIP-112
BIP-68: nSequence 的相對時間鎖語義
- 定義 nSequence 如何編碼相對時間鎖
- 共識層面的強制執行
BIP-112: OP_CHECKSEQUENCEVERIFY
- 腳本層面的相對時間鎖驗證
- 允許在腳本中檢查 nSequence
BIP-113: 中位時間過去 (MTP)
- 使用過去 11 個區塊的中位時間
- 防止礦工操縱時間戳
// 三個 BIP 共同啟用於 2016 年 7 月
// 軟分叉高度: 419328 nSequence 編碼
nSequence 是 32 位整數:
位元 31 (禁用標誌):
0 = 啟用相對時間鎖
1 = 禁用相對時間鎖
位元 22 (類型標誌):
0 = 區塊數
1 = 時間(512 秒為單位)
位元 0-15 (值):
區塊數: 0 - 65535 區塊
時間: 0 - 65535 × 512 秒 ≈ 388 天
// 編碼格式
┌────┬────────────┬────┬────────────────┐
│ 31 │ 30-23 │ 22 │ 21-16 │ 15-0 │
│禁用│ 保留(必須0)│類型│ 保留 │ 值 │
└────┴────────────┴────┴────────────────┘
// 範例
0x00000090 = 144 區塊 (約 1 天)
0x00400090 = 144 × 512 秒 = 73728 秒 ≈ 20.5 小時 腳本示例
基本相對時間鎖
// 144 區塊(約 1 天)後才能花費
OP_144
OP_CHECKSEQUENCEVERIFY
OP_DROP
<pubkey>
OP_CHECKSIG
// 執行流程:
1. 推入 144 到堆疊
2. CSV 檢查 nSequence >= 144
3. 如果檢查失敗,交易無效
4. DROP 移除堆疊頂部的 144
5. 正常的簽名驗證 閃電網路承諾交易
// 本地輸出(to_local)腳本
OP_IF
// 撤銷路徑:對方可以使用撤銷密鑰立即花費
<revocationpubkey>
OP_ELSE
// 延遲路徑:自己需要等待後才能花費
<to_self_delay>
OP_CHECKSEQUENCEVERIFY
OP_DROP
<local_delayedpubkey>
OP_ENDIF
OP_CHECKSIG
// to_self_delay 典型值: 144 區塊(1 天)
// 這給對方時間來廣播撤銷交易 HTLC (Hash Time Locked Contract)
// HTLC 腳本示例
OP_IF
// Hash 路徑:知道 preimage 可以立即領取
OP_HASH160 <payment_hash> OP_EQUALVERIFY
<remote_htlcpubkey>
OP_ELSE
// 超時路徑:超時後退款
<cltv_expiry>
OP_CHECKLOCKTIMEVERIFY
OP_DROP
<local_htlcpubkey>
OP_ENDIF
OP_CHECKSIG
// 結合 CSV 的二階段 HTLC
// 第一階段使用 CLTV
// 第二階段使用 CSV 時間類型比較
// 區塊數 vs 時間
區塊數模式 (位元 22 = 0):
優點:
- 更可預測
- 不受時間戳操縱影響
- 適合需要精確區塊數的場景
缺點:
- 區塊時間可能變化
- 144 區塊可能是 20-30 小時
時間模式 (位元 22 = 1):
優點:
- 更接近實際時間
- 適合需要特定時間延遲的場景
缺點:
- 精度只有 512 秒
- 受 MTP 規則影響
// 閃電網路使用區塊數模式 驗證規則
OP_CSV 驗證邏輯:
1. 檢查堆疊頂部值
- 如果 < 0,失敗
- 如果 > 0x80000000,視為禁用
2. 檢查類型匹配
- 腳本值和 nSequence 必須使用相同類型
- 都是區塊數,或都是時間
3. 檢查值
- nSequence 的值必須 >= 腳本值
4. 檢查 nSequence 禁用位
- 如果 nSequence 禁用相對鎖,失敗
// 偽代碼
def verify_csv(stack_value, nSequence):
if stack_value < 0:
return False
if stack_value & 0x80000000: # 禁用位設置
return True # 跳過檢查
# 類型必須匹配
stack_type = stack_value & 0x00400000
seq_type = nSequence & 0x00400000
if stack_type != seq_type:
return False
# 值比較
stack_masked = stack_value & 0x0000FFFF
seq_masked = nSequence & 0x0000FFFF
return seq_masked >= stack_masked 與交易版本的關係
// 交易版本要求
BIP-68 相對時間鎖只在交易版本 >= 2 時啟用
版本 1 交易:
- nSequence 不強制執行相對時間鎖
- 仍可用於 RBF 信號
版本 2 交易:
- nSequence 強制執行相對時間鎖
- 這是現代錢包的默認版本
// 檢查
bitcoin-cli decoderawtransaction <hex>
{
"version": 2, // 必須 >= 2
"vin": [{
"sequence": 144 // 相對時間鎖生效
}]
} 實際應用
閃電網路通道
閃電網路使用 CSV 的場景:
1. 承諾交易 to_local 輸出
- 防止單方面關閉後立即提款
- 給對方時間廣播懲罰交易
2. HTLC 超時路徑
- 二階段超時機制
- 先 CLTV 再 CSV
3. 錨點輸出
- 允許手續費調整
- 使用 CSV 延遲
典型延遲值:
- to_self_delay: 144-2016 區塊
- 由通道參數協商決定 保管庫 (Vault)
// 簡單保管庫設計
// 提款需要兩步,中間有延遲
解鎖腳本:
OP_IF
// 緊急恢復路徑(需要多簽)
2 <key1> <key2> <key3> 3 OP_CHECKMULTISIG
OP_ELSE
// 正常提款路徑(需要延遲)
<144>
OP_CHECKSEQUENCEVERIFY
OP_DROP
<hot_key>
OP_CHECKSIG
OP_ENDIF
使用流程:
1. 發起提款交易(廣播到網路)
2. 等待 144 區塊確認
3. 如果發現異常,使用緊急路徑取消
4. 正常情況下,延遲後完成提款 程式實現
// Python: 編碼相對時間鎖
def encode_sequence_blocks(blocks):
"""編碼區塊數相對時間鎖"""
if blocks < 0 or blocks > 0xFFFF:
raise ValueError("Invalid block count")
return blocks # 類型位為 0
def encode_sequence_time(seconds):
"""編碼時間相對時間鎖"""
if seconds < 0:
raise ValueError("Invalid time")
# 轉換為 512 秒單位
units = (seconds + 511) // 512 # 向上取整
if units > 0xFFFF:
raise ValueError("Time too large")
return 0x00400000 | units # 設置類型位
def decode_sequence(seq):
"""解碼 nSequence"""
if seq & 0x80000000:
return {"disabled": True}
is_time = bool(seq & 0x00400000)
value = seq & 0x0000FFFF
if is_time:
return {
"type": "time",
"seconds": value * 512,
"human": f"{value * 512 / 3600:.1f} hours"
}
else:
return {
"type": "blocks",
"blocks": value,
"human": f"~{value * 10 / 60:.1f} hours"
}
# 使用示例
print(encode_sequence_blocks(144)) # 144
print(encode_sequence_time(86400)) # 0x004000A8 (1天) 安全考量
- 類型混淆:確保腳本和 nSequence 使用相同類型
- 版本檢查:交易版本必須 >= 2
- 禁用位:注意 nSequence 禁用位的處理
- 最大值:相對鎖最大約 388 天
- MTP:時間模式使用中位時間,非實際時間
與 RBF 的互動
// nSequence 的多重用途
nSequence < 0xFFFFFFFE:
- 啟用 RBF(可替換)
- 如果版本 >= 2,也啟用相對時間鎖
nSequence = 0xFFFFFFFE:
- 禁用 RBF
- 但仍啟用 nLockTime
nSequence = 0xFFFFFFFF:
- 禁用 RBF
- 禁用 nLockTime
// 相對時間鎖值通常遠小於這些值
// 所以同時啟用 RBF 和相對鎖 相關 BIP
- BIP-68:nSequence 相對時間鎖共識規則
- BIP-112:OP_CHECKSEQUENCEVERIFY 操作碼
- BIP-113:中位時間過去 (MTP) 用於時間鎖
- BIP-65:OP_CHECKLOCKTIMEVERIFY(絕對時間鎖)
已複製連結