跳到主要內容

Appendix A: 比特幣基礎回顧

閃電網路能夠運行在多個區塊鏈之上,但主要錨定在比特幣上。要理解閃電網路,你需要對比特幣及其構建模組有基本的了解。

有許多好的資源可以用來學習更多關於比特幣的知識,包括 Andreas M. Antonopoulos 所著的配套書籍《精通比特幣》(第二版),你可以在 GitHub 上以開源授權找到它:https://github.com/bitcoinbook/bitcoinbook[]。然而,你不需要閱讀另一整本書來準備這本書!

在本章中,我們收集了你需要了解的關於比特幣最重要的概念,並在閃電網路的背景下進行解釋。這樣你可以準確地學習理解閃電網路所需的知識,而不會分心。

本章涵蓋了比特幣的幾個重要概念,包括:

  • 金鑰和數位簽章

  • 雜湊函數

  • 比特幣交易及其結構

  • 比特幣交易鏈接

  • 交易輸出點

  • 比特幣腳本:鎖定和解鎖腳本

  • 基本鎖定腳本

  • 複雜和條件式鎖定腳本

  • 時間鎖

A.1. 金鑰和數位簽章

你可能聽說過比特幣是基於_密碼學_的,這是一個在電腦安全中廣泛使用的數學分支。密碼學還可以用來證明對秘密的知識而不揭露該秘密(數位簽章),或證明資料的真實性(數位指紋)。這些類型的密碼學證明是比特幣的關鍵數學工具,在比特幣應用中被廣泛使用。

比特幣的所有權是通過_數位金鑰_、_比特幣地址_和_數位簽章_建立的。數位金鑰實際上並不儲存在網路中,而是由使用者創建並儲存在一個稱為_錢包_的檔案或簡單資料庫中。使用者錢包中的數位金鑰完全獨立於比特幣協定,可以由使用者的錢包軟體生成和管理,無需參考區塊鏈或訪問網際網路。

大多數比特幣交易需要有效的數位簽章才能被包含在區塊鏈中,而這只能用秘密金鑰生成;因此,擁有該金鑰副本的任何人都可以控制比特幣。用於花費資金的數位簽章也被稱為_見證_,這是密碼學中使用的術語。比特幣交易中的見證資料證明了被花費資金的真正所有權。金鑰成對出現,由私(秘密)鑰和公鑰組成。把公鑰想像成類似於銀行帳號,把私鑰想像成類似於秘密 PIN 碼。

A.1.1. 私鑰和公鑰

私鑰只是一個隨機選取的數字。在實踐中,為了便於管理許多金鑰,大多數比特幣錢包使用確定性衍生演算法從單一隨機_種子_生成一系列私鑰。簡單來說,單一隨機數字被用來產生一系列看似隨機的數字,這些數字被用作私鑰。這允許使用者只備份種子,就能從該種子_衍生_所有他們需要的金鑰。

比特幣和許多其他加密貨幣及區塊鏈一樣,使用_橢圓曲線_來提供安全性。在比特幣中,secp256k1 橢圓曲線上的橢圓曲線乘法被用作 單向函數。簡單來說,橢圓曲線數學的性質使得計算點的純量乘法變得簡單,但不可能計算反函數(除法或離散對數)。

每個私鑰都有一個對應的_公鑰_,通過在橢圓曲線上使用純量乘法從私鑰計算得出。簡單來說,有了私鑰 k,我們可以將它乘以常數 G 來產生公鑰 K

  • K = k*G

這個計算是不可逆的。給定公鑰 K,無法計算出私鑰 k。在橢圓曲線數學中無法進行除以 G 的運算。相反,必須在一個稱為_暴力攻擊_的窮舉過程中嘗試所有可能的 k 值。因為 k 是一個 256 位元的數字,用任何傳統電腦窮舉所有可能的值所需的時間和能量比這個宇宙中可用的還要多。

A.1.2. 雜湊

在比特幣和閃電網路中廣泛使用的另一個重要工具是_密碼學雜湊函數_,特別是 SHA-256 雜湊函數。

雜湊函數,也稱為_摘要函數_,是一種將任意長度的資料轉換為固定長度結果的函數,這個結果稱為_雜湊_、摘要_或_指紋(參見 SHA-256 密碼學雜湊演算法)。重要的是,雜湊函數是_單向_函數,這意味著你無法反轉它們並從指紋計算輸入資料。

