跳至主要內容
協議 高級

Script

Bitcoin Script

又稱:比特幣腳本

Bitcoin Script 是比特幣交易中用於定義花費條件的堆疊式程式語言。每個 UTXO 都包含一個鎖定腳本(scriptPubKey),指定誰可以花費這筆資金;而花費時需要提供解鎖腳本(scriptSig)來滿足這些條件。

設計哲學

中本聰刻意將 Script 設計為圖靈不完備

設計選擇原因
無迴圈防止無限執行,避免 DoS 攻擊
無狀態確保驗證結果的確定性
有限操作碼減少攻擊面,提高安全性
堆疊式執行簡單可預測,易於驗證

這種設計確保每個腳本執行都能在有限時間內完成,並且相同的輸入永遠產生相同的結果。

執行機制

Script 使用後進先出(LIFO)堆疊執行:

執行流程:scriptSig + scriptPubKey

   從左到右依序執行

   資料推入堆疊,操作碼處理堆疊

   最終堆疊頂部為 TRUE (非零) = 有效

執行範例:P2PKH 驗證

scriptSig:    <sig> <pubKey>
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

執行過程:
1. <sig>           → 堆疊: [sig]
2. <pubKey>        → 堆疊: [sig, pubKey]
3. OP_DUP          → 堆疊: [sig, pubKey, pubKey]
4. OP_HASH160      → 堆疊: [sig, pubKey, hash(pubKey)]
5. <pubKeyHash>    → 堆疊: [sig, pubKey, hash(pubKey), pubKeyHash]
6. OP_EQUALVERIFY  → 驗證兩個 hash 相等,堆疊: [sig, pubKey]
7. OP_CHECKSIG     → 驗證簽名,堆疊: [TRUE]

常見操作碼分類

堆疊操作

操作碼十六進制功能
OP_DUP0x76複製堆疊頂部元素
OP_DROP0x75移除堆疊頂部元素
OP_SWAP0x7c交換頂部兩個元素
OP_ROT0x7b旋轉頂部三個元素

密碼學操作

操作碼十六進制功能
OP_SHA2560xa8SHA-256 雜湊
OP_HASH1600xa9SHA-256 後 RIPEMD-160
OP_HASH2560xaa雙重 SHA-256
OP_CHECKSIG0xac驗證 ECDSA 簽名
OP_CHECKMULTISIG0xae驗證多重簽名

流程控制

操作碼十六進制功能
OP_IF0x63條件執行開始
OP_ELSE0x67條件分支
OP_ENDIF0x68條件執行結束
OP_VERIFY0x69驗證頂部為真,否則失敗
OP_RETURN0x6a標記輸出不可花費

時間鎖操作

操作碼十六進制功能
OP_CHECKLOCKTIMEVERIFY0xb1絕對時間鎖(BIP-65)
OP_CHECKSEQUENCEVERIFY0xb2相對時間鎖(BIP-112)

標準腳本類型

P2PKH(Pay-to-Public-Key-Hash)

最傳統的地址格式,以 1 開頭:

鎖定腳本(25 bytes):
OP_DUP OP_HASH160 <20-byte pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

解鎖腳本:
<signature> <publicKey>

P2SH(Pay-to-Script-Hash)

支援複雜腳本,地址以 3 開頭:

鎖定腳本(23 bytes):
OP_HASH160 <20-byte scriptHash> OP_EQUAL

解鎖腳本:
<data> ... <redeemScript>

P2WPKH(Pay-to-Witness-Public-Key-Hash)

SegWit 原生格式,地址以 bc1q 開頭:

鎖定腳本(22 bytes):
OP_0 <20-byte pubKeyHash>

見證資料:
<signature> <publicKey>

P2WSH(Pay-to-Witness-Script-Hash)

SegWit 腳本格式:

鎖定腳本(34 bytes):
OP_0 <32-byte scriptHash>

見證資料:
<data> ... <witnessScript>

P2TR(Pay-to-Taproot)

Taproot 格式,地址以 bc1p 開頭:

鎖定腳本(34 bytes):
OP_1 <32-byte tweaked-pubKey>

花費方式:
- 金鑰路徑:直接 Schnorr 簽名
- 腳本路徑:揭示 Tapscript + 控制區塊

進階腳本應用

多重簽名(2-of-3)

鎖定腳本:
OP_2 <pubKey1> <pubKey2> <pubKey3> OP_3 OP_CHECKMULTISIG

解鎖腳本:
OP_0 <sig1> <sig2>

注意:OP_0 是由於 OP_CHECKMULTISIG 的歷史 bug,會多消耗一個堆疊元素。

時間鎖合約

# 2024年1月1日後才能花費
OP_CHECKLOCKTIMEVERIFY:
<locktime: 1704067200> OP_CHECKLOCKTIMEVERIFY OP_DROP
<pubKey> OP_CHECKSIG

# 100 個區塊後才能花費
OP_CHECKSEQUENCEVERIFY:
<sequence: 100> OP_CHECKSEQUENCEVERIFY OP_DROP
<pubKey> OP_CHECKSIG

雜湊時間鎖合約(HTLC)

閃電網路的核心機制:

OP_IF
    # 知道 preimage 的人可以花費
    OP_HASH160 <hash> OP_EQUALVERIFY
    <receiverPubKey> OP_CHECKSIG
OP_ELSE
    # 超時後發送者可以取回
    <timeout> OP_CHECKLOCKTIMEVERIFY OP_DROP
    <senderPubKey> OP_CHECKSIG
OP_ENDIF

Script 大小限制

限制類型數值
腳本最大長度10,000 bytes
堆疊元素最大數量1,000
單個元素最大長度520 bytes
操作碼執行上限201(非推送操作)
多簽金鑰上限20 個(傳統) / 無限制(Tapscript)

Tapscript 改進

Taproot 引入的 Tapscript 對傳統 Script 做了多項改進:

  1. Schnorr 簽名:使用 OP_CHECKSIGADD 替代 OP_CHECKMULTISIG
  2. 移除限制:無多簽金鑰數量限制
  3. 批次驗證:多個簽名可同時驗證,提高效率
  4. 成功操作碼OP_SUCCESSx 預留未來升級空間
# Tapscript 多簽(更高效)
<pubKey1> OP_CHECKSIG
<pubKey2> OP_CHECKSIGADD
<pubKey3> OP_CHECKSIGADD
OP_2 OP_EQUAL

安全注意事項

  1. 避免重複使用地址:每個地址應只使用一次
  2. 注意 OP_RETURN:資料輸出不可花費
  3. 時間鎖精度:區塊時間可被礦工操控 ±2 小時
  4. 腳本複雜度:複雜腳本增加手續費和錯誤風險

開發工具

  • btcdeb:Script 除錯器
  • miniscript:高階 Script 編譯語言
  • Bitcoin Coredecodescript RPC 命令
  • bdk/rust-bitcoin:Rust Script 處理庫
已複製到剪貼簿