# 第六章 交易
## 6.1 簡介
比特幣交易是比特幣系統中最重要的部分。比特幣中的其他一切都是為了確保交易可以被創建、在網絡上傳播、驗證,并最終添加到全局交易分類賬本(區塊鏈)中。比特幣交易的本質是數據結構,這些數據結構是對比特幣交易參與者價值傳遞的編碼。比特幣區塊鏈是一本全局復式記賬總賬簿,每個比特幣交易都是在比特幣區塊鏈上的一個公開記錄。
在這一章,我們將會剖析比特幣交易的多種形式、所包含的信息、如何被創建、如何被驗證以及如何成為所有比特幣交易永久記錄的一部分。在本章中使用的術語“錢包”,指的是構建交易的軟件,而不僅僅是密鑰數據庫。
## 6.2 交易細節
在[【第二章比特幣概述】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch02.md)中,我們使用區塊瀏覽器查看了Alice曾經在Bob的咖啡店支付咖啡的交易(圖6-1)。
區塊瀏覽器應用程序顯示從Alice的“地址”到Bob的“地址”的交易。 這里顯示的是交易內容的簡化視圖。 實際上,正如我們將在本章中看到的,所顯示的大部分信息都是由區塊瀏覽器構建的,并不在交易中。

圖6-1 Alice與Bob咖啡店的交易
### 6.2.1 交易 - 幕后細節
在幕后,實際的交易看起來與典型的區塊瀏覽器提供的交易非常不同。 事實上,我們在各種比特幣應用程序用戶界面中看到的大多數高級結構并不存在于比特幣系統中。
我們可以使用Bitcoin Core的命令行界面(getrawtransaction和decodeawtransaction)來檢索Alice的“原始”交易,對其進行解碼,并查看它包含的內容。 結果如下:
Alice的交易被解碼后是這個樣子:
```
{
"version": 1,
"locktime": 0,
"vin": [
{
"txid":"7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.01500000,
"scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
},
{
"value": 0.08450000,
"scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
}
]
}
```
您可能會注意到這筆交易似乎少了些什么東西,比如:Alice的地址在哪里?Bob的地址在哪里? Alice發送的“0.1”個幣的輸入在哪里? 在比特幣里,沒有具體的貨幣,沒有發送者,沒有接收者,沒有余額,沒有帳戶,沒有地址。為了使用者的便利,以及使事情更容易理解,所有這些都構建在更高層次上。
你可能還會注意到很多奇怪和難以辨認的字段以及十六進制字符串。 不必擔心,本章將詳細介紹這里所示的各個字段。
## 6.3 交易的輸入輸出
比特幣交易的基本組成部分是*交易輸出transaction output*。 交易輸出是比特幣不可分割的基本組合,記錄在區塊鏈上,并被整個網絡認可有效。 比特幣全節點跟蹤所有可找到的和可使用的輸出,稱為 *“未花費的交易輸出”(unspent transaction outputs)*,即*UTXO*。 所有UTXO的集合被稱為*UTXO集*,目前有數百萬個UTXO。 當新的UTXO被創建,UTXO集就會變大,當UTXO被消耗時,UTXO集會隨著縮小。每一個交易都代表UTXO集的變化(狀態轉換)。
當用戶的錢包已經“收到”比特幣時,就意味著,錢包已經檢測到了可用的UTXO,這些UTXO可以用錢包所控制的其中一個密鑰消費。 因此,用戶的比特幣“余額”是指用戶錢包中可用的UTXO總和,這些UTXO分散在幾百個交易和幾百個區塊中。用戶的 “比特幣余額”,這個概念是比特幣錢包應用創建的。比特幣錢包掃描區塊鏈,得到可以用這個錢包控制的密鑰進行消費的所有UTXO,加到一起就計算出了該用戶的余額 。大多數錢包維護一個數據庫或使用數據庫服務來存儲所有UTXO的快速引用集,其中包含可以使用用戶的密鑰進行消費的所有UTXO。
一個UTXO可以是1“聰”(satoshi)的任意倍數(整數倍)。就像美元可以被分割成表示兩位小數的“分”一樣,比特幣可以被分割成八位小數的“聰”。盡管UTXO可以是任意值,但一旦被創造出來,即不可分割。這是UTXO值得被強調的一個重要特性:UTXO的面值為“聰”的整數倍,是離散(不連續)且不可分割的價值單位,一個UTXO只能在一次交易中作為一個整體被消耗。
如果一個 UTXO比一筆交易金額大,它仍會被當作一個整體而消耗掉,但同時會在交易中生成找零。例如,你有一個價值20比特幣的 UTXO,想支付1比特幣,那么你的交易必須消耗掉整個20比特幣的UTXO,產生兩個輸出:一個支付了1比特幣給收款人,另一個支付19比特幣的找零到你的錢包。這樣的話,由于UTXO(或交易輸出)的不可分割特性,大部分比特幣交易都會產生找零。
想象一下,一位顧客要買1.5元的飲料。她掏出錢包并試圖從所有硬幣和鈔票中找出一種組合來湊齊她要支付的1.5 元。如果可能的話,她會選剛剛好的零錢(比如一張1元紙幣和5個一毛硬幣)或者是小面額的組合(比如3個五毛硬幣)。如果都不行的話,她會用一張大面額的鈔票,比如5元紙幣。如果她把5元給了商店老板,她會得到3.5元的找零,并把找零放回她的錢包供未來使用。
類似的,一筆比特幣交易可以是任意金額,但必須從用戶可用的UTXO中創建出來。用戶不能再把UTXO進一步細分,就像不能把一元紙幣撕開而繼續當貨幣使用一樣。用戶的錢包應用通常會從用戶可用的UTXO中選取多個來拼湊出一個大于或等于當前交易所需的比特幣量。
就像現實生活中一樣,比特幣應用可以使用一些策略來滿足付款需求:組合若干小額UTXO,并算出準確的找零;或者使用一個比交易額大的UTXO然后進行找零。所有這些復雜的、由可花費UTXO組成的集合,都是由用戶的錢包自動完成, 并不為用戶所見。只有當你以編程方式用UTXO來構建原始交易時,這些才與你有關。
一筆交易會消耗先前的已被記錄(存在)的UTXO,并創建新的UTXO以備未來的交易消耗。通過這種方式,一定數量的比特幣價值在不同所有者之間轉移,并在交易鏈中消耗和創建UTXO。
交易的輸出與輸入鏈存在一個例外,即被稱為*“幣基交易”(Coinbase Transaction)*的特殊交易,它是每個區塊中的第一筆交易,這筆交易是由“贏家”礦工放置的,創造了支付給該礦工的全新比特幣,作為挖礦獎勵。這個特殊的幣基交易不消耗UTXO,相反,它有一個稱為“coinbase”的特殊類型的輸入。這也就是為什么比特幣可以在挖礦過程中被創造出來,我們將在“第十章挖礦”進行詳述。
**小貼士:** 輸入和輸出,先有那個呢?先有雞還是先有蛋?嚴格來講,先產生輸出,因為創造新比特幣的 “幣基交易”沒有輸入,但它可以無中生有產生輸出。
### 6.3.1 交易輸出
每一筆比特幣交易都會創造輸出,并被比特幣賬簿記錄下來。幾乎所有的輸出,除了一個例外(見“數據輸出操作符”(OP_RETURN)),都能創造稱為UTXO的比特幣塊,然后被整個網絡識別,供所有者在未來交易中使用。
UTXO集中的UTXO被每一個全節點比特幣客戶端追蹤。 新的交易從UTXO集中消耗(花費)一個或多個輸出。
交易輸出包含兩部分:
- 一定量的比特幣,面值為“聰”(satoshis) ,是最小的比特幣單位;
- 確定花費輸出所需條件的加密難題(cryptographic puzzle)
這個加密難題也被稱為鎖定腳本(locking script), 見證腳本(witness script), 或腳本公鑰 (scriptPubKey)。
有關交易腳本語言會在后面的“交易腳本和腳本語言”一節中詳細討論。
現在,我們來看看 Alice 的交易(之前的6.2.1“交易 - 幕后細節”所示),看看我們是否可以找到并識別輸出。 在 JSON 編碼中,輸出位于名為 vout 的數組(列表)中:
```
"vout": [
{
"value": 0.01500000,
"scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY
OP_CHECKSIG"
},
{
"value": 0.08450000,
"scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
}
]
```
如您所見,交易包含兩個輸出。 每個輸出都由一個值和一個加密難題來定義。 在 Bitcoin Core 顯示的編碼中,這里的value值以比特幣為單位,但在交易本身中,它被記錄為以 “聰”為單位的整數。 輸出的第二部分是設定支付條件的加密難題。 Bitcoin Core 將其顯示為 scriptPubKey,后面跟一個可讀的腳本。
稍后將在6.4.3 腳本構建(鎖定與解鎖)中討論UTXO的鎖定和解鎖。 在ScriptPubKey 中使用的腳本語言在6.4比特幣交易腳本和腳本語言中討論。 但在深入研究這些話題之前,需要先了解交易輸入和輸出的整體結構。
#### 6.3.1.1交易序列化 - 輸出
當交易通過網絡傳輸或在應用程序之間交換時,它們是*序列化*的。 序列化是將數據結構的內部表示轉換為可以一次發送一個字節的格式(也稱為字節流)的過程。 序列化最常用于編碼通過網絡傳輸或用于文件中存儲的數據結構。 交易輸出的序列化格式如表6-1所示:
表6-1交易輸出序列化
Size |Field |Description
-|-|-
8 bytes (little-endian)|Amount|Bitcoin value in satoshis (10-8 bitcoin)
1–9 bytes (VarInt)|Locking-Script Size|Locking-Script length in bytes, to follow
Variable|Locking-Script|A script defining the conditions needed to spend the output
大多數比特幣庫和框架在內部不會將交易存儲為字節流,因為每次需要訪問單個字段時,都需要復雜的解析。為了方便和可讀性,比特幣庫在數據結構(通常是面向對象的結構)中存儲交易。
從交易的字節流表示轉換為庫的內部表示數據結構的過程稱為*反序列化*或*交易解析*。轉換回字節流通過網絡傳輸、哈希或存儲在磁盤上的過程稱為序列化。大多數比特幣庫都有用于交易序列化和反序列化的內置函數。
看看是否可以從序列化的十六進制形式手動解碼 Alice 的交易,找到我們以前看到的一些元素。包含兩個輸出的部分在下面例6-1中加粗顯示:
例6-1。Alice的交易,序列化十六進制表示
0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd73
4d2804fe65fa35779000000008b483045022100884d142d86652a3f47
ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039
ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813
01410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade84
16ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc1
7b4a10fa336a8d752adfffffffff02**60e31600000000001976a914ab6
8025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef800000000000
1976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac** 00000000
這里有一些提示:
- 加粗顯示的部分有兩個輸出,每個都如本節之前所述進行了序列化。
- 0.015比特幣的價值是1,500,000 聰。 十六進制表示是16 e3 60。
- 在序列化交易中,值16 e3 60以小端(最低有效字節優先)字節順序進行編碼,所以它看起來像60 e3 16。
- scriptPubKey的長度為25個字節,十六進制顯示為19。
### 6.3.2交易輸入
交易輸入標識哪個UTXO(通過引用)將被消費,并通過解鎖腳本提供所有權證明。
要構建一個交易,一個錢包從它控制的UTXO中選擇足夠的面值來支付請求的付款。 有時一個UTXO就足夠,有時候需要不止一個。 對于用于付款的每個UTXO,錢包將創建一個指向該UTXO的輸入,使用解鎖腳本解鎖它。
讓我們更詳細地看一下輸入的組成內容。輸入的第一部分是一個指向UTXO的指針,引用交易哈希和輸出索引,這個索引標識了交易中的特定UTXO。 第二部分是解鎖腳本,錢包構建它用以滿足在UTXO中的支付條件。 大多數情況下,解鎖腳本是一個證明比特幣所有權的數字簽名和公鑰,但是并不是所有的解鎖腳本都包含簽名。 第三部分是序列號,稍后再討論。
考慮一下我們在【6.2.1“交易 - 幕后細節】提到的例子。交易輸入是一個名為 vin 的數組(列表):
```
"vin": [
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
]
```
如您所見,列表中只有一個輸入(因為一個UTXO的面值足夠完成付款)。 輸入包含四個元素:
- 一個交易ID,引用包含將要消費的UTXO的交易
- 一個輸出索引(vout),用于標識來自該交易的哪個UTXO被引用(第一個為零)
- 一個 scriptSig(解鎖腳本),滿足UTXO的消費條件,解鎖用于支出
- 一個序列號(稍后討論)
在 Alice 的交易中,輸入指向的交易ID是:
```
7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18
```
輸出索引是0(即由該交易創建的第一個UTXO)。解鎖腳本由Alice的錢包創建,首先檢索引用的UTXO,檢查其鎖定腳本,然后用它來構造滿足要求的解鎖腳本。
僅僅看這個輸入,你可能已經注意到,除了涉及包含該UTXO的交易之外,我們無從了解這個UTXO的任何內容。不知道它的金額(多少聰),不知道鎖定腳本的消費要求。要找到這些信息,必須通過檢索整個交易來檢索被引用的UTXO。請注意,由于輸入的值未明確說明,因此還必須使用被引用的UTXO來計算需要支付的交易費(參見[【6.3.3 交易費】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md#633-交易費))。
不僅僅是Alice的錢包需要檢索輸入中引用的UTXO。一旦將該交易廣播到網絡,每個驗證節點也將需要檢索交易輸入中引用的UTXO,以驗證該交易。
因為缺乏上下文,這些交易本身似乎不完整。它們在輸入中引用了UTXO,但是如果不檢索UTXO,我們就無法知道輸入的值或其鎖定條件。在編寫比特幣軟件時,無論何時,只要是解碼交易以驗證交易、計算費用或檢查解鎖腳本,所編的代碼就必須首先從區塊鏈中檢索引用的UTXO,以便構造輸入引用的UTXO隱含但不存在的上下文。例如,要計算支付總額的交易費,必須知道輸入和輸出值的總和。但是,如果沒有檢索輸入中引用的UTXO,就不能知道這些值。因此,在單個交易中計算交易費用看似簡單,實際上涉及多個交易的多個步驟和數據。
我們可以使用與Bitcoin Core相同的命令序列,就像我們在檢索Alice的交易(getrawtransaction和decodeawtransaction)時一樣。可以得到在前面的輸入中引用的UTXO,如下:
Alice 的UTXO,輸入中引用的來自以前的交易:
```
"vout": [
{
"value": 0.10000000,
"scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG"
}
]
```
我們看到這個UTXO的值為0.1BTC,并且它有一個包含“OP_DUP OP_HASH160 ...”的鎖定腳本(scriptPubKey)。
**提示** 為了充分了解Alice的交易,我們必須檢索作為輸入引用的之前的交易。 檢索以前的交易和未花費的交易輸出的函數很常見,大多數比特幣函數庫和API中都有。
#### 6.3.2.1交易序列化--交易輸入
當交易被序列化在網絡上傳輸時,它們的輸入被編碼成字節流,如下表所示
表6-2 交易輸入序列化
Size |Field |Description
---- | ---- |----
32 bytes|Transaction Hash|Pointer to the transaction containing the UTXO to be spent
4 bytes|Output Index|The index number of the UTXO to be spent; first one is 0
1–9 bytes (VarInt)|Unlocking-Script Size|Unlocking-Script length in bytes, to follow
Variable|Unlocking-Script|A script that fulfills the conditions of the UTXO locking script
4 bytes|Sequence Number|Used for locktime or disabled (0xFFFFFFFF)
與輸出一樣,可以從序列化格式的 Alice 的交易中找到輸入。 首先,將輸入解碼:
```
"vin":
[
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
]
```
現在,看一下下面例6-2中序列化以十六進制表示的字段:
例6-2 Alice的交易,序列化并以十六進制表示
0100000001**186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd73
4d2804fe65fa35779000000008b483045022100884d142d86652a3f47
ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039
ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813
01410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade84
16ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc1
7b4a10fa336a8d752adfffffffff**0260e31600000000001976a914ab6
8025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef800000000000
1976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac00000 000
**提示:**
- 交易ID序列化后與原來的字節逆序呈現,因此以(十六進制)18開頭,以79結尾
- 輸出索引為4字節組的“0”,容易識別
- scriptSig的長度為139個字節,十六進制為8b
- 序列號設置為FFFFFFFF,也容易識別
### 6.3.3 交易費
大多數交易都包含交易費,這是對比特幣礦工保護網絡安全的補償。交易費本身也是一種安全機制,增加攻擊者向網絡中大量發送交易的經濟成本。我們將在[【第十章挖礦】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch10.md)詳細討論挖礦、交易費和礦工得到的獎勵。
這一節解釋交易費是如何被包含在一個典型的交易中的。大多數錢包自動計算并包含交易費。但是, 如果你以編程方式構造交易,或者使用命令行界面,你必須手動計算并包含這些費用。
交易費用是一種激勵措施,激勵將交易納入(挖礦)下一個區塊,但通過對每筆交易收取小額費用,也起到抑制濫用系統的作用。交易費由成功挖到區塊的礦工收取,該區塊把交易記錄在區塊鏈上。
交易費是基于交易的千字節(KB)大小來計算的,而不是交易比特幣的價值。總的來說,交易費是根據比特幣網絡中的市場力量確定的。礦工會依據許多不同的標準,比如交易費,對交易進行優先級排序,甚至在某些特定情況下免費處理交易。但大多數情況下,交易費影響處理優先級,這意味著有足夠費用的交易會更可能被打包進下一個挖出的區塊中;反之交易費不足或者沒有交易費的交易可能會被推遲,基于盡力而為的原則在幾個區塊之后被處理,甚至可能根本不被處理。交易費不是強制的,而且沒有交易費的交易最終也可能會被處理,但是,有交易費會鼓勵優先處理。
隨著時間的推移,交易費的計算方式以及在交易處理優先級上的影響已經發生了變化。起初,交易費是固定的,是網絡中的一個固定常數。隨著網絡容量和交易量的增加,收費結構逐漸放松,并可能受到市場力量的影響。至少從2016年初以來,比特幣網絡容量的限制已經造成交易之間的競爭,從而導致更高的費用,免費交易徹底成為歷史。零費用或非常低費用的交易很少被處理,有時甚至不會在網絡上傳播。
在 Bitcoin Core 中,費用中繼策略由minrelaytxfee選項設置。 目前默認的minrelaytxfee是每KB大小0.00001比特幣或者mBTC的1%。 因此,默認情況下,費用低于0.0001比特幣的交易被視為零費用,只有在內存池有空間時才會被轉發; 否則,會被丟棄。 比特幣節點可以通過調整minrelaytxfee的值來覆蓋默認的費用中繼策略。
任何創建交易的比特幣服務,包括錢包,交易所,零售應用等,都必須實施動態收費。動態費用可以通過第三方費用估算服務或內置的費用估算算法來實現。如果不確定,請從第三方服務開始,隨著經驗積累,如果希望刪除第三方依賴項,再設計并實現自己的算法。
費用估算算法根據網絡能力和“彼此競爭”的交易提供的費用計算適當的費用。這些算法從十分簡單的(最后一個塊中的平均值或中位數)到非常復雜的(統計分析)都有。它們估計必要的費用(以字節的聰為單位),這將使得交易具有很高的可能性被選擇打包進一定數量的塊內。大多數服務為用戶提供高、中、低優先級費用的選擇。高優先級意味著用戶支付更高的交易費,但交易就更可能被打包進下一個區塊中。中低優先級意味著用戶支付較低的交易費,但交易可能需要更長時間才能確認。
許多錢包應用程序使用第三方服務進行費用計算。常用的一個是[earnbitcoin網站這個頁面](https://bitcoinfees.earn.com/) ,它提供了一個API和一個可視化圖表,以聰/字節為單位顯示了不同優先級的費用。
**小貼士:** 固定費用在比特幣網絡上不再可行。 設置固定費用的錢包將導致用戶體驗很差,因為交易往往會被“卡住”,不被確認。不了解比特幣交易和費用的用戶因交易被“卡住” 而感到沮喪,因為他們認為自己已經失去了這筆錢。
下面圖6-2中的圖表顯示了按照10聰/字節增長的實時估算費用,還有每個收費區間中交易的預期確認時間(分鐘和塊數)。 對于每個收費區間(例如,61-70 聰/字節),兩個橫條顯示該區間內過去24小時中交易總數(102,975筆)和未確認交易的數量(1405筆)。 根據圖表,此時推薦的高優先級費用為80 聰/字節,這就使交易在最近的下一個區塊(零塊延遲)中被挖出。 一般來說,一筆常規交易的大小約為226字節,因此單筆交易費建議為18,080 聰(0.00018080 BTC)。
費用估算數據可以通過簡單的HTTP REST API[https://bitcoinfees.earn.com/api/v1/fees/recommended](https://bitcoinfees.earn.com/api/v1/fees/recommended) 例如,在命令行中使用curl命令:
使用費用估算API
```
$ curl https://bitcoinfees.earn.com/api/v1/fees/recommended
{"fastestFee":80,"halfHourFee":80,"hourFee":60}
```
API返回一個satoshi/byte 形式的JSON對象,其中包括當前”最快確認“ (fastestFee),三個塊(halfHourFee)確認和六個塊(hourFee)確認的費用估算值。

圖6-2 bitcoinfees.earn.com提供的費用估算服務
### 6.3.4 把交易費加到交易中
交易的數據結構沒有交易費這個字段。相反,交易費是指輸入和輸出之間的差值。從所有輸入中扣掉所有輸出之后的剩余的金額是礦工收取的交易費:
```
Fees = Sum(Inputs) – Sum(Outputs)
```
正確理解交易比較困難,但又尤為重要。因為如果你要構建你自己的交易,你必須確保沒有因為疏忽沒支付夠輸入,反而在交易中添加一大筆交易費。這意味著你必須計算所有的輸入,如有必要則加上找零, 不然的話,就給了礦工一筆相當可觀的交易費!
舉例來說,如果你消耗了一個20比特幣的UTXO來完成1比特幣的付款,你必須包含一筆19比特幣的找零回到你的錢包。否則,那剩下的19比特幣會被當作交易費,并將由挖出你交易的礦工收走。盡管你會得到高優先級的處理,并且讓一個礦工喜出望外,但這一定不是你想要的結果。
**警告:** 如果你忘記了在手動構造的交易中增加找零的輸出,系統會把找零當作交易費來處理。“不用找了!”也許不是你的真實意愿。
讓我們重溫一下Alice在咖啡店的交易來看看在實際中它如何運作。Alice想花0.015比特幣購買咖啡。為了確保這筆交易能被立即處理,Alice想添加一筆交易費,比如說0.001。這意味著總花費會變成0.016。因此她的錢包需要湊齊一些UXTO加起來是0.016比特幣或更多金額。如果更多的話,就得加上找零。我們假設她的錢包有一個0.2比特幣的UTXO可用。錢包就會消耗掉這個UTXO,創造一個新的0.015的輸出給Bob的咖啡店,另一個0.184比特幣的輸出作為找零回到Alice的錢包,并留下未分配的0.001交易費作為交易的隱含費用。
再看看另一種情況。Eugenia,菲律賓的兒童募捐項目主管,完成了一次為孩子購買教材的籌款活動。她從世界范圍內接收到了好幾千份小額捐款,總額是50比特幣。所以她的錢包塞滿了非常小的UTXO。現在她想用比特幣從本地的一家出版商購買幾百本教材。
現在Eugenia的錢包應用想要構造一個單筆大額付款交易,它必須來自可用的由許多較小的金額組成的UTXO集。這意味著這筆交易是把上百個小額UTXO作為輸入,產生一個用來付給出版商的輸出。輸入數量這么巨大的交易一定會比1KB要大,也許會達到兩至三KB。結果就是它需要比通常交易要高得多的交易費。
Eugenia的錢包應用會測量交易的大小,乘以每KB需要的費用來計算適當的交易費。很多錢包會支付較大的交易費,確保交易得到及時處理。更高交易費不是因為Eugenia付的錢很多,而是因為她的交易很復雜并且尺寸更大——交易費與交易的比特幣金額無關。
## 6.4 比特幣交易腳本和腳本語言
比特幣交易腳本語言,稱為*腳本Scripts*,是一種類似Forth的逆波蘭表示法的基于堆棧的執行語言。 如果聽起來不知所云,可能是你沒有學習過20世紀60年代的編程語言,但是沒關系,我們將在本章中解釋這一切。 放置在UTXO上的鎖定腳本和解鎖腳本都以此腳本語言編寫。 當一筆比特幣交易被驗證時,每一筆輸入中的解鎖腳本與其相應的鎖定腳本一起執行,以確定這筆交易是否滿足支付條件。
腳本是一種非常簡單的語言,設計范圍有限,可在一些硬件上執行,與嵌入式設備一樣簡單。 它僅需要做最少的處理,許多現代編程語言可以做的事情它都不能做。 但將它用于驗證可編程貨幣,這就是一個深思熟慮的安全特性。
如今,大多數比特幣網絡處理的交易都是“Alice付給Bob”的形式,基于一種稱為“P2PKH”(Pay-toPublic-Key-Hash)腳本。但是,比特幣交易不局限于“支付給Bob的比特幣地址”的腳本。事實上,鎖定腳本可以被編寫成表達各種復雜的情況。為了理解這些更為復雜的腳本,我們必須首先了解交易腳本和腳本語言的基礎知識。
本節將會展示比特幣交易腳本語言的各個內容;同時,也會演示如何使用它去表達簡單的花費條件以及這些條件如何通過解鎖腳本來滿足。
**小貼士:** 比特幣交易驗證并不基于靜態模式,而是通過執行腳本語言來實現的。這種語言允許表達幾乎無限的各種條件。這也就是比特幣擁有“可編程的貨幣”的力影響力的方式。
### 6.4.1 圖靈非完備性
比特幣腳本語言包含許多操作碼,但在一個重要方面受到故意的限制——除了條件流程控制之外,沒有循環或復雜的流程控制功能。這樣就確保了腳本語言是非*圖靈完備的Turing Complete*,這意味著腳本的復雜性有限,執行時間也是可預見的。腳本并不是一種通用語言,這些限制確保該語言不被用于創造無限循環或其它類型的邏輯炸彈,這樣的炸彈可以植入在一筆交易中,引起針對比特幣網絡的“拒絕服務”攻擊。記住,每一筆交易都會被網絡中的全節點驗證,受限制的語言能防止交易驗證機制被作為漏洞。
### 6.4.2 無狀態驗證
比特幣交易腳本語言是無狀態的的,在執行腳本之前沒有狀態,或者在執行腳本之后也沒有保存狀態。所以執行腳本所需信息都已包含在腳本中。可以預見的是,一個腳本能在任何系統上以相同的方式執行。如果您的系統驗證了一個腳本,可以確信的是比特幣網絡中的任何其他系統也將能驗證這個腳本,這意味著一個有效的交易對每個人而言都是有效的,而且每一個人都知道這一點。這種結果的可預見性是比特幣系統的一項至關重要的優勢。
### 6.4.3 腳本構建(鎖定與解鎖)
比特幣的交易驗證引擎依賴于兩類腳本來驗證比特幣交易:鎖定腳本和解鎖腳本。
鎖定腳本是一個放置在輸出上面的花費條件:它指定了今后花費這筆輸出必須要滿足的條件。 由于鎖定腳本往往含有一個公鑰或比特幣地址(公鑰哈希值),在歷史上它曾被稱為*腳本公鑰scriptPubKey*。在這本書中,我們稱之為“鎖定腳本”,以承認這種腳本技術的廣泛可能性。在大多數比特幣應用程序中,我們所稱的“鎖定腳本”將以scriptPubKey的形式出現在源代碼中。您還將看到被稱為見證腳本(witness script)的鎖定腳本(參見[隔離見證]章節),或者更普遍稱為*加密難題cryptographic puzzle*。 這些術語在不同的抽象層次都代表同樣的東西。
解鎖腳本是這樣一個腳本,它“解決”或滿足由鎖定腳本放置在輸出上的條件,并允許使用輸出。解鎖腳本是每一筆比特幣交易輸入的一部分,而且往往含有一個由用戶的比特幣錢包(通過用戶的私鑰)生成的數字簽名。由于解鎖腳本常常包含一個數字簽名,因此它曾被稱作*腳本簽名ScriptSig*。在大多數比特幣應用的源代碼中,ScriptSig便是我們所說的解鎖腳本。你也會看到解鎖腳本被稱作“見證”(witness 參見[隔離見證]章節)。在本書中,我們將它稱為“解鎖腳本”,用以承認更廣泛的鎖定腳本需求,因為并非所有解鎖腳本都一定包含簽名。
每一個比特幣驗證節點會通過同時執行鎖定和解鎖腳本來驗證一筆交易。每個輸入都包含一個解鎖腳本,并引用了之前存在的UTXO。 驗證軟件將復制解鎖腳本,檢索輸入所引用的UTXO,并從該UTXO復制鎖定腳本。 然后依次執行解鎖腳本和鎖定腳本。 如果解鎖腳本滿足鎖定腳本的條件,則輸入有效(請參閱[【6.4.3.3 解鎖腳本和鎖定腳本的單獨執行】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md#6433-解鎖和鎖定腳本的單獨執行))。 所有輸入都是作為交易總體驗證的一部分獨立驗證的。
請注意,UTXO被永久地記錄在區塊鏈中,因此是不變的,并且不受在新交易中引用失敗的嘗試的影響。 只有正確滿足輸出條件的有效交易才會導致輸出被視為“已花費”,然后從未花費交易輸出集(UTXO set)中移除。
下圖是最常見類型的比特幣交易(P2PKH:對公鑰哈希的付款)的解鎖和鎖定腳本的示例,顯示在腳本驗證之前解除鎖定和鎖定腳本的連接所產生的組合腳本:

圖6-3 結合scriptSig和scriptPubKey評估交易腳本
#### 6.4.3.1腳本執行堆棧
比特幣的腳本語言被稱為基于堆棧的語言,因為它使用一種被稱為*堆棧stack*的數據結構。堆棧是一個非常簡單的數據結構,可以被視為一疊卡片。堆棧允許兩個操作:推送push和彈出pop。 推送就是在堆棧頂部添加一個項目。 彈出從堆棧中刪除最頂端的項。堆棧上的操作只作用于堆棧最頂端項目。堆棧數據結構也被稱為“后進先出”( Last-In-First-Out)或 “LIFO” 隊列。
腳本語言執行腳本時,從左到右處理每個項目。數字(數據常量)被推送入堆棧。操作碼(Operators)從堆棧中推送或彈出一個或多個參數,對其進行操作,并可能將結果推送到堆棧上。例如,操作碼 OP_ADD 將從堆棧中彈出兩個項目,對它們求和,并將求和結果值推送到堆棧上。
條件操作碼(Conditional operators)對一個條件進行評估,產生一個 TRUE 或 FALSE 的布爾結果(boolean result)。例如, OP_EQUAL 從堆棧中彈出兩個項目,如果它們相等,則推送為 TRUE(由數字1表示),否則推送為 FALSE(由數字0表示)。比特幣交易腳本通常包含條件操作碼,以便它們可以產生用來表示有效交易的 TRUE 結果。
#### 6.4.3.2一個簡單的腳本
現在讓我們將學到的關于腳本和堆棧的知識應用到一些簡單的例子中。
如圖6-4,腳本“ 2 3 OP_ADD 5 OP_EQUAL ”演示了算術加法操作碼 OP_ADD ,該操作碼將兩個數字相加,然后把結果推送到堆棧, 后面的條件操作符 OP_EQUAL 是驗算之前的兩數之和是否等于 5 。為了簡化起見,前綴OP_在演示步驟過程中被省略了。有關可用腳本操作碼和函數的更多詳細信息,請參見[【附錄:交易腳本】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/appdx-scriptops.md)。

圖6-4比特幣的腳本驗證中,執行簡單的數學運算
盡管絕大多數解鎖腳本都指向一個公鑰哈希值(本質上就是比特幣地址),因此需要使用資金的所有權證明,但腳本不必那么復雜。任何解鎖和鎖定腳本的任何組合如果結果為真(TRUE),則為有效。前面用于腳本語言示例的簡單算術計算同樣也是一個有效的鎖定腳本,該腳本能用于鎖定交易輸出。
使用部分算術腳本作為鎖定腳本的示例:
```
3 OP_ADD 5 OP_EQUAL
```
該腳本能被包含解鎖腳本輸入的一筆交易所滿足:
```
2
```
驗證軟件將鎖定和解鎖腳本組合起來,結果腳本是:
```
2 3 OP_ADD 5 OP_EQUAL
```
正如在上圖6-4中所看到的一步步例子,當腳本被執行時,結果是OP_TRUE,交易有效。這不僅是一個有效的交易輸出鎖定腳本,同時產生的UTXO也能被任何具備算術技能知道數字2能夠滿足腳本的人所花費。
**小貼士:** 如果堆棧頂部的結果顯示為TRUE(標記為{0x01}),即為任何非零值,或腳本執行后堆棧為空,則交易有效。如果堆棧頂部的結果顯示為FALSE(0字節空值,標記為{})或腳本執行被操作碼明確終止,如OP_VERIFY、 OP_RETURN,或條件終止符如OP_ENDIF,則交易無效。詳見[【附錄:交易腳本】。](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/appdx-scriptops.md)
以下是一個稍微復雜一點的腳本,它用于計算 2+7-3+1 。注意,當腳本在同一行包含多個操作碼時,堆棧允許一個操作碼的結果由下一個操作碼執行。
```
2 7 OP_ADD 3 OP_SUB 1 OP_ADD 7 OP_EQUAL
```
請試著用紙筆自行演算腳本,當腳本執行完畢時,堆棧中會留下一個TRUE值。
#### 6.4.3.3 解鎖腳本和鎖定腳本的單獨執行
在最初版本的比特幣客戶端中,解鎖腳本和鎖定腳本按順序連起來執行。出于安全因素考慮,在2010年發生了改變,因為存在一個漏洞,允許格式錯誤的解鎖腳本將數據推送到堆棧并損壞鎖定腳本。而在當前的方案中,腳本是單獨執行的,在兩次執行之間傳輸堆棧,如下所述。
首先,使用堆棧執行引擎執行解鎖腳本。如果解鎖腳本在執行過程中未報錯(例如:沒有留下“dangling”操作碼),則復制主堆棧,并執行鎖定腳本。如果從解鎖腳本中復制而來的堆棧數據執行鎖定腳本的結果為“TRUE",那么解鎖腳本就成功地滿足了鎖定腳本所設置的條件,因此,該輸入是一個能使用該UTXO的有效授權。如果合并腳本執行后的結果是”TRUE“以外的任何結果,輸入都是無效的,因為它不能滿足UTXO中所設置的使用該筆資金的條件。
### 6.4.4 P2PKH(Pay-to-Public-Key-Hash)
比特幣網絡處理的大多數交易都是由“付款至公鑰哈希”或P2PKH腳本鎖定的輸出,這些輸出都含有一個鎖定腳本,將輸入鎖定為一個公鑰哈希值,即我們常說的比特幣地址。由P2PKH腳本鎖定的輸出可以通過提供一個公鑰和由相應私鑰創建的數字簽名來解鎖(花費)。參見[【6.5數字簽名(ECDSA)】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md#65數字簽名ecdsa)。
例如,我們再次回顧一下Alice向Bob咖啡館支付的案例。Alice向Bob咖啡館的比特幣地址支付0.015比特幣,該筆交易的輸出內容為以下形式的鎖定腳本:
```
OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
```
腳本中的 Cafe Public Key Hash 即為咖啡館的比特幣地址,但該地址不是基于Base58Check編碼。事實上,大多數比特幣地址的*公鑰哈希public key hash*都顯示為十六進制碼,而不是大家所熟知的以1開頭的基于Bsase58Check編碼的比特幣地址。
上述鎖定腳本相應的解鎖腳本是:
```
<Cafe Signature> <Cafe Public Key>
```
將兩個腳本結合起來可以形成如下組合驗證腳本:
```
<Cafe Signature> <Cafe Public Key> OP_DUP OP_HASH160
<Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
```
只有當解鎖腳本與鎖定腳本的設定條件相匹配時,執行組合驗證腳本時才會顯示結果為真(TRUE)。換句話說,只有當解鎖腳本得到了咖啡館的有效簽名,交易執行結果才會被通過(結果為真),該有效簽名是從與公鑰哈希相匹配的咖啡館的私鑰中所獲取的。
圖6-5和圖6-6(分兩部分)顯示了組合腳本一步步檢驗交易有效性的過程。

圖6-5評估P2PKH交易的腳本(1/2)

圖6-6評估P2PKH交易的腳本(2/2)
## 6.5 數字簽名(ECDSA)
到目前為止,我們還沒有深入了解“數字簽名”的細節。在本節中,我們將研究數字簽名的工作原理,以及如何在不出示私鑰的情況下提供私鑰的所有權證明。
比特幣中使用的數字簽名算法是*橢圓曲線數字簽名算法(Elliptic Curve Digital Signature Algorithm)*或*ECDSA*。 ECDSA是基于橢圓曲線私鑰/公鑰對用于數字簽名的算法,如[【4.1.5 橢圓曲線加密(Elliptic Curve Cryptography)解釋】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch04.md#415-橢圓曲線加密elliptic-curve-cryptography解釋)所述。ECDSA用于腳本函數OP_CHECKSIG,OP_CHECKSIGVERIFY,OP_CHECKMULTISIG和OP_CHECKMULTISIGVERIFY。每當在鎖定腳本中看到這些時,解鎖腳本都必須包含一個ECDSA簽名。
數字簽名在比特幣中有三種用途(請參閱下面的側欄)。第一,簽名證明私鑰的所有者,即資金所有者,有權花費這些資金。第二,授權證明是不可拒絕的(不可否認性)。第三,簽名證明交易(或交易的具體部分)在簽字之后沒有也不能被任何人修改。
請注意,交易的每筆輸入都是獨立簽名的。這一點至關重要,因為不管是簽名還是輸入都不必屬于同一“所有者”或者被其使用。事實上,一個名為 “CoinJoin” 的特定交易方案就使用這個特性來創建多方私密交易。
**注意:** 每個交易輸入和它包含的任何簽名完全獨立于任何其他輸入或簽名。 多方可以協作構建交易,但是每方只能簽名一個輸入。
**維基百科對 “數字簽名 ”的定義:**
數字簽名是用于證明數字消息或文檔的真實性的數學方案。 有效的數字簽名使收件人有理由相信消息是由已知的發件人創建的(身份驗證),發件人不能否認已發送的消息(不可否認性),并且消息在傳輸過程中沒有更改(完整性)。
來源:?[https://en.wikipedia.org/wiki/Digital_signature](https://en.wikipedia.org/wiki/Digital_signature)*
### 6.5.1 數字簽名如何工作
數字簽名是一種*數學方案mathematical scheme*,由兩部分組成的:第一部分是使用私鑰(簽名密鑰)從消息(交易)創建簽名的算法; 第二部分是允許任何人給定依據給定的消息和公鑰驗證簽名的算法。
#### 6.5.1.1 創建數字簽名
在比特幣的ECDSA算法的實現中,被簽名的“消息”是交易,或更確切地說是交易中特定數據子集的哈希值(參見[【6.5.3簽名哈希類型(SIGHASH)】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md#653簽名哈希類型sighash))。簽名密鑰是用戶的私鑰,結果就是簽名:
\(\(Sig = F_{sig}(F_{hash}(m), dA)\)\)
這里的:
- *dA* 是簽名私鑰
- *m* 是交易(或其部分)
- *F<sub>hash</sub>* 是散列函數
- *F<sub>sig</sub>* 是簽名算法
- *Sig* 是結果簽名
ECDSA數學運算的更多細節可以在[【6.5.4 ECDSA數學】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md#654-ecdsa數學)找到。
函數*F<sub>sig</sub>* 產生由兩個值組成的簽名Sig,通常稱為R和S:
```
Sig = (R, S)
```
現在已經計算了兩個值R和S,它們就使用一種稱為*可分辨編碼規則Distinguished Encoding Rules*或*DER*的國際標準編碼方案,序列化為字節流。
#### 6.5.1.2 簽名序列化(DER)
我們再來看看Alice創建的交易。 在交易輸入中有一個解鎖腳本,其中包含Alice的錢包中的以下DER編碼簽名:
```
3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301
```
該簽名是Alice的錢包生成的R和S值的序列化字節流,證明她擁有授權花費該輸出的私鑰。 序列化格式包含以下9個元素:
- *0x30*表示DER序列的開始
- *0x45* - 序列的長度(69字節)
- *0x02* - 一個整數值
- *0x21* - 整數的長度(33字節)
- *00884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb* - R值
- *0x02* - 接下來是一個整數
- *0x20* - 整數的長度(32字節)
- *4b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813* - S值
- 后綴(*0x01*)指示使用的哈希的類型(SIGHASH_ALL)
看看您是否可以使用此列表解碼 Alice 的序列化(DER編碼)簽名。 重要的數字是R和S; 數據的其余部分是DER編碼方案的一部分。
### 6.5.2 驗證簽名
要驗證簽名,必須有簽名(*R*和*S*)、序列化交易和公鑰(對應于用于創建簽名的私鑰)。本質上,簽名的驗證意味著“只有生成此公鑰的私鑰的所有者,才能在此交易上產生此簽名。”
簽名驗證算法采用消息(交易或其部分的哈希值)、簽名者的公鑰和簽名(R和S值),如果簽名對該消息和公鑰有效,則返回 TRUE 值。
### 6.5.3 簽名哈希類型(SIGHASH)
數字簽名被應用于消息,在比特幣中,就是交易本身。簽名意味著簽名者對特定交易數據的*承諾commitment*。最簡單的形式是,簽名應用于整個交易,從而承諾所有輸入,輸出和其他交易字段。但是,一個簽名也可以只承諾交易數據的子集,這對于我們將在本節中看到的許多場景是有用的。
比特幣簽名使用 SIGHASH 標志顯示,交易數據的哪一部分包含在私鑰簽名的哈希中。 SIGHASH 標志是附加到簽名的單個字節。每個簽名都有一個SIGHASH標志,該標志在隨輸入不同而不同。一筆交易如果有三個簽名輸入,就會有不同SIGHASH標志的三個簽名,每個簽名簽署(承諾)交易的不同部分。
記住,每個輸入可能在其解鎖腳本中包含一個簽名。因此,包含多個輸入的交易可以擁有具有不同SIGHASH標志的多個簽名,這些標志在每個輸入中承諾交易的不同部分。還要注意,比特幣交易可能包含來自不同“所有者”的輸入,他們在部分構建(和無效)的交易中可能僅簽名一個輸入,需要與他人協作收集所有必要的簽名后才能使交易生效。許多SIGHSASH標志類型,只有考慮到由許多參與者在比特幣網絡之外共同協作去更新僅部分簽名了的交易,才具有意義。
有三個SIGHASH標志:ALL,NONE和SINGLE,如下表6-3所示。
表6-3 SIGHASH類型和意義
SIGHASH flag |Value |Description
---- | ---- |----
ALL|0x01|簽名應用到所有輸出輸入
NONE|0x02|簽名只應用到所有輸入,不包括任何輸出
SINGLE|0x03|簽名應用到所有輸入和與簽名輸入具有相同索引號的那個輸出
另外還有一個修飾符標志SIGHASH_ANYONECANPAY,它可以與前面的每個標志組合使用。 當設置ANYONECANPAY時,只有一個輸入被簽名,其余的(及其序列號)保持開放以進行修改。 ANYONECANPAY的值為0x80,并通過按位OR運算,得到如下表6-4所示的組合標志:
表6-4 帶修飾符的SIGHASH類型及其含義
SIGHASH flag |Value |Description
---- | ---- |----
ALL|ANYONECANPAY |0x81|簽名應用到一個輸入和所有輸出
NONE|ANYONECANPAY|0x82|簽名應用到一個輸入,不包括任何輸出
SINGLE|ANYONECANPAY|0x83|簽名應用到一個輸入和具有相同索引號的輸出
這些標志組合總結如下圖6-7。

圖6-7 不同sighash組合的總結
簽名和驗證期間應用sighash標志的方式是生成交易的副本并截斷其中的某些字段(設置為零長度并清空)。繼而交易被序列化,SIGHASH標志被添加到序列化交易的結尾,并將結果哈希,得到的哈希值即是被簽名的“消息”。 根據使用的SIGHASH標志,交易的不同部分會被截斷。 所得到的哈希值取決于交易中數據的不同子集。 在進行哈希前的最后一步,借助于包含SIGHASH,簽名提交了SIGHASH類型,因此不能再更改(例如,被礦工)。
**小貼士:** 所有SIGHASH類型都簽署到交易的nLocktime字段(請參閱[【7.5.1交易鎖定時間(nLocktime)】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch07.md#751交易鎖定時間nlocktime))。 此外,SIGHASH類型本身在交易簽名之前就被附加到交易中了,因此一旦簽名就不能再修改它。
在Alice的交易(參見[【6.5.1.2 簽名序列化(DER)】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md#6512-簽名序列化der))的例子中,我們看到DER編碼簽名的最后一部分是01,這是SIGHASH_ALL標志。這會導致鎖定交易數據,因此Alice的簽名承諾的是所有的輸入和輸出狀態。 這是最常見的簽名形式。
我們來看看其他一些SIGHASH類型,以及如何在實踐中使用它們:
*ALL | ANYONECANPAY*
這種結構可以用來做“眾籌”交易,試圖籌集資金的人可以用單筆輸出來構建一個交易,單筆輸出將“目標”金額付給眾籌發起人。這樣的交易顯然是無效的,因為它沒有輸入。但是現在其他人可以添加自己的輸入來修改它,實現捐贈。他們用ALL | ANYONECANPAY簽名自己的輸入,除非收集到足夠的輸入以達到輸出的價值,否則交易無效,每次捐贈是一項“抵押”,直到募集到整個目標金額,籌款人才能收取。
*NONE*
該結構可用于創建特定金額的“不記名支票”或“空白支票”。它對輸入進行承諾,但允許更改輸出鎖定腳本。任何人都可以將自己的比特幣地址寫入輸出鎖定腳本并兌換交易。不過,輸出值本身被簽名鎖定。
*NONE | ANYONECANPAY*
這種結構可以用來建造一個“吸塵器”。用戶的錢包中擁有微小UTXO,因為微小UTXO的面值還不夠支付交易費,所以用戶無法花費這些費用。借助這種類型的簽名,微小UTXO可以捐贈給任何人,收集起來隨時消費。
有一些修改或擴展SIGHASH系統的建議。其中一個是Blockstream的Glenn Willen作為Elements項目的一部分提議的Bitmask Sighash模式。其目的是創建一個靈活的SIGHASH類型的替代方案,允許使用“輸入和輸出的任意的,礦工可以重寫的位掩碼”來表示“更復雜的合同預承諾方案,例如分布式資產交易所中有變更的已簽名的報價”。
**注釋:** 您不會在用戶的錢包應用程序中看到SIGHASH標志作為一個功能呈現。 有極少數例外,錢包會構建P2PKH腳本,并使用SIGHASH_ALL標志進行簽名。 要使用不同的SIGHASH標志,必須編寫軟件來構造和簽名交易。 更重要的是,SIGHASH標志可以被特殊用途的比特幣應用程序使用,實現新的用途。
### 6.5.4 ECDSA數學
如前所述,簽名由數學函數*F<sub>sig</sub>* 創建,該函數生成了由*R*和*S*兩個值組成的簽名。在本節中,我們將更詳細查看*F<sub>sig</sub>* 函數。
簽名算法首先生成一個 *短暫的ephemeral*(臨時的)私公鑰對。 該臨時密鑰對用于在涉及簽名私鑰和交易哈希的轉換之后計算*R*和*S*值。
臨時密鑰對基于隨機數*k*,后者用作臨時私鑰。 從*k*,生成相應的臨時公鑰*P*(以P = k * G計算,與派生比特幣公鑰相同);參見[【4.1.4 公鑰】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch04.md#414-公鑰)部分)。數字簽名的*R*值則是臨時公鑰*P*的x坐標。
在此基礎上,算法計算簽名的*S*值,使得:
S = k<sup>-1</sup> (Hash(m) + dA * R) mod n
其中:
- *k*是臨時私鑰
- *R*是臨時公鑰的x坐標
- *dA*是簽名私鑰
- *m*是交易數據
- *n*是橢圓曲線的階
驗證是簽名生成函數的倒數,使用R,S值和公鑰來計算值P,該值是橢圓曲線上的一個點(簽名創建時使用的臨時公鑰):
P = S<sup>-1</sup> * Hash(m) * G + S<sup>-1</sup> * R * Qa
其中:
- *R*和*S*是簽名值
- *Qa*是Alice的公鑰
- *m*是簽名的交易數據
- *G*是橢圓曲線生成點
如果計算出的點*P*的*x*坐標等于*R*,則驗證者就得出結論,簽名是有效的。
請注意,在驗證簽名時,私鑰既不知道也不會泄露。
> **小貼士:** ECDSA是一個相當復雜的數學問題,完整的解釋超出了本書的范圍。 網上有一些很棒的指南會指導你一步步學習:搜索“ECDSA解釋”或嘗試這個:http://bit.ly/2r0HhGB。
### 6.5.5 隨機性在簽名中的重要性
如我們在[【6.5.4 ECDSA數學】](https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md#654-ecdsa數學)中所看到的,簽名生成算法使用隨機密鑰*k*作為臨時私有公鑰對的基礎。 *k* 的值不重要,只要它是隨機的。如果使用相同的*k*值用在不同的消息(交易)上生成兩個簽名,則任何人都可以計算簽名私鑰。在簽名算法中使用相同的 *k* 值會導致私鑰泄露!
> **警告** 如果在兩個不同的交易中,簽名算法使用相同的 *k*值,則私鑰就能被計算出來,暴露給全世界!
這不僅僅在理論上可能,我們已經看到在比特幣交易簽名算法的幾種不同實現中,這個問題導致了私鑰暴露。人們由于無意中重復使用 *k* 值導致資金被盜。重用 *k* 值的最常見原因是未正確初始化的隨機數生成器。
為了避免此漏洞,行業最佳實踐是,不使用以熵為種子的隨機數生成器生成*k*,而是使用以交易數據本身為種子的確定性隨機流程。這確保每個交易產生不同的 *k* 值。在互聯網工程任務組(Internet Engineering Task Force)發布的[RFC 6979](https://tools.ietf.org/html/rfc6979)中定義了 *k* 值的確定性初始化的行業標準算法。
如果您正在部署在比特幣中簽名交易的算法,則必須使用RFC 6979或類似的確定性隨機算法來確保為每個交易生成不同的 *k* 值。
## 6.6 比特幣地址,余額和其他抽象
我們在本章開始時發現,交易的“幕后”看起來與錢包、區塊鏈瀏覽器和其他面向用戶的應用程序中呈現出來的非常不同。 前幾章中的許多簡單而熟悉的概念,如比特幣地址和余額,似乎都沒有出現在交易結構中。 我們看到交易本身并不包含比特幣地址,而是通過鎖定和解鎖比特幣離散值的腳本進行操作。 余額也不存在于這個系統中的任何地方,但是每個錢包應用程序都明明白白地顯示了用戶錢包的余額。
現在,我們已經探討了比特幣交易中實際包含的內容,我們可以研究如何從交易的看似原始的組件中派生出更高級別的抽象。
我們再來看看Alice的交易在一個常用的區塊瀏覽器(下圖6-8)中呈現的:

圖6-8 Alice與Bob咖啡館的交易
在交易的左側,區塊鏈瀏覽器將Alice的比特幣地址顯示為“發送者”。其實這個信息本身并不在交易中。當區塊鏈瀏覽器檢索到交易時,它還檢索在輸入中引用的上一個交易,并從該舊交易中提取第一個輸出。在該輸出內是一個鎖定腳本,將UTXO鎖定到Alice的公鑰哈希(P2PKH腳本)。區塊鏈瀏覽器提取公鑰哈希,并使用Base58Check編碼對其進行編碼,以生成和顯示表示該公鑰的比特幣地址。
同樣,在右側,區塊鏈瀏覽器顯示了兩個輸出:第一個到Bob的比特幣地址,第二個到Alice的比特幣地址(作為找零)。為了創建這些比特幣地址,區塊鏈瀏覽器再次從每個輸出中提取鎖定腳本,將其識別為P2PKH腳本,從中提取公鑰哈希。最后,區塊鏈瀏覽器使用Base58Check重新編碼公鑰哈希,生成和顯示比特幣地址。
如果點擊Bob的比特幣地址,區塊鏈瀏覽器將顯示Bob的比特幣地址的余額,如下圖6-9:

圖6-9 Bob的比特幣地址的余額
區塊鏈瀏覽器顯示了Bob的比特幣地址的余額。但是比特幣系統中卻沒有“余額”的概念。這里顯示的余額其實是由區塊鏈瀏覽器按如下方式構建出來的:
為了構建“總收入”數量,區塊鏈瀏覽器首先解碼比特幣地址的Base58Check編碼,檢索編碼在地址內的Bob公鑰的160位哈希值。然后,區塊鏈瀏覽器搜索交易數據庫,使用包含Bob公鑰哈希的P2PKH鎖定腳本查找輸出。通過匯總所有輸出的值,區塊鏈瀏覽器就得出了接收總額。
構建當前余額(顯示為“最終余額”)需要更多的工作。區塊鏈瀏覽器保持一個單獨的數據庫,即UTXO集,其中保存著當前未被使用的輸出。為了維護這個數據庫,區塊鏈瀏覽器必須實時監控比特幣網絡中出現的未經確認的交易,添加新創建的UTXO,刪除已用UTXO。這是一個復雜的過程,依賴于在交易傳播過程中跟蹤交易,以及與比特幣網絡保持共識,以確保跟隨正確的主鏈。區塊鏈瀏覽器有時也會出現未能保持同步,導致其對UTXO集的跟蹤掃描不完整或不正確。
區塊鏈瀏覽器從UTXO集中,匯總引用Bob的公鑰哈希的所有未花費輸出的金額,就得出顯示給用戶的“最終余額”數值。
為了生成這張畫面,得到這兩個“余額”,區塊鏈瀏覽器必須索引和搜索數十、數百甚至數十萬的交易。
總之,通過錢包應用程序,區塊鏈瀏覽器和其他比特幣用戶界面呈現給用戶的信息通常由更高級別的抽象組成,這些抽象是通過搜索許多不同的交易、檢查其內容和操作其中包含的數據而派生出來的。通過呈現這種簡單的比特幣交易視圖(類似于從一個發送者到一個接收者的銀行支票),這些應用程序必須抽象出許多潛在的細節。它們主要關注常見的交易類型:每個輸入上具有SIGHASH_ALL簽名的P2PKH交易。因此,雖然比特幣應用程序以易于閱讀的方式呈現所有了80%以上的交易,但有時候會被偏離規范的交易困擾。對于包含更復雜的鎖定腳本,或不同SIGHASH標志,或多個輸入和輸出的交易,這種抽象就顯得簡單和不足。
每天都有數百個不包含P2PKH輸出的交易在區塊鏈上被確認。 區塊鏈瀏覽器經常向他們發出紅色警告信息,表示無法解碼地址。以下鏈接包含最近不能完全解碼的“奇怪交易”:https://blockchain.info/strange-transactions.
正如我們將在下一章中看到的,這些并不一定是奇怪的交易。它們是包含比常見的P2PKH更復雜的鎖定腳本的交易。接下來我們將學習如何解碼和理解更復雜的腳本及其支持的應用程序。