SHA-256 密碼學雜湊演算法
Figure 109. SHA-256 密碼學雜湊演算法

例如,如果我們使用命令列終端機將文字「Mastering the Lightning Network」輸入到 SHA-256 函數中,它將產生如下指紋:

$ echo -n "Mastering the Lightning Network" | shasum -a 256

ce86e4cd423d80d054b387aca23c02f5fc53b14be4f8d3ef14c089422b2235de  -

用於計算雜湊的輸入也稱為_原像_。

當然,輸入的長度可以更大得多。讓我們用中本聰的 比特幣白皮書 PDF 檔案嘗試同樣的事情:

$ wget http://bitcoin.org/bitcoin.pdf
$ cat bitcoin.pdf | shasum -a 256
b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553  -

雖然比單一句子需要更長的時間,但 SHA-256 函數處理這個 9 頁的 PDF,將其「消化」成一個 256 位元的指紋。

現在你可能會想,一個可以消化無限大小資料的函數怎麼可能產生一個固定大小數字的唯一指紋?

理論上,由於原像(輸入)的數量是無限的,而指紋的數量是有限的,必然存在許多原像產生相同的 256 位元指紋。當兩個原像產生相同的雜湊時,這被稱為_碰撞_。

在實踐中,256 位元的數字是如此巨大,以至於你永遠無法故意找到碰撞。密碼學雜湊函數的工作基礎是,尋找碰撞是一種暴力努力,需要如此多的能量和時間,以至於實際上是不可能的。

密碼學雜湊函數因為具有一些有用的特性而被廣泛應用於各種應用中。它們是:

確定性

相同的輸入總是產生相同的雜湊。

不可逆性

不可能從雜湊計算原像。

防碰撞

在計算上不可行找到兩個具有相同雜湊的訊息。

不相關性

輸入的微小變化會在輸出中產生如此大的變化,以至於輸出看起來與輸入不相關。

均勻/隨機

密碼學雜湊函數產生的雜湊均勻分佈在整個 256 位元可能輸出空間中。雜湊的輸出看起來是隨機的,儘管它並非真正隨機。

使用密碼學雜湊的這些特性,我們可以構建一些有趣的 應用

指紋

雜湊可用於對檔案或訊息進行指紋識別,以便唯一識別它。雜湊可用作任何資料集的通用識別碼。

完整性證明

檔案或訊息的指紋證明其完整性,因為檔案或訊息無法以任何方式被篡改或修改而不改變指紋。這通常用於確保軟體在安裝到你的電腦之前未被篡改。

承諾/不可否認性

你可以通過發布其雜湊來承諾特定的原像(例如,一個數字或訊息)而不揭露它。之後,你可以揭露秘密,每個人都可以驗證它與你之前承諾的是同一個東西,因為它產生了發布的雜湊。

工作量證明/雜湊研磨

你可以使用雜湊來證明你已經完成了計算工作,方法是在雜湊中顯示一個非隨機模式,這只能通過重複猜測原像來產生。例如,比特幣區塊頭的雜湊以許多零位元開始。產生它的唯一方法是更改標頭的一部分並將其雜湊數萬億次,直到它偶然產生該模式。

原子性

你可以將秘密原像作為在幾個連結交易中花費資金的先決條件。如果任何一方為了花費其中一個交易而揭露原像,則所有其他各方現在也可以花費他們的交易。所有或沒有一個變得可花費,在幾個交易中實現原子性。

A.1.3. 數位簽章

私鑰用於創建簽章,這些簽章是通過證明交易中使用的資金的所有權來花費比特幣所必需的。

_數位簽章_是通過將私鑰應用於特定訊息而計算出的數字。

給定訊息 m 和私鑰 k,簽名函數 Fsign 可以產生簽章 S

\[$ S = F_{sign}(m, k) $\]

這個簽章 S 可以由任何擁有公鑰 K(對應於私鑰 k)和訊息的人獨立驗證:

\[$ F_{verify}(m, K, S) $\]

如果 Fverify 返回 true 結果,則驗證者可以確認訊息 m 是由擁有私鑰 k 的人簽署的。重要的是,數位簽章證明了在簽署時擁有私鑰 k,而不揭露 k

數位簽章使用密碼學雜湊演算法。簽章應用於訊息的雜湊,因此訊息 m 被「摘要」成一個固定長度的雜湊 H(m),作為指紋。

