8.1 簡介
挖礦是增加比特幣貨幣供應的一個過程。挖礦同時還保護著比特幣系統的安全,防止欺詐交易,避免“雙重支付”,“雙重支付”是指多次花費同一筆比特幣。礦工們通過為比特幣網絡提供算力來換取獲得比特幣獎勵的機會。
礦工們驗證每筆新的交易并把它們記錄在總帳簿上。每10分鐘就會有一個新的區塊被“挖掘”出來,每個區塊里包含著從上一個區塊產生到目前這段時間內發生的所有交易,這些交易被依次添加到區塊鏈中。我們把包含在區塊內且被添加到區塊鏈上的交易稱為“確認”交易,交易經過“確認”之后,新的擁有者才能夠花費他在交易中得到的比特幣。
礦工們在挖礦過程中會得到兩種類型的獎勵:創建新區塊的新幣獎勵,以及區塊中所含交易的交易費。為了得到這些獎勵,礦工們爭相完成一種基于加密哈希算法的數學難題,這些難題的答案包括在新區塊中,作為礦工的計算工作量的證明,被稱為”“工作量證明”。該算法的競爭的機制以及獲勝者有權在區塊鏈上進行交易記錄的機制,這二者是比特幣安全的基石。
新比特幣的生成過程被稱為挖礦是因為它的獎勵機制被設計為速度遞減模式,類似于貴重金屬的挖礦過程。比特幣的貨幣是通過挖礦發行的,類似于中央銀行通過印刷銀行紙幣來發行貨幣。礦工通過創造一個新區塊得到的比特幣數量大約每四年(或準確說是每210,000個塊)減少一半。開始時為2009年1月每個區塊獎勵50個比特幣,然后到2012年11月減半為每個區塊獎勵25個比特幣。之后將在2016年的某個時刻再次減半為每個新區塊獎勵12.5個比特幣。基于這個公式,比特幣挖礦獎勵以指數方式遞減,直到2140年。屆時所有的比特幣(20,999,999,980)全部發行完畢。換句話說在2140年之后,不會再有新的比特幣產生。
礦工們同時也會獲取交易費。每筆交易都可能包含一筆交易費,交易費是每筆交易記錄的輸入和輸出的差額。在挖礦過程中成功“挖出”新區塊的礦工可以得到該區塊中包含的所有交易“小費”。目前,這筆費用占礦工收入的0.5%或更少,大部分收益仍來自挖礦所得的比特幣獎勵。然而隨著挖礦獎勵的遞減,以及每個區塊中包含的交易數量增加,交易費在礦工收益中所占的比重將會逐漸增加。在2140年之后,所有的礦工收益都將由交易費構成。
“挖礦”這個詞有一定的誤導性。它容易引起對貴重金屬采礦的的聯想,從而使我們的注意力都集中在每個新區塊產生的獎勵上。盡管挖礦帶來的獎勵是一種激勵,但它最主要的目的并不是獎勵本身或者新幣的產生。如果只把挖礦看作生產新幣的過程,那你是把手段(激勵措施)當成了目的。挖礦是一種將結算所去中心化的過程,每個結算所對處理的交易進行驗證和結算。挖礦保護了比特幣系統的安全,并且實現了在沒有中心機構的情況下,也能使整個比特幣網絡達成共識。
挖礦這個發明使比特幣變得很特別,這種去中心化的安全機制是點對點的電子貨幣的基礎。鑄造新幣的獎勵和交易費是一種激勵機制,它可以調節礦工行為和網絡安全,同時又完成了比特幣的貨幣發行。
8.1.1 比特幣經濟學和貨幣創造
通過創造出新區塊,比特幣以一個確定的但不斷減慢的速率被鑄造出來。大約每十分鐘產生一個新區塊,每一個新區塊都伴隨著一定數量從無到有的全新比特幣。每開采210,000個塊,大約耗時4年,貨幣發行速率降低50%。在比特幣運行的第一個四年中,每個區塊創造出50個新比特幣。
比特幣貨幣供應速度隨著時間發生幾何級降低總量有限并且發行速度遞減創造了一種抗通脹的貨幣供應模式。法幣可被中央銀行無限制地印刷出來,而比特幣永遠不會因超額印發而出現通脹。
通貨緊縮貨幣
最重要并且最有爭議的一個結論是一種事先確定的發行速率遞減的貨幣發行模式會導致貨幣通貨緊縮(簡稱通縮)。通縮是一種由于貨幣的供應和需求不匹配導致的貨幣增值的現象。它與通脹相反,價格通縮意味著貨幣隨著時間有越來越強的購買力。
許多經濟學家提出通縮經濟是一種無論如何都要避免的災難型經濟。因為在快速通縮時期,人們預期著商品價格會下跌,人們將會儲存貨幣,避免花掉它。這種現象充斥了日本經濟“失去的十年”,就是因為在需求坍塌之后導致了滯漲狀態。
比特幣專家們認為通縮本身并不壞。更確切地說,我們將通縮與需求坍塌聯系在一起是因為過去出現的一個特例。在法幣屆,貨幣是有可能被無限制印刷出來的,除非遇到需求完全崩塌并且毫無發行貨幣意愿的情形,因此經濟很難進入滯漲期。而比特幣的通縮并不是需求坍塌引起的,它遵循一種預定且有節制的貨幣供應模型。
實際上,通縮貨幣會讓賣家考慮到折現的影響,容易誘發過度的囤積本能,除非這部分折現率超過買家的囤積本能。因為買賣雙方都有囤積的動機,這兩種折現率會因為雙方的囤積本能相互抵消,而達成一個平衡價格。因此即使在比特幣價格貼現率為30%的情況下,大部分使用比特幣的零售商并不會感受到花費比特幣很困難,也能因此盈利。當然,比特幣這種不是因經濟快速衰退而引起的通縮,是否會引發其他問題,仍有待觀察。
8.2 去中心化共識
在不考慮相信任何人的情況下,比特幣網絡中的所有參與者如何達成對任意一個所有權的共識呢?所有的傳統支付系統都依賴于一個中心認證機構,依靠中心機構提供的結算服務來驗證并處理所有的交易。比特幣沒有中心機構,幾乎所有的完整節點都有一份公共總帳的備份,這份總帳可以被視為認證過的記錄。區塊鏈并不是由一個中心機構創造的,它是由比特幣網絡中的所有節點各自獨立競爭完成的。換句話說比特幣網絡中的所有節點,依靠著節點間的不穩定的網絡連接所傳輸的信息,最終得出同樣的結果并維護了同一個公共總帳。
中本聰的主要發明就是這種去中心化的自發共識機制。這種自發,是指沒有經過明確選舉或者沒有固定達成的共識的時間。換句話說,共識是數以千計的獨立節點遵守了簡單的規則通過異步交互自發形成的產物。所有的比特幣屬性,包括貨幣、交易、支付以及不依靠中心機構和信任的安全模型等都是這個機制的衍生物。
比特幣的去中心化共識由所有網絡節點的4種獨立過程相互作用而產生:
? 每個全節點依據綜合標準對每個交易進行獨立驗證
? 通過完成工作量證明算法的驗算,挖礦節點將交易記錄獨立打包進新區塊,
? 每個節點獨立的對新區塊進行校驗并組裝進區塊鏈
? 每個節點對區塊鏈進行獨立選擇,在工作量證明機制下選擇累計工作量最大的區塊鏈
8.3 交易的獨立校驗
錢包軟件通過收集UTXO、提供正確的解鎖腳本、構造支付給接收者的輸出這一系列的方式來創建交易。產生的交易隨后將被發送到比特幣網絡臨近的節點,從而使得該交易能夠在整個比特幣網絡中傳播。
然而,在交易傳遞到臨近的節點前,每一個收到交易的比特幣節點將會首先驗證該交易,這將確保只有有效的交易才會在網絡中傳播,而無效的交易將會在第一個節點處被廢棄。每一個節點在校驗每一筆交易時,都需要對照一個長長的標準列表:
?交易的語法和數據結構必須正確。
?輸入與輸出列表都不能為空。
?交易的字節大小是小于 MAX_BLOCK_SIZE 的。
?每一個輸出值,以及總量,必須在規定值的范圍內 (小于2,100萬個幣,大于0)。
?沒有哈希等于0,N等于-1的輸入(coinbase交易不應當被中繼)。
?nLockTime是小于或等于 INT_MAX 的。
?交易的字節大小是大于或等于100的。
?交易中的簽名數量應小于簽名操作數量上限。
?解鎖腳本( scriptSig )只能夠將數字壓入棧中,并且鎖定腳本( scriptPubkey )必須要符合isStandard的格式 (該
格式將會拒絕非標準交易)。
?池中或位于主分支區塊中的一個匹配交易必須是存在的。
?對于每一個輸入,如果引用的輸出存在于池中任何的交易,該交易將被拒絕。
?對于每一個輸入,在主分支和交易池中尋找引用的輸出交易。如果輸出交易缺少任何一個輸入,該交易將成為一個孤
立的交易。如果與其匹配的交易還沒有出現在池中,那么將被加入到孤立交易池中。
?對于每一個輸入,如果引用的輸出交易是一個coinbase輸出,該輸入必須至少獲得 COINBASE_MATURITY (100)個確認。
?對于每一個輸入,引用的輸出是必須存在的,并且沒有被花費。
?使用引用的輸出交易獲得輸入值,并檢查每一個輸入值和總值是否在規定值的范圍內 (小于2100萬個幣,大于0)。
?如果輸入值的總和小于輸出值的總和,交易將被中止。
?如果交易費用太低以至于無法進入一個空的區塊,交易將被拒絕。
?每一個輸入的解鎖腳本必須依據相應輸出的鎖定腳本來驗證。
這些條件能夠在比特幣標準客戶端下的 AcceptToMemoryPool 、 CheckTransaction 和 CheckInputs 函數中獲得更詳細的闡述。請注意,這些條件會隨著時間發生變化,為了處理新型拒絕服務攻擊,有時候也為交易類型多樣化而放寬規則。在收到交易后,,每一個節點都會在全網廣播前對這些交易進行校驗,并以接收時的相應順序,為有效的新交易建立一個池(交易池)。
8.4 挖礦節點
在比特幣網絡中,一些節點被稱為專業節點礦工。同其他節點一樣,Jing的節點時刻監聽著傳播到比特幣網絡的新區塊。而這些新加入的區塊對挖礦節點有著特殊的意義。礦工間的競爭以新區塊的傳播而結束,如同宣布誰是最后的贏家。對于礦工們來說,獲得一個新區塊意味著某個參與者贏了,而他們則輸了這場競爭。然而,一輪競爭的結束也代表著下一輪競爭的開始。新區塊并不僅僅是象征著競賽結束的方格旗;它也是下一個區塊競賽的發令槍。
8.5 整合交易至區塊
驗證交易后,比特幣節點會將這些交易添加到自己的內存池中。內存池也稱作交易池,用來暫存尚未被加入到區塊的交易記錄。與其他節點一樣,Jing的節點會收集、驗證并中繼新的交易。而與其他節點不同的是,Jing的節點會把這些交易整合到一個候選區塊中。
讓我們繼續跟進,看下Alice從Bob咖啡店購買咖啡時產生的那個區塊(參見“2.1.2 買咖啡”)。Alice的交易在區塊277,316。為了演示本章中提到的概念,我們假設這個區塊是由Jing的挖礦系統挖出的,并且繼續跟進Alice的交易,因為這個交易已經成為了新區塊的一部分。
Jing的挖礦節點維護了一個區塊鏈的本地副本,包含了自2009年比特幣系統啟動運行以來的全部區塊。當Alice買咖啡的時候,Jing節點的區塊鏈已經收集到了區塊277,314,并繼續監聽著網絡上的交易,在嘗試挖掘新區塊的同時,也監聽著由其他節點發現的區塊。當Jing的節點在挖礦時,它從比特幣網絡收到了區塊277,315。這個區塊的到來標志著終結了產出區塊277,315競賽,與此同時也是產出區塊277,316競賽的開始。
在上一個10分鐘內,當Jing的節點正在尋找區塊277,315的解的同時,它也在收集交易記錄為下一個區塊做準備。目前它已經收到了幾百筆交易記錄,并將它們放進了內存池。直到接收并驗證區塊277,315后,Jing的節點會檢查內存池中的全部交易,并移除已經在區塊277,315中出現過的交易記錄,確保任何留在內存池中的交易都是未確認的,等待被記錄到新區塊中。
Jing的節點立刻構建一個新的空區塊,做為區塊277,316的候選區塊。稱作候選區塊是因為它還沒有包含有效的工作量證明,不是一個有效的區塊,而只有在礦工成功找到一個工作量證明解之后,這個區塊才生效。?
8.5.1 交易塊齡,礦工費和優先級
Jing的比特幣節點需要為內存池中的每筆交易分配一個優先級,并選擇較高優先級的交易記錄來構建候選區塊。交易的優先級是由交易輸入所花費的UTXO的“塊齡”決定,交易輸入值高、“塊齡”大的交易比那些新的、輸入值小的交易擁有更高的優先級。如果區塊中有足夠的空間,高優先級的交易行為將不需要礦工費。
交易的優先級是通過輸入值和輸入的“塊齡”乘積之和除以交易的總長度得到的:
Priority = Sum (Value of input * Input Age) / Transaction Size
在這個等式中,交易輸入的值是由比特幣單位“聰”(1億分之1個比特幣)來表示的。UTXO的“塊齡”是自該UTXO被記錄到區塊鏈為止所經歷過的區塊數,即這個UTXO在區塊鏈中的深度。交易記錄的大小由字節來表示。
一個交易想要成為“較高優先級”,需滿足的條件:優先值大于57,600,000,相當于一個比特幣(即1億聰),年齡為一天(144個區塊),交易的大小為250個字節:
High Priority > 100,000,000 satoshis * 144 blocks / 250 bytes = 57,600,000
區塊中用來存儲交易的前50K字節是保留給較高優先級交易的。Jing的節點在填充這50K字節的時候,會優先考慮這些
最高優先級的交易,不管它們是否包含了礦工費。這種機制使得高優先級交易即便是零礦工費,也可以優先被處理。然后,Jing的挖礦節點(全節點)會選出那些包含最小礦工費的交易,并按照“每千字節礦工費”進行排序,優先選擇礦工費高的交易來填充剩下的區塊,區塊大小上限為 MAX_BLOCK_SIZE 。
如區塊中仍有剩余空間,Jing的挖礦節點可以選擇那些不含礦工費的交易。有些礦工會竭盡全力將那些不含礦工費的交易整合到區塊中,而其他礦工也許會選擇忽略這些交易。
在區塊被填滿后,內存池中的剩余交易會成為下一個區塊的候選交易。因為這些交易還留在內存池中,所以隨著新的區塊被加到鏈上,這些交易輸入時所引用UTXO的深度(即交易“塊齡”)也會隨著變大。由于交易的優先值取決于它交易輸入的“塊齡”,所以這個交易的優先值也就隨之增長了。最后,一個零礦工費交易的優先值就有可能會滿足高優先級的門檻,被免費地打包進區塊。
比特幣交易中沒有過期、超時的概念,一筆交易現在有效,那么它就永遠有效。然而,如果一筆交易只在全網廣播了一次,那么它只會保存在一個挖礦節點的內存中。因為內存池是以未持久化的方式保存在挖礦節點存儲器中的,所以一旦這個節點重新啟動,內存池中的數據就會被完全擦除。而且,即便一筆有效交易被傳播到了全網,如果它長時間未處理,它將從挖礦節點的內存池中消失。如果交易本應該在一段時間內被處理而實際沒有,那么錢包軟件應該重新發送交易或重新支付更高的礦工費。
8.5.2 創幣交易
區塊中的第一筆交易是筆特殊交易,稱為創幣交易或者coinbase交易。這個交易是由Jing的節點構造并用來獎勵礦工們所做的貢獻的。Jing的節點會創建“向Jing的地址支付25.09094928個比特幣”這樣一個交易,把生成交易的獎勵發送到自己的錢包。Jing挖出區塊獲得的獎勵金額是coinbase獎勵(25個全新的比特幣)和區塊中全部交易礦工費的總和。
與常規交易不同,創幣交易沒有輸入,不消耗UTXO。它只包含一個被稱作coinbase的輸入,僅僅用來創建新的比特幣。創幣交易有一個輸出,支付到這個礦工的比特幣地址。
8.5.3 Coinbase獎勵與礦工費
為了構造創幣交易,Jing的節點需要計算礦工費的總額,將這418個已添加到區塊交易的輸入和輸出分別進行加總,然后用輸入總額減去輸出總額得到礦工費總額,公式如下:
Total Fees = Sum(Inputs) - Sum(Outputs)
詳細的計算過程可以參看比特幣核心客戶端中的GetBlockValue函數
8.5.4 創幣交易的結構
創幣交易的結構比較特殊,與一般交易輸入需要指定一個先前的UTXO不同,它包含一個“coinbase“輸入。在表5-3中,我們已經給出了交易輸入的結構。現在讓我們來比較一下常規交易輸入與創幣交易輸入。表8-1給出了常規交易輸入的結構,表8-2給出的是創幣交易輸入的結構。
在創幣交易中,“交易哈希”字段32個字節全部填充0,“交易輸出索引”字段全部填充0xFF(十進制的255),這兩個字段的值表示不引用UTXO。“解鎖腳本”由coinbase數據代替,數據可以由礦工自定義。
8.5.5 Coinbase數據
創幣交易不包含“解鎖腳本“(又稱作 scriptSig)字段,這個字段被coinbase數據替代,長度最小2字節,最大100字節。除了開始的幾個字節外,礦工可以任意使用coinbase的其他部分,隨意填充任何數據。
以創世塊為例,中本聰在coinbase中填入了這樣的數據“The Times 03/Jan/ 2009 Chancellor on brink of secondbailout for banks“(泰晤士報 2009年1月3日 財政大臣將再次對銀行施以援手),表示對日期的證明,同時也表達了對銀行系統的不信任。現在,礦工使用coinbase數據實現extra nonce功能,并嵌入字符串來標識挖出它的礦池,這部分內容會在后面的小節描述。coinbase前幾個字節也曾是可以任意填寫的,不過在后來的第34號比特幣改進提議(BIP34)中規定了版本2的區塊(版本字段為2的區塊),這個區塊的高度必須跟在腳本操作“push“之后,填充在coinbase字段的起始處。
8.6 構造區塊頭
為了構造區塊頭,挖礦節點需要填充六個字段,如表8-3中所示。
在區塊277,316被挖出的時候,區塊結構中用來表示版本號的字段值為2,長度為4字節,以小段格式編碼值為0x20000000。接著,挖礦節點需要填充“前區塊哈希”,在本例中,這個值為Jing的節點從網絡上接收到的區塊277,315的區塊頭哈希值,它是區塊277316候選區塊的父區塊。區塊277,315的區塊頭哈希值為:
0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569
為了向區塊頭填充merkle根字段,要將全部的交易組成一個merkle樹。創幣交易作為區塊中的首個交易,后將余下的418筆交易添至其后,這樣區塊中的交易一共有419筆。在164頁,我們已經見到過“Merkle樹”,樹中必須有偶數個葉子節點,所以需要復制最后一個交易作為第420個節點,每個節點是對應交易的哈希值。這些交易的哈希值逐層地、成對地組合,直到最終組合并成一個根節點。merkle數的根節點將全部交易數據摘要為一個32字節長度的值,例8-3中merkel根的值如下:c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e
挖礦節點會繼續添加一個4字節的時間戳,以Unix紀元時間編碼,即自1970年1月1日0點到當下總共流逝的秒數。本例中的1388185914對應的時間是2013年12月27日,星期五,UTC/GMT。
接下來,節點需要填充難度目標值,為了使得該區塊有效,這個字段定義了所需滿足的工作量證明的難度。難度在區塊中以“尾數-指數”的格式,編碼并存儲,這種格式稱作“難度位”。這種編碼的首字節表示指數,后面的3字節表示尾數(系數)。以區塊277316為例,難度位的值為0x1903a30c,0x19是指數的十六進制格式,后半部0x03a30c是系數。這部分的概念在第195頁的“難度目標與難度調整”和第194的“難度表示”有詳細的解釋。
最后一個字段是nonce,初始值為0。
區塊頭完成全部的字段填充后,挖礦就可以開始進行了。挖礦的目標是找到一個使區塊頭哈希值小于難度目標的nonce。挖礦節點通常需要嘗試數十億甚至數萬億個不同的nonce取值,直到找到一個滿足條件的nonce值。
8.7 構建區塊
既然Jing的節點已經構建了一個候選區塊,那么就輪到Jing的礦機對這個新區塊進行“挖掘”,求解工作量證明算法以使這個區塊有效。從本書中我們已經學習了比特幣系統中不同地方用到的哈希加密函數。比特幣挖礦過程使用的是SHA256哈希函數。
用最簡單的術語來說,挖礦就是重復計算區塊頭的哈希值,不斷修改該參數,直到與哈希值匹配的一個過程。哈希函數的結果無法提前得知,也沒有能得到一個特定哈希值的模式。哈希函數的這個特性意味著:得到哈希值的唯一方法是不斷的嘗試,每次隨機修改輸入,直到出現適當的哈希值。
8.7.1 工作量證明算法
哈希函數的輸入數據的長度是任意的,將產生一個長度固定且絕不雷同的值,可將其視為輸入的數字指紋。對于特定輸入,哈希的結果每次都一樣,任何實現相同哈希函數的人都可以計算和驗證。一個加密哈希函數的主要特征就是不同的輸入幾乎不可能出現相同的數字指紋。因此,相對于隨機選擇輸入,有意地選擇輸入去生成一個想要的哈希值幾乎是不可能的。無論輸入的大小是多少,SHA256函數的輸出的長度總是256bit。
礦工用一些交易構建一個候選區塊。接下來,這個礦工計算這個區塊頭信息的哈希值,看其是否小于當前目標值。如果這個哈希值不小于目標值,礦工就會修改這個nonce(通常將之加1)然后再試一次。按當前比特幣系統的難度,礦工得試10^15次(10的15次方)才能找到一個合適的nonce使區塊頭信息哈希值足夠小。
比特幣網絡已經擁有100PH每秒(petahashes per second, peta-為1015)的處理能力,平均每10分鐘就可以找到一個新區塊
8.7.2 難度表示
在例8-3中,我們在區塊中看到難度目標,其被標為"難度位"或簡稱"bits"。在區塊277,316中,它的值為 0x1903a30c。這個標記的值被存為系數/指數格式,前兩位十六進制數字為冪,接下來得六位為系數。在這個區塊里,0x19為冪,而0x03a30c為系數。
計算難度目標的公式為:
target = coefficient * 2^(8 * (exponent – 3))
由此公式及難度位的值 0x1903a30c,可得:
target = 0x03a30c * 2^(0x08 * (0x19 - 0x03))
=> target = 0x03a30c * 2^(0x08 * 0x16)
=> target = 0x03a30c * 2^0xB0
按十進制計算為:
=> target = 238,348 * 2^176
=> target =
22,829,202,948,393,929,850,749,706,076,701,368,331,072,452,018,388,575,715,328
轉化為十六進制后為:
=> target =0x0000000000000003A30C00000000000000000000000000000000000000000000
也就是說高度為277,316的有效區塊的頭信息哈希值是小于這個目標值的。這個數字的二進制表示中前60位都是0。在這個難度上,一個每秒可以處理1萬億個哈希計算的礦工(1 tera-hash per second 或 1 TH/sec)平均每8,496個區塊才能找到一個正確結果,換句話說,平均每59天,才能為某一個區塊找到正確的哈希值。
8.7.3 難度目標與難度調整
如前所述,目標決定了難度,進而影響求解工作量證明算法所需要的時間。那么問題來了:為什么這個難度值是可調整的?由誰來調整?如何調整?
比特幣的區塊平均每10分鐘生成一個。這就是比特幣的心跳,是貨幣發行速率和交易達成速度的基礎。不僅是在短期內,而是在幾十年內它都必須要保持恒定。在此期間,計算機性能將飛速提升。此外,參與挖礦的人和計算機也會不斷變化。為了能讓新區塊的保持10分鐘一個的產生速率,挖礦的難度必須根據這些變化進行調整。事實上,難度是一個動態的參數,會定期調整以達到每10分鐘一個新區塊的目標。簡單地說,難度被設定在,無論挖礦能力如何,新區塊產生速率都保持在10分鐘一個。
那么,在一個完全去中心化的網絡中,這樣的調整是如何做到的呢?難度的調整是在每個完整節點中獨立自動發生的。每2,016個區塊中的所有節點都會調整難度。難度的調整公式是由最新2,016個區塊的花費時長與20,160分鐘(兩周,即這些區塊以10分鐘一個速率所期望花費的時長)比較得出的。難度是根據實際時長與期望時長的比值進行相應調整的(或變難或變易)。簡單來說,如果網絡發現區塊產生速率比10分鐘要快時會增加難度。如果發現比10分鐘慢時則降低難度。
這個公式可以總結為如下形式:
New Difficulty = Old Difficulty * (Actual Time of Last 2016 Blocks / 20160 minutes)
為了防止難度的變化過快,每個周期的調整幅度必須小于一個因子(值為4)。如果要調整的幅度大于4倍,則按4倍調整。由于在下一個2,016區塊的周期不平衡的情況會繼續存在,所以進一步的難度調整會在下一周期進行。因此平衡哈希計算能力和難度的巨大差異有可能需要花費幾個2,016區塊周期才會完成。
尋找一個比特幣區塊需要整個網絡花費10分鐘來處理,每發現2,016個區塊時會根據前2,016個區塊完成的時間對難度進行調整。
值得注意的是目標難度與交易的數量和金額無關。這意味著哈希算力的強弱,即讓比特幣更安全的電力投入量,與交易的數量完全無關。換句話說,當比特幣的規模變得更大,使用它的人數更多時,即使哈希算力保持當前的水平,比特幣的安全性也不會受到影響。哈希算力的增加表明更多的人為得到比特幣回報而加入了挖礦隊伍。只要為了回報,公平正當地從事挖礦的礦工群體保持足夠的哈希算力,"接管"攻擊就不會得逞,讓比特幣的安全無虞。
目標難度和挖礦電力消耗與將比特幣兌換成現金以支付這些電力之間的關系密切相關。高性能挖礦系統就是要用當前硅芯片以最高效的方式將電力轉化為哈希算力。挖礦市場的關鍵因素就是每度電轉換為比特幣后的價格。因為這決定著挖礦活動的營利性,也因此刺激著人們選擇進入或退出挖礦市場。
8.8 成功構建區塊
前面已經看到,Jing的節點創建了一個候選區塊,準備拿它來挖礦。Jing有幾個安裝了ASIC(專用集成電路)的礦機,上面有成千上萬個集成電路可以超高速地并行運行SHA256算法。這些定制的硬件通過USB連接到他的挖礦節點上。接下來,運行在Jing的桌面電腦上的挖礦節點將區塊頭信息傳送給這些硬件,讓它們以每秒億萬次的速度進行nonce測試。
在對區塊277,316的挖礦工作開始大概11分鐘后,這些硬件里的其中一個求得了解并發回挖礦節點。當把這個結果放進區塊頭時,nonce 4,215,469,401 就會產生一個區塊哈希值:0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569
而這個值小于難度目標值:0000000000000003A30C00000000000000000000000000000000000000000000 Jing的挖礦節點立刻將這個區塊發給它的所有相鄰節點。這些節點在接收并驗證這個新區塊后,也會繼續傳播此區塊。當這個新區塊在網絡中擴散時,每個節點都會將它作為區塊277,316加到自身節點的區塊鏈副本中。當挖礦節點收到并驗證了這個新區塊后,它們會放棄之前對構建這個相同高度區塊的計算,并立即開始計算區塊鏈中下一個區塊的工作。
下面介紹節點進行區塊驗證、最長鏈選擇、達成共識,并以此形成一個去中心化區塊鏈的過程。
8.9 校驗新區塊
比特幣共識機制的第三步是通過網絡中的每個節點獨立校驗每個新區塊。當新區塊在網絡中傳播時,每一個節點在將它轉發到其節點之前,會進行一系列的測試去驗證它。這確保了只有有效的區塊會在網絡中傳播。獨立校驗還確保了誠實的礦工生成的區塊可以被納入到區塊鏈中,從而獲得獎勵。行為不誠實的礦工所產生的區塊將被拒絕,這不但使他們失去了獎勵,而且也浪費了本來可以去尋找工作量證明解的機會,因而導致其電費虧損。
當一個節點接收到一個新的區塊,它將對照一個長長的標準清單對該區塊進行驗證,若沒有通過驗證,這個區塊將被拒絕。這些標準可以在比特幣核心客戶端的CheckBlock函數和CheckBlockHead函數中獲得,它包括:
? 區塊的數據結構語法上有效
? 區塊頭的哈希值小于目標難度(確認包含足夠的工作量證明)
? 區塊時間戳早于驗證時刻未來兩個小時(允許時間錯誤)
? 區塊大小在長度限制之內
? 第一個交易(且只有第一個)是coinbase交易
? 使用檢查清單驗證區塊內的交易并確保它們的有效性,本書177頁
? “交易的獨立校驗”一節已經討論過這個清單。
每一個節點對每一個新區塊的獨立校驗,確保了礦工無法欺詐。在前面的章節中,我們看到了礦工們如何去記錄一筆交易,以獲得在此區塊中創造的新比特幣和交易費。為什么礦工不為他們自己記錄一筆交易去獲得數以千計的比特幣?這是因為每一個節點根據相同的規則對區塊進行校驗。一個無效的coinbase交易將使整個區塊無效,這將導致該區塊被拒絕,因此,該交易就不會成為總賬的一部分。礦工們必須構建一個完美的區塊,基于所有節點共享的規則,并且根據正確工作量證明的解決方案進行挖礦,他們要花費大量的電力挖礦才能做到這一點。如果他們作弊,所有的電力和努力都會浪費。這就是為什么獨立校驗是去中心化共識的重要組成部分。
8.10 區塊鏈的組裝與選擇
比特幣去中心化的共識機制的最后一步是將區塊集合至有最大工作量證明的鏈中。一旦一個節點驗證了一個新的區塊,它將嘗試將新的區塊連接到到現存的區塊鏈,將它們組裝起來。
節點維護三種區塊:第一種是連接到主鏈上的,第二種是從主鏈上產生分支的(備用鏈),最后一種是在已知鏈中沒有找到已知父區塊的。在驗證過程中,一旦發現有不符合標準的地方,驗證就會失敗,這樣區塊會被節點拒絕,所以也不會加入到任何一條鏈中。
任何時候,主鏈都是累計了最多難度的區塊鏈。在一般情況下,主鏈也是包含最多區塊的那個鏈,除非有兩個等長的鏈并且其中一個有更多的工作量證明。主鏈也會有一些分支,這些分支中的區塊與主鏈上的區塊互為“兄弟”區塊。這些區塊是有效的,但不是主鏈的一部分。 保留這些分支的目的是如果在未來的某個時刻它們中的一個延長了并在難度值上超過了主鏈,那么后續的區塊就會引用它們。在“8.10.1 區塊鏈分叉”,我們將會看到在同樣的區塊高度,幾乎同時挖出區塊時,候選鏈是如何產生的。
當節點接收到新區塊,它會嘗試將這個區塊插入到現有區塊鏈中。節點會看一下這個區塊的“previous block hash”字段,這個字段是該區塊對其父區塊的引用。同時,新的節點將嘗試在已存在的區塊鏈中找出這個父區塊。大多數情況下,父區塊是主塊鏈的“頂點”,這就意味著這個新的區塊延長了主鏈。舉個例子,一個新的區塊——區塊277,316引用了它的父區塊——區塊277,315。大部分收到了區塊277,316的節點將區塊277,315作為主鏈的頂點,連接這個新區塊并延長區塊鏈。
有時候,新區塊所延長的區塊鏈并不是主鏈,這一點我們將在“8.10.1 區塊鏈分叉”中看到。在這種情況下,節點將新的區塊添加到備用鏈,同時比較備用鏈與主鏈的難度。如果備用鏈比主鏈積累了更多的難度,節點將收斂于備用鏈,意味著節點將選擇備用鏈作為其新的主鏈,而之前那個老的主鏈則成為了備用鏈。如果節點是一個礦工,它將開始構造新的區塊,來延長這個更新更長的區塊鏈。
如果節點收到了一個有效的區塊,而在現有的區塊鏈中卻未找到它的父區塊,那么這個區塊被認為是“孤塊”。孤塊會被保存在孤塊池中,直到它們的父區塊被節點收到。一旦收到了父區塊并且將其連接到現有區塊鏈上,節點就會將孤塊從孤塊池中取出,并且連接到它的父區塊,讓它作為區塊鏈的一部分。當兩個區塊在很短的時間間隔內被挖出來,節點有可能會以相反的順序接收到它們,這個時候孤塊現象就會出現。
選擇了最大難度的區塊鏈后,所有的節點最終在全網范圍內達成共識。隨著更多的工作量證明被添加到鏈中,鏈的暫時性差異最終會得到解決。挖礦節點通過“投票”來選擇它們想要延長的區塊鏈,當它們挖出一個新塊并且延長了一個鏈,新塊本身就代表它們的投票。
相互競爭的鏈之間是存在差異的,下節我們將看到節點是怎樣通過獨立選擇最長難度鏈來解決這種差異的。
8.10.1 區塊鏈分叉
因為區塊鏈是去中心化的數據結構,所以不同副本之間不能總是保持一致。區塊有可能在不同時間到達不同節點,導致節點有不同的區塊鏈視角。解決的辦法是,每一個節點總是選擇并嘗試延長代表累計了最大工作量證明的區塊鏈,也就是最長的或最大累計難度的鏈。節點通過將記錄在每個區塊中的難度加總起來,得到建立這個鏈所要付出的工作量證明的總量。只要所有的節點選擇最長累計難度的區塊鏈,整個比特幣網絡最終會收斂到一致的狀態。分叉即在不同區塊鏈間發生的臨時差異,當更多的區塊添加到了某個分叉中,這個問題便會迎刃而解。
從理論上來說,兩個區塊的分叉是有可能的,這種情況發生在因先前分叉而相互對立起來的礦工,又幾乎同時發現了兩個不同區塊的解。然而,這種情況發生的幾率是很低的。單區塊分叉每周都會發生,而雙塊分叉則非常罕見。
比特幣將區塊間隔設計為10分鐘,是在更快速的交易確認和更低的分叉概率間作出的妥協。更短的區塊產生間隔會讓交易清算更快地完成,也會導致更加頻繁地區塊鏈分叉。與之相對地,更長的間隔會減少分叉數量,卻會導致更長的清算時間。
8.11 挖礦和算力競賽
近兩年,ASIC芯片變得更加密集,特征尺寸接近芯片制造業前沿的22納米。挖礦的利潤率驅動這個行業以比通用計算更快的速度發展。目前,ASIC制造商的目標是超越通用CPU芯片制造商,設計特征尺寸為16納米的芯片。對比特幣挖礦而言,已經沒有更多飛躍的空間,因為這個行業已經觸及了摩爾定律的最前沿。摩爾定律指出計算能力每18個月增加一倍。盡管如此,隨著更高密度的芯片和數據中心的部署競賽,網絡算力繼續保持同步的指數增長。現在的競爭已經不再是比較單一芯片的能力,而是一個礦場能塞進多少芯片,并處理好散熱和供電問題。
8.11.1 隨機值升位方案
12年以來,比特幣挖礦發展出一個解決區塊頭基本結構限制的方案。在比特幣的早期,礦工可以通過遍歷隨機數(Nonce)獲得符合要求的hash來挖出一個塊.難度增長后,礦工經常在嘗試了40億個值后仍然沒有出塊。然而,這很容易通過讀取塊的時間戳并計算經過的時間來解決。后來隨著算力的增加又不行了,需要更多的空間來儲存nonce值。解決方案是使用coinbase交易作為額外的隨機值來源,因為coinbase腳本可以儲存2-100字節的數據,礦工們開始使用這個空間作為額外隨機值的來源,允許他們去探索一個大得多的區塊頭值范圍來找到有效的塊。
8.11.2 礦池
在這個激烈競爭的環境中,個體礦工獨立工作(也就是solo挖礦)沒有一點機會。他們找到一個區塊以抵消電力和硬件成本的可能性非常小,以至于可以稱得上是賭博,就像是買彩票。就算是最快的消費型ASIC也不能和那些在巨大機房里擁有數萬芯片并靠近水電站的商業礦場競爭。現在礦工們合作組成礦池,匯集數以千計參與者們的算力并分享獎勵。通過參加礦池,礦工們得到整體回報的一小部分,但通常每天都能得到,因而減少了不確定性。
礦池通過專用挖礦協議協調成百上千的礦工。個人礦工在建立礦池賬號后,設置他們的礦機連接到礦池服務器。他們的挖礦設備在挖礦時保持和礦池服務器的連接,和其他礦工同步各自的工作。這樣,礦池中的礦工分享挖礦任務,之后分享獎勵。
成功出塊的獎勵支付到礦池的比特幣地址,而不是單個礦工的。一旦獎勵達到一個特定的閾值,礦池服務器便會定期支付獎勵到礦工的比特幣地址。通常情況下,礦池服務器會為提供礦池服務收取一個百分比的費用。
參加礦池的礦工把搜尋候選區塊的工作量分割,并根據他們挖礦的貢獻賺取“份額”。礦池為賺取“份額”設置了一個低難度的目標,通常比比特幣網絡難度低1000倍以上。當礦池中有人成功挖出一塊,礦池獲得獎勵,并和所有礦工按照他們做出貢獻的“份額”數的比例分配。
8.11.2.1 托管礦池
大部分礦池是“托管的”,意思是有一個公司或者個人經營一個礦池服務器。礦池服務器的所有者叫礦池管理員,同時他從礦工的收入中收取一個百分比的費用。
礦池服務器運行專業軟件以及協調池中礦工們活動的礦池采礦協議。礦池服務器同時也連接到一個或更多比特幣完全節點并直接訪問一個塊鏈數據庫的完整副本。這使得礦池服務器可以代替礦池中的礦工驗證區塊和交易,緩解他們運行一個完整節點的負擔。對于池中的礦工,這是一個重要的考量,因為一個完整節點要求一個擁有最少15-20GB的永久儲存空間(磁盤)和最少2GB內存(RAM)的專用計算機。此外,運行一個完整節點的比特幣軟件需要監控、維護和頻繁升級。由于缺乏維護或資源導致的任何宕機都會傷害到礦工的利潤。對于很多礦工來說,不需要跑一個完整節點就能采礦,也是加入托管礦池的一大好處。
礦工連接到礦池服務器使用一個采礦協議比如Stratum (STM)或者 GetBlockTemplate (GBT)。一個舊標準GetWork(GWK) 自從2012年底已經基本上過時了,因為它不支持在hash速度超過4GH/S時采礦。STM和GBT協議都創建包含候選區塊頭模板的區塊模板。礦池服務器通過聚集交易,添加coinbase交易(和額外的隨機值空間),計算MERKLE根,并連接到上一個塊hash來建立一個候選區塊。這個候選區塊的頭部作為模板分發給每個礦工。礦工用這個區塊模板在低于比特幣網絡的難度下采礦,并發送成功的結果返回礦池服務器賺取份額。
8.11.2.2 P2P礦池
托管礦池存在管理人作弊的可能,管理人可以利用礦池進行雙重支付或使區塊無效。(參見“8.12 共識攻擊”) 此外,中心化的礦池服務器代表著單點故障。如果因為拒絕服務攻擊服務器掛了或者被減慢,池中礦工就不能采礦。在2011年,為了解決由中心化造成的這些問題,提出和實施了一個新的礦池挖礦方法。P2Pool是一個點對點的礦池,沒有中心管理人。
8.12 共識攻擊
比特幣的共識機制指的是,被礦工(或礦池)試圖使用自己的算力實行欺騙或破壞的難度很大,至少理論上是這樣。就像我們前面講的,比特幣的共識機制依賴于這樣一個前提,那就是絕大多數的礦工,出于自己利益最大化的考慮,都會通過誠實地挖礦來維持整個比特幣系統。然而,當一個或者一群擁有了整個系統中大量算力的礦工出現之后,他們就可以通過攻擊比特幣的共識機制來達到破壞比特幣網絡的安全性和可靠性的目的。
值得注意的是,共識攻擊只能影響整個區塊鏈未來的共識,或者說,最多能影響不久的過去幾個區塊的共識(最多影響過去10個塊)。而且隨著時間的推移,整個比特幣塊鏈被篡改的可能性越來越低。理論上,一個區塊鏈分叉可以變得很長,但實際上,要想實現一個非常長的區塊鏈分叉需要的算力非常非常大,隨著整個比特幣區塊鏈逐漸增長,過去的區塊基本可以認為是無法被分叉篡改的。同時,共識攻擊也不會影響用戶的私鑰以及加密算法(ECDSA)。共識攻擊也不能從其他的錢包那里偷到比特幣、不簽名地支付比特幣、重新分配比特幣、改變過去的交易或者改變比特幣持有紀錄。共識攻擊能夠造成的唯一影響是影響最近的區塊(最多10個)并且通過拒絕服務來影響未來區塊的生成。
共識攻擊的一個典型場景就是“51%攻擊”。想象這么一個場景,一群礦工控制了整個比特幣網絡51%的算力,他們聯合
起來打算攻擊整個比特幣系統。由于這群礦工可以生成絕大多數的塊,他們就可以通過故意制造塊鏈分叉來實現“雙重支付”或者通過拒絕服務的方式來阻止特定的交易或者攻擊特定的錢包地址。區塊鏈分叉/雙重支付攻擊指的是攻擊者通過不承認最近的某個交易,并在這個交易之前重構新的塊,從而生成新的分叉,繼而實現雙重支付。有了充足算力的保證,一個攻擊者可以一次性篡改最近的6個或者更多的區塊,從而使得這些區塊包含的本應無法篡改的交易消失。值得注意的是,雙重支付只能在攻擊者擁有的錢包所發生的交易上進行,因為只有錢包的擁有者才能生成一個合法的簽名用于雙重支付交易。攻擊者只能在自己的交易上進行雙重支付攻擊,但當這筆交易對應的是不可逆轉的購買行為的時候,這種攻擊就是有利可圖的。
讓我們看一個“51%攻擊”的實際案例吧。在第1章我們講到,Alice 和 Bob 之間使用比特幣完成了一杯咖啡的交易。咖啡店老板 Bob 愿意在 Alice 給自己的轉賬交易確認數為零的時候就向其提供咖啡,這是因為這種小額交易遭遇“51%攻擊”的風險和顧客購物的即時性(Alice 能立即拿到咖啡)比起來,顯得微不足道。這就和大部分的咖啡店對低于25美元的信用卡消費不會費時費力地向顧客索要簽名是一樣的,因為和顧客有可能撤銷這筆信用卡支付的風險比起來,向用戶索要信用卡簽名的成本更高。相應的,使用比特幣支付的大額交易被雙重支付的風險就高得多了,因為買家(攻擊者)可以通過在全網廣播一個和真實交易的UTXO一樣的偽造交易,以達到取消真實交易的目的。雙重支付可以有兩種方式:要么是在交易被確認之前,要么攻擊者通過塊鏈分叉來完成。進行51%攻擊的人,可以取消在舊分叉上的交易記錄,然后在新分叉上重新生成一個同樣金額的交易,從而實現雙重支付。
再舉個例子:攻擊者Mallory在Carol的畫廊買了描繪偉大的中本聰的三聯組畫,Mallory通過轉賬價值25萬美金的比特幣與Carol進行交易。在等到一個而不是六個交易確認之后,Carol放心地將這幅組畫包好,交給了Mallory。這時,Mallory的一個同伙,一個擁有大量算力的礦池的人Paul,在這筆交易寫進區塊鏈的時候,開始了51%攻擊。首先,Paul利用自己礦池的算力重新計算包含這筆交易的塊,并且在新塊里將原來的交易替換成了另外一筆交易(比如直接轉給了Mallory的另一個錢包而不是Carol的),從而實現了“雙重支付”。這筆“雙重支付”交易使用了跟原有交易一致的UTXO,但收款人被替換成了Mallory的錢包地址。然后,Paul利用礦池在偽造的塊的基礎上,又計算出一個更新的塊,這樣,包含這筆“雙重支付”交易的塊鏈比原有的塊鏈高出了一個塊。到此,高度更高的分叉區塊鏈取代了原有的區塊鏈,“雙重支付”交易取代了原來給Carol的交易,Carol既沒有收到價值25萬美金的比特幣,原本擁有的三幅價值連城的畫也被Mallory白白拿走了。在整個過程中,Paul礦池里的其他礦工可能自始至終都沒有覺察到這筆“雙重支付”交易有什么異樣,因為挖礦程序都是自動在運行,并且不會時時監控每一個區塊中的每一筆交易。
為了避免這類攻擊,售賣大宗商品的商家應該在交易得到全網的6個確認之后再交付商品。或者,商家應該使用第三方的多方簽名的賬戶進行交易,并且也要等到交易賬戶獲得全網多個確認之后再交付商品。一條交易的確認數越多,越難被攻擊者通過51%攻擊篡改。對于大宗商品的交易,即使在付款24小時之后再發貨,對買賣雙方來說使用比特幣支付也是方便并且有效率的。而24小時之后,這筆交易的全網確認數將達到至少144個(能有效降低被51%攻擊的可能性)。
共識攻擊中除了“雙重支付”攻擊,還有一種攻擊場景就是拒絕對某個特定的比特幣地址提供服務。一個擁有了系統中絕大多數算力的攻擊者,可以輕易地忽略某一筆特定的交易。如果這筆交易存在于另一個礦工所產生的區塊中,該攻擊者可以故意分叉,然后重新產生這個區塊,并且把想忽略的交易從這個區塊中移除。這種攻擊造成的結果就是,只要這名攻擊者擁有系統中的絕大多數算力,那么他就可以持續地干預某一個或某一批特定錢包地址產生的所有交易,從而達到拒絕為這些地址服務的目的。
需要注意的是,51%攻擊并不是像它的命名里說的那樣,攻擊者需要至少51%的算力才能發起,實際上,即使其擁有不到51%的系統算力,依然可以嘗試發起這種攻擊。之所以命名為51%攻擊,只是因為在攻擊者的算力達到51%這個閾值的時候,其發起的攻擊嘗試幾乎肯定會成功。本質上來看,共識攻擊,就像是系統中所有礦工的算力被分成了兩組,一組為誠實算力,一組為攻擊者算力,兩組人都在爭先恐后地計算塊鏈上的新塊,只是攻擊者算力算出來的是精心構造的、包含或者剔除了某些交易的塊。因此,攻擊者擁有的算力越少,在這場決逐中獲勝的可能性就越小。從另一個角度講,一個攻擊者擁有的算力越多,其故意創造的分叉塊鏈就可能越長,可能被篡改的最近的塊或者或者受其控制的未來的塊就會越多。一些安全研究組織利用統計模型得出的結論是,算力達到全網的30%就足以發動51%攻擊了。????