比特幣 Script 互動式模擬器教育指南:動手玩轉比特幣智能合約
透過互動式模擬器實作比特幣腳本語言。從堆疊機原理開始,逐步介紹基本操作碼、P2PKH、P2SH、HTLC 等常見腳本類型,最後涵蓋 Taproot 與 MAST 等最新升級。包含完整程式碼範例和逐步執行追蹤,適合想深入理解比特幣智能合約運作原理的開發者和愛好者。
比特幣 Script 互動式模擬器教育指南:動手玩轉比特幣智能合約
為什麼要學比特幣腳本?
我第一次看到比特幣腳本的時候,整個人是懵的。那堆看起來像亂碼的字串:OP_DUP OP_HASH160 88ac——這到底是什麼鬼?
後來我花了幾個禮拜啃文件、做實驗,總算搞懂了。說實話,一旦你開竅了,比特幣腳本其實沒那麼可怕。
這篇文章的目標很簡單:用互動式的方式,讓你真正理解比特幣腳本是怎麼運作的。
我們會從最基本的堆疊操作開始,一路玩到多簽名合約和時間鎖。你可以在腦中模擬執行過程,或者找個線上的比特幣腳本模擬器實際跑跑看。
準備好了嗎?讓我們開始。
第一關:理解堆疊機
什麼是堆疊?
堆疊(Stack)是一種資料結構,遵循「後進先出」(LIFO)的原則。
想像你有一疊盤子:
- Push(推入):把新盤子放在最上面
- Pop(彈出):拿走最上面的盤子
比特幣腳本就是用這種方式運作的。
逆波蘭表示法
比特幣腳本使用逆波蘭表示法(Reverse Polish Notation, RPN),又稱後綴表示法。
普通數學表達式:
3 + 4
逆波蘭表示法:
3 4 +
好處是:你不需要括號來指定運算順序。* 5 只會影響堆疊上最上面的兩個元素。
實驗一:基本算術運算
讓我們從最簡單的開始。
表達式:(3 + 4) * 2
逆波蘭表示法:
3 4 OP_ADD 2 OP_MUL
執行步驟追蹤:
步驟 操作 堆疊狀態
─────────────────────────────────
1 Push 3 [3]
2 Push 4 [3, 4]
3 OP_ADD 彈出 4, 3 → 計算 3+4=7 → Push 7 [7]
4 Push 2 [7, 2]
5 OP_MUL 彈出 2, 7 → 計算 7*2=14 → Push 14 [14]
最終堆疊頂部是 14,正確!
表達式:10 / (3 - 1)
逆波蘭表示法:
10 3 1 OP_SUB OP_DIV
執行步驟追蹤:
步驟 操作 堆疊狀態
──────────────────────────────────────
1 Push 10 [10]
2 Push 3 [10, 3]
3 Push 1 [10, 3, 1]
4 OP_SUB 彈出 1, 3 → 計算 3-1=2 → Push 2 [10, 2]
5 OP_DIV 彈出 2, 10 → 計算 10/2=5 → Push 5 [5]
最終結果是 5。
常見算術操作碼
| 操作碼 | 名稱 | 說明 |
|---|---|---|
| OP_ADD | 加法 | 彈出兩個值,計算 a + b,推回結果 |
| OP_SUB | 減法 | 彈出兩個值,計算 a - b |
| OP_MUL | 乘法 | 彈出兩個值,計算 a * b |
| OP_DIV | 除法 | 彈出兩個值,計算 a / b(整除) |
| OP_MOD | 取模 | 彈出兩個值,計算 a % b |
| OP_1ADD | 加1 | 堆疊頂部 + 1 |
| OP_1SUB | 減1 | 堆疊頂部 - 1 |
實驗二:堆疊操作
OP_DUP:複製頂部
有時候你需要堆疊頂部的值,但又不想把它彈出。這時候用 OP_DUP。
操作 堆疊變化
─────────────────────
執行前: [a, b, c] (c 在頂部)
執行: OP_DUP
執行後: [a, b, c, c]
OP_DROP:丟棄頂部
執行前: [a, b, c]
執行: OP_DROP
執行後: [a, b]
OP_SWAP:交換前兩個
執行前: [a, b, c]
執行: OP_SWAP
執行後: [a, c, b]
OP_OVER:複製倒數第二個
執行前: [a, b, c]
執行: OP_OVER
執行後: [a, b, c, b]
實驗練習
挑戰 1:計算 ((2 + 3) * 4) + 5
提示:先算 2+3,然後乘 4,最後加 5。
答案:
2 3 OP_ADD 4 OP_MUL 5 OP_ADD
追蹤:
[2]
[2, 3]
[5] # 2+3=5
[5, 4]
[20] # 5*4=20
[20, 5]
[25] # 20+5=25
挑戰 2:交換堆疊前兩個元素,然後複製
[a, b, c] → [a, c, b] → [a, c, b, b]
腳本:
OP_SWAP OP_DUP
實驗三:條件執行
OP_IF:條件分支
OP_IF 會檢查堆疊頂部是否為 TRUE(非零)。如果是,執行 if 分支的指令;否則,執行 else 分支(如果有的話)。
基本結構:
OP_IF
<指令1>
<指令2>
OP_ELSE
<指令3>
<指令4>
OP_ENDIF
實驗:簡單的條件判斷
腳本:
5 OP_IF
OP_1
OP_ELSE
OP_0
OP_ENDIF
因為 5 是非零值(TRUE),所以執行 if 分支:
步驟 操作 堆疊狀態
─────────────────────────────
1 Push 5 [5]
2 OP_IF 檢查到 5 是 TRUE,執行 if 分支
3 OP_1 [1]
4 OP_ENDIF 結束條件,堆疊頂部 [1]
如果把 5 改成 0:
0 OP_IF
OP_1
OP_ELSE
OP_0
OP_ENDIF
結果會是 [0]。
巢狀條件
條件可以巢狀:
OP_IF
<外層 if>
OP_IF
<內層 if>
OP_ELSE
<內層 else>
OP_ENDIF
OP_ELSE
<外層 else>
OP_ENDIF
實驗四:P2PKH——最常見的比特幣地址
什麼是 P2PKH?
Pay to Public Key Hash(P2PKH)是最傳統的比特幣地址格式,以「1」開頭。99% 的比特幣交易都是這個格式。
鎖定腳本
當你「發送」比特幣到一個 P2PKH 地址時,你實際上是把比特幣鎖定在一個腳本裡:
OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
是接收者的公鑰哈希(20 位元組)。
解鎖腳本
要花費這個 UTXO,必須提供:
<signature> <pubKey>
完整驗證流程
把解鎖腳本和鎖定腳本串在一起:
<signature> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
執行步驟:
步驟 操作 堆疊狀態
──────────────────────────────────────────────────
1 Push signature [sig]
2 Push pubKey [sig, pubKey]
3 OP_DUP [sig, pubKey, pubKey]
4 OP_HASH160 [sig, pubKey, pubKeyHash]
5 Push pubKeyHash [sig, pubKey, pubKeyHash, pubKeyHash']
6 OP_EQUALVERIFY [sig, pubKey] (如果相等,繼續;否則失敗)
7 OP_CHECKSIG [TRUE/FALSE]
為什麼需要 OP_DUP?
注意到 OP_DUP 把 pubKey 複製了一份。為什麼?
因為 OP_CHECKSIG 需要兩個東西:
- 簽名(堆疊上的)
- 公鑰(在堆疊上的)
OP_EQUALVERIFY 會消耗一個 pubKey 來比較。如果沒有 OP_DUP,OP_CHECKSIG 就找不到公鑰了。
實驗五:P2SH——支付到腳本哈希
為什麼需要 P2SH?
P2PKH 很棒,但有個問題:如果你想要更複雜的鎖定條件(比如多簽名),發送方就必須知道完整的腳本內容。
P2SH 解決了這個問題:發送方只需要知道一個「腳本哈希」,接收方才需要知道完整的腳本內容。
格式
P2SH 地址以「3」開頭。
鎖定腳本:
OP_HASH160 <scriptHash> OP_EQUAL
是 20 位元組的哈希(通常是 SHA-256 + RIPEMD-160)。
實驗:2-of-3 多簽名
假設 Alice、Bob、Charlie 三個人要用 2-of-3 多簽名來管理資金。任何兩人同意就可以花費。
步驟 1:創建 redeemScript
OP_2 <pubKey1> <pubKey2> <pubKey3> OP_3 OP_CHECKMULTISIG
(注意:OP_CHECKMULTISIG 會消耗一個多餘的元素,所以前面要放一個 OP_0)
步驟 2:計算腳本哈希
把上面的腳本做 SHA-256,然後 RIPEMD-160,得到 20 位元組的哈希。
步驟 3:鎖定比特幣
發送方只需要知道這個哈希:
OP_HASH160 <scriptHash> OP_EQUAL
步驟 4:解鎖
要花費的人需要提供:
<sig1> <sig2> OP_0 <redeemScript>
為什麼要有 OP_0?因為比特幣早期的一個 bug,OP_CHECKMULTISIG 會消耗一個多餘的堆疊元素。放 OP_0 只是為了補償這個 bug。
執行流程
解鎖腳本 + 鎖定腳本:
<sig1> <sig2> OP_0 <redeemScript> OP_HASH160 <scriptHash> OP_EQUAL
步驟 操作 堆疊狀態
──────────────────────────────────────────────────
1 Push sig1 [sig1]
2 Push sig2 [sig1, sig2]
3 Push OP_0 [sig1, sig2, 0]
4 Push redeemScript [sig1, sig2, 0, redeemScript]
5 OP_HASH160 [sig1, sig2, 0, scriptHash']
6 Push scriptHash [sig1, sig2, 0, scriptHash', scriptHash]
7 OP_EQUAL [sig1, sig2, 0] (如果相等,繼續)
8 OP_CHECKMULTISIG [TRUE]
實驗六:時間鎖——OPCLTV 和 OPCSV
OPCHECKLOCKTIMEVERIFY (OPCLTV)
這個操作碼允許你在腳本中加入「絕對時間鎖」——必須等到某個時間才能花費。
語法:
<time> OP_CHECKLOCKTIMEVERIFY OP_DROP <remaining script>
可以是:
- 區塊高度(如果值 < 500,000,000)
- Unix 時間戳(如果值 >= 500,000,000)
實驗:1 年後才能花的比特幣
假設 2025 年 3 月 29 日,區塊高度大約 890,000。一年大約 52,500 個區塊,所以目標區塊高度大約是 942,500。
鎖定腳本:
942500 OP_CHECKLOCKTIMEVERIFY OP_DROP <pubKey> OP_CHECKSIG
如果有人在區塊 942,500 之前嘗試花費,OP_CLTV 會讓腳本失敗。只有在區塊 942,500 或之後,交易才有效。
OPCHECKSEQUENCEVERIFY (OPCSV)
這個操作碼實現「相對時間鎖」——必須等待一定時間(相對於 UTXO 被創建的時間)。
語法:
<sequence> OP_CHECKSEQUENCEVERIFY OP_DROP <remaining script>
格式:
- 位元組 0-3:序列號(nSequence)
- 位元組 4:flags
實驗:錢包恢復機制
想像這個場景:你想設計一個錢包,正常情況下用單簽名,但如果你的硬體錢包丟了,可以用你的「恢復短語」在一個月後恢復資金。
腳本邏輯:
OP_IF
# 正常路徑:單簽名
<primaryKey> OP_CHECKSIG
OP_ELSE
# 恢復路徑:一個月後
<144> OP_CSV OP_DROP
<recoveryKey> OP_CHECKSIG
OP_ENDIF
實驗七:HTLC——哈希時間鎖合約
HTLC 是閃電網路的核心構建模組。它結合了哈希鎖和時間鎖。
語法結構
OP_IF
# 成功路徑:提供原像
OP_HASH256 <hash> OP_EQUALVERIFY <receiverKey> OP_CHECKSIG
OP_ELSE
# 退款路徑:等待時間鎖
<locktime> OP_CLTV OP_DROP <senderKey> OP_CHECKSIG
OP_ENDIF
實驗:原子交換場景
假設 Alice 想用 1 BTC 交換 Bob 的 100 個假想的 Altcoins。
- Alice 生成一個隨機秘密
preimage - Alice 計算
hash = SHA256(preimage) - Alice 創建 HTLC,把 1 BTC 鎖進去
這時候:
- Bob 如果能提供
preimage,可以立即拿走 1 BTC - 如果 Bob 48 小時內沒有提供
preimage,Alice 可以拿回比特幣
同時,Bob 把 100 Altcoins 發給 Alice。只有當 Alice 揭示 preimage 時,Bob 才能從區塊鏈上「認領」這個秘密,用來完成 Altcoins 的交換。
執行追蹤
場景 A:Bob 成功領取
堆疊:<BobSig> OP_TRUE <preimage>
─────────────────────────────────
1 Push BobSig [BobSig]
2 Push OP_TRUE [BobSig, 1]
3 Push preimage [BobSig, 1, preimage]
4 OP_HASH256 [BobSig, 1, hash']
5 <hash> [BobSig, 1, hash', hash]
6 OP_EQUALVERIFY [BobSig, 1] (相等,繼續)
7 Push BobKey [BobSig, 1, BobKey]
8 OP_CHECKSIG [TRUE]
場景 B:時間到期,Alice 退款
堆疊:<AliceSig> OP_FALSE
─────────────────────────────
1 Push AliceSig [AliceSig]
2 Push OP_FALSE [AliceSig, 0]
3 OP_IF 跳過 if 分支
4 OP_ELSE 執行 else 分支
5 <locktime> [AliceSig, 0, locktime]
6 OP_CLTV 檢查時間
7 OP_DROP [AliceSig, 0]
8 Push AliceKey [AliceSig, 0, AliceKey]
9 OP_CHECKSIG [TRUE]
實驗八:Taproot——最新的腳本升級
為什麼要 Taproot?
Taproot 是比特幣 2021 年 11 月的重大升級。它帶來了:
- Schnorr 簽名:比 ECDSA 更簡單、更安全、更具可聚合性
- MAST:可以隱藏未使用的腳本條件
- 更便宜:複雜腳本的成本更低
Taproot 地址格式
Taproot 地址以 bc1p 開頭。
鎖定腳本:
OP_1 <x-only-pubkey>
是 32 位元組的公鑰。
密鑰路徑 vs 腳本路徑
Taproot 的一個巧妙設計是:你永遠可以選擇用「密鑰路徑」來花費。
密鑰路徑:只需要簽名,就像普通錢包一樣。
腳本路徑:如果你想用更複雜的條件,可以「揭示」那個腳本並滿足它的條件。
實驗:MAST 結構
假設你有三種花費方式:
- 單簽名(最常見)
- 2-of-3 多簽名
- 時間鎖後單簽名
用 MAST 結構:
根哈希
/ \
單簽名哈希 多簽/時間鎖哈希
| / \
葉節點A 葉節點B 葉節點C
如果用方式 1 花費,只需要揭示:
- 葉節點 A
- 控制區塊(證明葉節點 A 在樹中)
葉節點 B 和 C 永遠不需要揭示,所以它們的內容保持隱藏。
線上模擬器推薦
現在讓我推薦幾個可以實際跑比特幣腳本的線上工具:
1. Bitcoin Script Debugger
網址:https://www.cs.princeton.edu/~tierneyl/bitcoin-script-debugger/
這個工具可以讓你輸入腳本,逐步執行,觀察堆疊變化。非常適合學習。
2. Simin Belere's Bitcoin IDE
網址:https://bitcoin-script-ide.com/
提供更完整的開發環境,包括腳本範本和交易建構。
3. Bitcoin Optech Script Playground
Bitcoin Optech 的官方教學網站,提供腳本練習題。
4.CryptoLib
如果你會寫程式,可以用密碼學庫直接實驗。Python 的 bitcoinlib 或 JavaScript 的 bitcoinjs-lib 都可以讓你在本機測試。
常見錯誤與除錯
錯誤一:堆疊下溢
嘗試彈出堆疊上沒有的元素。
腳本:OP_ADD
堆疊:[5]
執行 OP_ADD:需要兩個元素,但只有一個 → 失敗!
解決方案:在操作前確保堆疊有足夠的元素。
錯誤二:OP_VERIFY 失敗
OP_VERIFY 會檢查堆疊頂部是否為 TRUE。如果不是,腳本立即失敗。
腳本:5 OP_VERIFY OP_1
堆疊:[5]
執行 OP_VERIFY:5 是非零 → TRUE → 繼續
執行 OP_1:堆疊 [5, 1]
成功!
腳本:0 OP_VERIFY OP_1
堆疊:[0]
執行 OP_VERIFY:0 是 FALSE → 腳本失敗!
錯誤三:類型錯誤
比特幣腳本沒有類型系統。數字和位元組串在堆疊上看起來一樣,但 OP_ADD 只接受數字。
如果你把字串「abc」當數字加,結果可能不是你想要的。
結語:腳本的力量
比特幣腳本語言的設計看起來很原始——沒有循環、沒有複雜的資料結構。但正是這種「刻意」的簡單性,讓比特幣變得安全可靠。
比特幣開發者的哲學是:在密碼學貨幣系統中,可預測性比表達力更重要。
如果你想更深入,可以:
- 閱讀比特幣開發者文檔(Bitcoin Developer Documentation)
- 研究 BIP 提案原文
- 在測試網上嘗試不同的腳本
- 關注比特幣核心代碼庫的腳本解釋器
比特幣腳本的世界很大,這只是冰山一角。但有了這些基礎,你已經可以理解比特幣網路中絕大多數的交易是如何運作的了。
動手試試看吧!
標籤:比特幣腳本、Script、堆疊機、OP_CODE、P2PKH、P2SH、HTLC、Taproot、MAST、比特幣智能合約、互動式學習
相關文章
- 比特幣地址類型與腳本類型技術深度比較:從 P2PK 到 P2TR 的完整演化與實務操作 — 本文從密碼學基礎、腳本設計、位元組效率、隱私保護和實務操作五個維度,全面比較比特幣主要的地址類型與腳本類型。涵蓋 P2PK、P2PKH、P2SH、P2WPKH、P2WSH、P2TR 的完整演化歷程,提供詳細的技術規格分析、Python/C 程式碼範例以及真實區塊鏈數據,幫助開發者和進階用戶理解不同地址類型的適用場景與選擇策略。
- 自私挖礦攻擊深度解析:礦工激勵與網路安全 — 深入分析比特幣自私挖礦攻擊的原理、數學模型與防禦機制。從 Eyal & Sirer 的經典論文出發,詳細解釋攻擊者如何透過隱藏區塊、操控分叉來獲得不公平優勢,並探討礦池集中化風險與激勵相容性設計的深層問題。
- Bitcoin Core RPC 實戰指南:腳本驗證、密碼學操作與區塊鏈數據分析 — 本文提供比特幣核心客戶端的 RPC 接口深度實戰指南。從比特幣節點運營商和開發者的視角,深入分析如何使用 Bitcoin Core RPC 進行腳本驗證、密碼學操作、區塊鏈數據查詢和交易分析。所有操作示例基於 Bitcoin Core v27.0 的實際 API,提供完整的命令語法、返回結果解析、安全注意事項與 Python 程式碼範例。
- 比特幣開發郵件列表參與完全指南:從新手到核心貢獻者的實踐之路 — 全面介紹比特幣開發郵件列表的運作機制、文化規範、參與技巧以及如何從普通訂閱者成長為有影響力的貢獻者,包含 BIP 流程解析和實際案例研究。
- 比特幣網路健康指標即時數據串接完整指南:從 API 到實際應用 — 深入探討比特幣網路健康指標的各個維度,介紹 mempool.space、Blockstream.info、Blockchain.com 等主流數據 API,並提供完整的 Python 實作範例,幫助讀者建立自己的比特幣網路健康監控系統。
延伸閱讀與來源
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!