通過將數位簽章應用於交易的雜湊,簽章不僅證明了授權,還「鎖定」了交易資料,確保其完整性。已簽署的交易無法被修改,因為任何更改都會導致不同的雜湊並使簽章無效。

A.1.4. 簽章類型

簽章並不總是應用於整個交易。為了提供簽名彈性,比特幣數位簽章包含一個稱為簽章雜湊類型的前綴,它指定交易資料的哪一部分包含在雜湊中。這允許簽章承諾或「鎖定」交易中的全部或僅部分資料。最常見的簽章雜湊類型是 SIGHASH_ALL,它通過將所有交易資料包含在簽署的雜湊中來鎖定交易中的所有內容。相比之下,SIGHASH_SINGLE 鎖定所有交易輸入,但只鎖定一個輸出(更多關於輸入和輸出的內容在下一節)。不同的簽章雜湊類型可以組合產生六種不同的「模式」,用於被簽章鎖定的交易資料。

更多關於簽章雜湊類型的資訊可以在 《精通比特幣》第二版第 6 章的「簽章雜湊類型」一節中找到。

A.2. 比特幣交易

_交易_是編碼比特幣系統中參與者之間價值轉移的資料結構。

A.2.1. 輸入和輸出

比特幣交易的基本構建模組是交易輸出。_交易輸出_是不可分割的比特幣貨幣塊,記錄在區塊鏈上,並被整個網路認可為有效。交易花費輸入並創建輸出。交易_輸入_只是對先前記錄交易的輸出的引用。這樣,每個交易都花費先前交易的輸出並創建新的輸出(參見 交易將價值從輸入轉移到輸出)。

交易輸入和輸出
Figure 110. 交易將價值從輸入轉移到輸出

比特幣全節點追蹤所有可用和可花費的輸出,稱為_未花費交易輸出_(UTXOs)。所有 UTXOs 的集合稱為 UTXO 集,目前數量達數百萬個 UTXOs。當新的 UTXOs 被創建時,UTXO 集會增長;當 UTXOs 被消費時,它會縮小。每個交易都代表 UTXO 集的一個變化(狀態轉換),通過消費一個或多個 UTXOs 作為_交易輸入_,並創建一個或多個 UTXOs 作為其_交易輸出_。

例如,假設使用者 Alice 有一個她可以花費的 100,000 聰的 UTXO。Alice 可以通過構建一個交易來向 Bob 支付 100,000 聰,該交易有一個輸入(消費她現有的 100,000 聰輸入)和一個「支付」給 Bob 100,000 聰的輸出。現在 Bob 有了一個他可以花費的 100,000 聰 UTXO,創建一個消費這個新 UTXO 的新交易,並將其花費到另一個 UTXO 作為對另一個使用者的支付,依此類推(參見 Alice 向 Bob 支付 100,000 聰)。

Alice 向 Bob 支付 100,000 聰
Figure 111. Alice 向 Bob 支付 100,000 聰

交易輸出可以有任意(整數)值,以聰計價。就像美元可以向下劃分到小數點後兩位為美分一樣,比特幣可以向下劃分到小數點後八位為聰。雖然輸出可以有任何任意值,但一旦創建,它就是不可分割的。這是輸出的一個重要特性,需要強調:輸出是離散的、不可分割的價值單位,以整數聰計價。未花費的輸出只能在交易中完整消費。

那麼,如果 Alice 想向 Bob 支付 50,000 聰,但只有一個不可分割的 100,000 聰 UTXO 怎麼辦?Alice 需要創建一個交易,消費(作為其輸入)100,000 聰 UTXO,並有兩個輸出:一個支付 50,000 聰給 Bob,另一個支付 50,000 聰_回_給 Alice 作為「找零」(參見 Alice 向 Bob 支付 50,000 聰,向自己支付 50,000 聰作為找零)。

Alice 向 Bob 支付 50,000 聰,向自己支付 50,000 聰作為找零
Figure 112. Alice 向 Bob 支付 50,000 聰,向自己支付 50,000 聰作為找零

找零輸出沒有什麼特別之處,也沒有辦法將其與任何其他輸出區分開來。它不必是最後一個輸出。可能有多個找零輸出,或沒有找零輸出。只有交易的創建者知道哪些輸出是給其他人的,哪些輸出是給他們自己擁有的地址的,因此是「找零」。

同樣,如果 Alice 想向 Bob 支付 85,000 聰,但有兩個可用的 50,000 聰 UTXOs,她必須創建一個具有兩個輸入(消費她的兩個 50,000 聰 UTXOs)和兩個輸出的交易,支付 Bob 85,000 聰並將 15,000 聰送回自己作為找零(參見 Alice 使用兩個 50,000 聰輸入向 Bob 支付 85,000 聰,向自己支付 15,000 聰作為找零)。

Alice 使用兩個 50,000 聰輸入向 Bob 支付 85,000 聰,向自己支付 15,000 聰作為找零
Figure 113. Alice 使用兩個 50,000 聰輸入向 Bob 支付 85,000 聰,向自己支付 15,000 聰作為找零

前面的圖解和範例展示了比特幣交易如何組合(花費)一個或多個輸入並創建一個或多個輸出。一個交易可以有數百甚至數千個輸入和輸出。

雖然閃電網路創建的交易有多個輸出,但它們本身沒有「找零」,因為通道的整個可用餘額在兩個通道夥伴之間分割。

A.2.2. 交易鏈

每個輸出都可以在後續交易中作為輸入花費。所以,例如,如果 Bob 決定花費 10,000 聰在一個向 Chan 支付的交易中,而 Chan 花費 4,000 聰向 Dina 支付,它會如 Alice 支付給 Bob,Bob 支付給 Chan,Chan 支付給 Dina 所示展開。

如果一個輸出在區塊鏈上記錄的另一個交易中被引用為輸入,則該輸出被視為_已花費_。如果沒有記錄的交易引用該輸出,則該輸出被視為_未花費_(並且可用於花費)。

唯一沒有輸入的交易類型是由比特幣礦工創建的特殊交易,稱為_幣基交易_。幣基交易只有輸出而沒有輸入,因為它通過挖礦創造新的比特幣。每個其他交易都花費一個或多個先前記錄的輸出作為其輸入。

由於交易是鏈接的,如果你隨機選擇一個交易,你可以沿著其任何一個輸入向後追蹤到創建它的先前交易。如果你繼續這樣做,你最終會到達比特幣最初被挖出的幣基交易。

Alice 支付給 Bob,Bob 支付給 Chan,Chan 支付給 Dina
Figure 114. Alice 支付給 Bob,Bob 支付給 Chan,Chan 支付給 Dina

A.2.3. TxID:交易識別碼

比特幣系統中的每個交易都由唯一識別碼(假設存在 BIP-0030)識別,稱為_交易 ID_或簡稱 TxID。為了產生唯一識別碼,我們使用 SHA-256 密碼學雜湊函數產生交易資料的雜湊。這個「指紋」作為通用識別碼。交易可以通過其交易 ID 引用,一旦交易被記錄在比特幣區塊鏈上,比特幣網路中的每個節點都知道這個交易是有效的。

例如,交易 ID 可能看起來像這樣:

通過雜湊交易資料產生的交易 ID
e31e4e214c3f436937c74b8663b3ca58f7ad5b3fce7783eb84fd9a5ee5b9a54c

這是一個真實的交易(作為《精通比特幣》書籍的範例創建),可以在比特幣區塊鏈上找到。嘗試通過在區塊瀏覽器中輸入此 TxID 來找到它:

或使用短連結(區分大小寫):

A.2.4. 輸出點:輸出識別碼

因為每個交易都有唯一 ID,我們還可以通過引用 TxID 和輸出索引號來唯一識別該交易中的交易輸出。交易中的第一個輸出是輸出索引 0,第二個輸出是輸出索引 1,依此類推。輸出識別碼通常稱為_輸出點_。

按照慣例,我們將輸出點寫為 TxID、冒號和輸出索引號:

輸出點:通過 TxID 和索引號識別輸出
7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18:0

輸出識別碼(輸出點)是將交易鏈接在一起的機制。每個交易輸入都是對先前交易的特定輸出的引用。該引用是一個輸出點:TxID 和輸出索引號。所以交易「花費」來自特定交易(通過 TxID)的特定輸出(通過索引號),以創建新的輸出,這些輸出本身可以通過引用輸出點來花費。

交易輸入引用輸出點形成鏈 展示了從 Alice 到 Bob 到 Chan 到 Dina 的交易鏈,這次在每個輸入中都有輸出點。

交易輸入引用輸出點形成鏈
Figure 115. 交易輸入引用輸出點形成鏈

Bob 交易中的輸入引用 Alice 的交易(通過 TxID)和索引為 0 的輸出。

Chan 交易中的輸入引用 Bob 交易的 TxID 和第一個索引輸出,因為向 Chan 的支付是輸出 #1。在 Bob 向 Chan 的支付中,Bob 的找零是輸出 #0。[1]

現在,如果我們看 Alice 向 Bob 的支付,我們可以看到 Alice 正在花費一個輸出點,該輸出點是交易 ID 為 6a5f1b3[…​] 的交易中的第三個(輸出索引 #2)輸出。我們在圖中沒有看到那個被引用的交易,但我們可以從輸出點推斷這些細節。

A.3. 比特幣腳本

完成我們理解所需的比特幣最後一個元素是控制輸出點訪問的腳本語言。到目前為止,我們通過說「Alice 簽署交易以向 Bob 支付」來簡化描述。然而,在幕後,有一些隱藏的複雜性使得實現更複雜的花費條件成為可能。最簡單和最常見的花費條件是「出示與以下公鑰匹配的簽章」。這樣的花費條件作為_鎖定腳本_記錄在每個輸出中,使用稱為_比特幣腳本_的腳本語言編寫。

比特幣腳本是一種極其簡單的基於堆疊的腳本語言。它不包含迴圈或遞迴,因此是_圖靈不完備_的(意味著它無法表達任意複雜性並且具有可預測的執行)。熟悉(現在已經古老的)FORTH 程式語言的人會認識其語法和風格。

A.3.1. 運行比特幣腳本

簡單來說,比特幣系統通過在堆疊上運行腳本來評估比特幣腳本;如果最終結果是 TRUE,它認為花費條件滿足,交易有效。

讓我們看一個非常簡單的比特幣腳本範例,它將數字 2 和 3 相加,然後將結果與數字 5 進行比較:

2 3 ADD 5 EQUAL

比特幣腳本執行範例 中,我們看到這個腳本是如何執行的(從左到右)。

比特幣腳本執行範例
Figure 116. 比特幣腳本執行範例

A.3.2. 鎖定和解鎖腳本

比特幣腳本由兩部分組成:

鎖定腳本

這些嵌入在交易輸出中,設定花費該輸出必須滿足的條件。例如,Alice 的錢包在支付給 Bob 的輸出中添加一個鎖定腳本,設定需要 Bob 的簽章才能花費它的條件。

解鎖腳本

這些嵌入在交易輸入中,滿足被引用輸出的鎖定腳本設定的條件。例如,Bob 可以通過提供包含數位簽章的解鎖腳本來解鎖前面的輸出。

使用簡化模型,為了驗證,解鎖腳本和鎖定腳本被連接並執行(P2SH 和 SegWit 是例外)。例如,如果某人用鎖定腳本 "3 ADD 5 EQUAL" 鎖定了一個交易輸出,我們可以在交易輸入中用解鎖腳本 "2" 來花費它。任何驗證該交易的人都會連接我們的解鎖腳本(2)和鎖定腳本(3 ADD 5 EQUAL)並通過比特幣腳本執行引擎運行結果。他們會得到 TRUE,我們就能夠花費該輸出。

顯然,這個簡化的範例對於鎖定實際的比特幣輸出來說是一個非常糟糕的選擇,因為沒有秘密,只有基本算術。任何人都可以通過提供答案「2」來花費該輸出。因此,大多數鎖定腳本需要證明對秘密的知識。

A.3.3. 鎖定到公鑰(簽章)

最簡單的鎖定腳本形式是需要簽章的腳本。讓我們考慮 Alice 向 Bob 支付 50,000 聰的交易。Alice 創建的向 Bob 支付的輸出將有一個需要 Bob 簽章的鎖定腳本,看起來像這樣:

需要來自 Bob 私鑰的數位簽章的鎖定腳本
<Bob Public Key> CHECKSIG

運算子 CHECKSIG 從堆疊中取出兩個項目:簽章和公鑰。如你所見,Bob 的公鑰在鎖定腳本中,所以缺少的是與該公鑰對應的簽章。這個鎖定腳本只能由 Bob 花費,因為只有 Bob 有相應的私鑰來產生與公鑰匹配的數位簽章。

為了解鎖這個鎖定腳本,Bob 會提供一個只包含他的數位簽章的解鎖腳本:

包含(僅)來自 Bob 私鑰的數位簽章的解鎖腳本
<Bob Signature>

顯示鎖定腳本(輸出)和解鎖腳本(輸入)的交易鏈 中,你可以看到 Alice 交易中的鎖定腳本(在支付給 Bob 的輸出中)和 Bob 交易中的解鎖腳本(在花費該輸出的輸入中)。

顯示鎖定腳本(輸出)和解鎖腳本(輸入)的交易鏈
Figure 117. 顯示鎖定腳本(輸出)和解鎖腳本(輸入)的交易鏈

為了驗證 Bob 的交易,比特幣節點會執行以下操作:

  1. 從輸入中提取解鎖腳本(<Bob Signature>)。

  2. 查找它試圖花費的輸出點(a643e37...3213:0)。這是 Alice 的交易,會在區塊鏈上找到。

  3. 從該輸出點提取鎖定腳本(<Bob PubKey> CHECKSIG)。

  4. 連接成一個腳本,將解鎖腳本放在鎖定腳本前面(<Bob Signature> <Bob PubKey> CHECKSIG)。

  5. 在比特幣腳本執行引擎上執行此腳本,看產生什麼結果。

  6. 如果結果是 TRUE,則推斷 Bob 的交易是有效的,因為它能夠滿足花費該輸出點的花費條件。

A.3.4. 鎖定到雜湊(秘密)

另一種類型的鎖定腳本,在閃電網路中使用,是_雜湊鎖_。要解鎖它,你必須知道雜湊的秘密_原像_。

為了演示這一點,讓 Bob 生成一個隨機數 R 並保密:

R = 1833462189

現在,Bob 計算這個數字的 SHA-256 雜湊:

H = SHA256(R) =>
H = SHA256(1833462189) =>
H = 0ffd8bea4abdb0deafd6f2a8ad7941c13256a19248a7b0612407379e1460036a

現在,Bob 把我們之前計算的雜湊 H 給 Alice,但保留數字 R 秘密。回想一下,由於密碼學雜湊的特性,Alice 無法「反轉」雜湊計算並猜測數字 R。

Alice 創建一個支付 50,000 聰的輸出,鎖定腳本為:

HASH256 H EQUAL

其中 H 是 Bob 給 Alice 的實際雜湊值(0ffd8...036a)。

讓我們解釋這個腳本:

HASH256 運算子從堆疊中彈出一個值並計算該值的 SHA-256 雜湊。然後它將結果推回堆疊。

H 值被推到堆疊上,然後 EQUAL 運算子檢查兩個值是否相同,並相應地將 TRUE 或 FALSE 推到堆疊上。

因此,這個鎖定腳本只有在與包含 R 的解鎖腳本結合時才會起作用,這樣當連接時,我們有:

R HASH256 H EQUAL

只有 Bob 知道 R,所以只有 Bob 能夠產生一個揭示秘密值 R 的解鎖腳本的交易。

有趣的是,Bob 可以把 R 值給其他任何人,然後他們就可以花費那個比特幣。這使得秘密值 R 幾乎像比特幣「代金券」,因為任何擁有它的人都可以花費 Alice 創建的輸出。我們將看到這是閃電網路中一個有用的特性!

A.3.5. 多重簽章腳本

比特幣腳本語言提供了多重簽章構建模組(原語),可用於構建託管服務和多個利益相關者之間的複雜所有權配置。需要多個簽章才能花費比特幣的安排稱為_多重簽章方案_,進一步指定為 K-of-N 方案,其中:

  • N 是多重簽章方案中識別的簽名者總數,以及

  • K 是_法定人數_或_閾值_:授權花費的最小簽章數量。

K-of-N 多重簽章的腳本是:

K <PubKey1> <PubKey2> ... <PubKeyN> N CHECKMULTISIG

其中 N 是列出的公鑰總數(公鑰 1 到公鑰 N),K 是花費輸出所需簽章的閾值。

閃電網路使用 2-of-2 多重簽章方案來構建支付通道。例如,Alice 和 Bob 之間的支付通道將建立在這樣的 2-of-2 多重簽章上:

2 <PubKey Alice> <PubKey Bob> 2 CHECKMULTISIG

前面的鎖定腳本可以用包含一對簽章的解鎖腳本來滿足:[2]中有描述。]

0 <Sig Alice> <Sig Bob>

兩個腳本組合在一起將形成組合驗證腳本:

0 <Sig Alice> <Sig Bob> 2 <PubKey Alice> <PubKey Bob> 2 CHECKMULTISIG

多重簽章鎖定腳本可以由比特幣地址表示,該地址編碼鎖定腳本的雜湊。例如,閃電支付通道的初始資金交易是向一個地址支付的交易,該地址編碼了兩個通道夥伴的 2-of-2 多重簽章的鎖定腳本。

A.3.6. 時間鎖腳本

比特幣中存在並在閃電網路中廣泛使用的另一個重要構建模組是_時間鎖_。時間鎖是對花費的限制,要求在允許花費之前必須經過一定的時間或區塊高度。它有點像一張從銀行帳戶開出的遠期支票,在支票上的日期之前無法兌現。

比特幣有兩個級別的時間鎖:交易級時間鎖和輸出級時間鎖。

_交易級時間鎖_記錄在交易的 nLockTime 欄位中,防止整個交易在時間鎖過去之前被接受。交易級時間鎖是當今比特幣中最常用的時間鎖機制。

_輸出級時間鎖_由腳本運算子創建。有兩種類型的輸出時間鎖:絕對時間鎖和相對時間鎖。

輸出級_絕對時間鎖_由運算子 CHECKLOCKTIMEVERIFY 實作,在對話中通常縮寫為 CLTV。絕對時間鎖使用絕對時間戳或區塊高度實現時間約束,表達相當於「在區塊 800,000 之前不可花費」。

輸出級_相對時間鎖_由運算子 CHECKSEQUENCEVERIFY 實作,在對話中通常縮寫為 CSV。相對時間鎖實現相對於交易確認的花費約束,表達相當於「在確認後 1,024 個區塊之前無法花費」。

A.3.7. 具有多個條件的腳本

比特幣腳本更強大的功能之一是流程控制,也稱為條件子句。你可能熟悉各種程式語言中使用 IF...THEN...ELSE 結構的流程控制。比特幣條件子句看起來有點不同,但本質上是相同的結構。

在基本層面上,比特幣條件操作碼允許我們構建一個鎖定腳本,該腳本有兩種解鎖方式,取決於評估邏輯條件的 TRUE/FALSE 結果。例如,如果 x 是 TRUE,鎖定腳本是 A ELSE 鎖定腳本是 B。

此外,比特幣條件表達式可以無限_嵌套_,意味著一個條件子句可以包含另一個,另一個又包含另一個,等等。比特幣腳本流程控制可用於構建非常複雜的腳本,具有數百甚至數千個可能的執行路徑。嵌套沒有限制,但共識規則對腳本的最大位元組大小施加了限制。

比特幣使用 IF、ELSE、ENDIF 和 NOTIF 操作碼實作流程控制。此外,條件表達式可以包含布林運算子,如 BOOLAND、BOOLOR 和 NOT。

乍一看,你可能會發現比特幣的流程控制腳本令人困惑。那是因為比特幣腳本是一種堆疊語言。與算術運算 \(1 + 1\) 在比特幣腳本中表示為 1 1 ADD 看起來「向後」一樣,比特幣中的流程控制子句也看起來「向後」。

在大多數傳統(程序式)程式語言中,流程控制看起來像這樣:

大多數程式語言中流程控制的虛擬碼
if (condition):
  code to run when condition is true
else:
  code to run when condition is false
code to run in either case

在像比特幣腳本這樣的基於堆疊的語言中,邏輯條件在 IF 之前,這使它看起來「向後」,像這樣:

比特幣腳本流程控制
condition
IF
  code to run when condition is true
ELSE
  code to run when condition is false
ENDIF
code to run in either case

閱讀比特幣腳本時,請記住被評估的條件在 IF 操作碼_之前_。

A.3.8. 在腳本中使用流程控制

比特幣腳本中流程控制的一個非常常見的用途是構建一個鎖定腳本,該腳本提供多個執行路徑,每個路徑都是贖回 UTXO 的不同方式。

讓我們看一個簡單的範例,我們有兩個簽名者 Alice 和 Bob,其中任何一個都能夠贖回。使用多重簽章,這將表達為 1-of-2 多重簽章腳本。為了演示,我們將使用 IF 子句做同樣的事情:

IF
 <Alice's Pubkey> CHECKSIG
ELSE
 <Bob's Pubkey> CHECKSIG
ENDIF

看看這個鎖定腳本,你可能會想:「條件在哪裡?IF 子句前面什麼都沒有!」

條件不是鎖定腳本的一部分。相反,條件將_在解鎖腳本中提供_,允許 Alice 和 Bob「選擇」他們想要的執行路徑。

Alice 用這個解鎖腳本贖回:

<Alice's Sig> 1

末尾的 1 作為條件(TRUE),將使 IF 子句執行 Alice 有簽章的第一個贖回路徑。

對於 Bob 來說,要贖回這個,他必須通過給 IF 子句一個 FALSE 值來選擇第二個執行路徑:

<Bob's Sig> 0

Bob 的解鎖腳本在堆疊上放一個 0,導致 IF 子句執行第二個(ELSE)腳本,這需要 Bob 的簽章。

因為兩個條件中的每一個也需要簽章,Alice 不能使用第二個子句,Bob 不能使用第一個子句;他們沒有所需的簽章!

由於條件流可以嵌套,解鎖腳本中的 TRUE / FALSE 值也可以嵌套,以導航複雜的條件路徑。

閃電網路中使用的複雜腳本 中,你可以看到閃電網路中使用的那種複雜腳本的範例,具有多個條件。[3]閃電網路中使用的腳本經過高度優化和緊湊,以最小化鏈上足跡,所以它們不容易閱讀和理解。儘管如此,看看你是否能識別我們在本章中學到的一些比特幣腳本概念。

Example 9. 閃電網路中使用的複雜腳本
# To remote node with revocation key
DUP HASH160 <RIPEMD160(SHA256(revocationpubkey))> EQUAL
IF
    CHECKSIG
ELSE
    <remote_htlcpubkey> SWAP SIZE 32 EQUAL
    NOTIF
        # To local node via HTLC-timeout transaction (timelocked).
        DROP 2 SWAP <local_htlcpubkey> 2 CHECKMULTISIG
    ELSE
        # To remote node with preimage.
        HASH160 <RIPEMD160(payment_hash)> EQUALVERIFY
        CHECKSIG
    ENDIF
ENDIF

1. 維基百科 賽局理論條目 提供了更多資訊。
2. Joseph Poon and Thaddeus Dryja. "The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments." DRAFT Version 0.5.9.2. January 14, 2016. https://lightning.network/lightning-network-paper.pdf.
1. Andreas M. Antonopoulos, Mastering Bitcoin, 2nd Edition, Chapter 1 (O’Reilly)
2. ACINQ:Eclair Mobile 閃電網路錢包的開發者。
3. 通常不建議為多筆付款重複使用同一個比特幣地址,因為所有比特幣交易都是公開的。 經過的好奇者可能會掃描 Alice 的 QR 碼,並在比特幣區塊鏈上看到 Alice 已經收到了多少小費到這個地址。 幸運的是,閃電網路為此提供了更私密的解決方案,將在本書後面討論!
4. Eclair 錢包不提供自動計算必要費用並將最大資金分配給通道的選項,所以 Alice 必須自己計算。
1. 雖然原始閃電網路白皮書描述了由兩個通道夥伴注資的通道,但截至 2020 年的當前規範假設只有一個夥伴向通道承諾資金。截至 2021 年 5 月,雙重注資閃電網路通道在 c-lightning 閃電網路實現中處於實驗階段。
2. George Danezis and Ian Goldberg, "Sphinx: A Compact and Provably Secure Mix Format," in IEEE Symposium on Security and Privacy (New York: IEEE, 2009), 269–282.
3. 「洋蔥」一詞最初由 Tor 專案使用。此外,Tor 網路也被稱為洋蔥網路,該專案使用洋蔥作為其標誌。Tor 服務在網際網路上使用的頂級域名是 onion
1. George Danezis and Ian Goldberg, "Sphinx: A Compact and Provably Secure Mix Format," in IEEE Symposium on Security and Privacy (New York: IEEE, 2009), 269–282.
1. HODL 這個詞來自論壇中一個興奮的拼寫錯誤,將 "HOLD"(持有)誤拼,用來鼓勵人們不要在恐慌中出售比特幣。
1. 回想一下,找零不必是交易中的最後一個輸出,實際上與其他輸出無法區分。
2. 第一個參數(0)沒有任何意義,但由於比特幣多重簽章實作中的一個錯誤而需要。這個問題在《精通比特幣》https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch07.asciidoc[第 7 章
3. 來自 BOLT #3