名詞
Block Chain:區塊鏈
UTXO: Unspent Transaction Output,未花費的交易輸出
Genesis Block: 塊0,創世塊
SPV: Simplified Payment Verification,簡單支付驗證
BIP: Bitcoin Improvement Proposal,比特幣改進提案
Proof Of Work: 工作量證明
區塊鏈
區塊鏈提供了比特幣的公用帳本,這是一個有序有時間戳記的交易(transaction)記錄。該系統用於防止重複花費(雙花 double spending)和修改先前的交易記錄。
Bitcoin 網路中的每個完整節點獨立地儲存僅包含由節點驗證過的區塊鏈。當多個節點在其塊鏈中都具有相同的塊時,它們被認為達成了共識。這些節點遵循維持共識的驗證規則被稱為共識規則。本節將介紹Bitcoin Core使用的許多共識規則。
區塊鏈概述
上圖顯示了區塊鏈的簡化版本。一個或多個新交易的塊被收集到一個區塊的交易資料部分中。每個交易資料的副本將被雜湊, 這些雜湊值兩兩配對,再被hash,直到得到最頂層的一個hash值,這就是一棵merkle樹的根。
merkle樹根儲存在這個區塊標題中。每個塊還儲存著先前塊的標題的雜湊值,這樣塊將連結在一起。這樣可以確保事務無法修改,而不修改記錄該事務的塊以及所有後續塊。
交易記錄也被連結在一起。比特幣錢包軟體給人的感覺是從錢包發送或接收多少聰(satoshi,單位)的比特幣,但實際上比特幣真的是在交易中流轉。每個交易花費先前在一個或多個較早的交易中接收到的多少聰的比特幣,因此一個交易的輸入是先前交易的輸出。
單個交易可以建立多個輸出,就像發送到多個地址時的情況一樣,但是特定交易的每個輸出只能是在區塊鏈中用作輸入一次。任何後續的引用都禁止重複花費 - 嘗試花費相同的多少聰的比特幣兩次。
輸出綁定到交易標識符(TXID)上,這是驗證過的交易的雜湊值。
因為特定交易的 輸出 只允許花費一次,那所有包含在區塊鏈上的交易輸出可以歸類為未花費的交易輸出(UTXOs)或已花費的交易輸出。要想付款有效,只能使用未花費的交易輸出UTXOs作為輸入。
先不講比特幣交易(後面會詳述),若一個交易的輸出超過交易的輸入,這個交易將會被拒絕--但是若是輸入超出輸出,這個差值可以作為交易費獎勵給建立這個區塊的Bitcoin礦工。例如,在上圖中,每個交易相比它相關的交易輸入花費了10000聰,實際上就是支付了10000聰的交易費。
工作量證明
區塊鏈是有由網路中對等的節點共同維護的,所以Bitcoin要求每個區塊需要一定工作量投入確保想篡改曆史區塊的不誠實節點比想在區塊鏈上建立新區塊的誠實節點需要付出更大代價。
連結區塊在一起使得在不修改所有後面的區塊情況下不可能修改此區塊中包含的交易。結果,修改特定區塊的成本隨著添加到區塊鏈中的每個新區塊而增加,放大了工作量證明的效果。
Bitcoin中使用的工作量證明利用了密碼散列的顯式隨機特性。一個好的加密雜湊演算法將任意資料轉換成看似隨機的數字。如果以任何方式修改資料並且重新得到雜湊值,則會產生一個新的看似隨機的數字,因此無法修改資料以使雜湊數值可被預測。
為了證明你做了一些額外的工作來建立一個區塊,你必須建立一個不超過某個值的區塊頭的散列。例如,如果最大可能的雜湊值為2256-1,則可以證明您通過產生雜湊值來兩兩組合最多嘗試次數小於2255。
在上面給出的例子中,平均每個其他嘗試都會產生一個成功的雜湊。您甚至可以估計給定雜湊嘗試將產生低於目標閾值的數位機率。比特幣假設一個線性機率,它使得目標閾值越低,平均需要更多的雜湊嘗試。
新的塊會被添加到塊鏈,僅當它們的雜湊難度至少與共識協議所期望的難度值相當。每2016 個塊,比特幣網路會使用儲存在每個塊頭中的時間戳記來計算產生上一個2016個塊的第一個區塊和最後一個區塊之間經過的秒數。這個理想值為1209600秒(兩周)。
如果產生2016個塊需要不到兩周的時間,則預期的難度值將按比例增加(高達300%),當以相同的速率檢查散列情況下以便接下來的2016塊應該恰好需要兩個星期來產生。
如果產生塊需要兩個多星期,因為相同的原因,預期的難度值會按比例降低(75%)。
(注意:Bitcoin Core實現中的一個時間戳記錯誤導致每2016 塊更新難度值僅從2015 塊,產生輕微的位移。)
因為每個塊頭必須雜湊到低於目標閾值的值,並且因為每個塊連結到前一個快,平均需要擴散一個更改過的區塊的雜湊算力與整個Bitcoin網路在初始塊的建立時間和目前時間之間所消耗的一樣多。只有您獲得了大部分網路的雜湊功能,您才可以根據交易曆史可靠地執行這種51%的攻擊(儘管如此,應該注意的是,即使小於50雜湊強度的百分比仍然有很好的機會進行這種攻擊)。
塊頭提供了幾個易於修改的欄位,例如專用的nonce欄位,因此擷取新的雜湊不需要等待新的交易到來。此外,只有80位元組的塊頭被散列以用於工作證明,因此在塊中包含大量的交易資料不會減慢雜湊的額外I/O和添加附加交易資料只需要重新計算merkle樹中的祖先散列。
塊高和分叉
任何算出塊頭的hash值低於目標閾值的Bitcoin礦工可以將整個塊添加到塊鏈上(假設塊有效)。這些塊通常由它們的塊高度 定位的 - 即它們與第一個比特幣塊之間的塊數量(塊0,最通常稱為創世塊)。例如,塊 2016是可以首先調整難度值的地方。
多個區塊可能有相同的區塊高度,當2個或多個礦工在大致相同時間內產生合適新區塊的時候這很常見。這在塊鏈中產生了一個明顯的分叉,如上圖所示。
當礦工同時在區塊鏈尾部產生新區塊,每個節點獨立選擇接受哪個區塊。在沒有其他考慮的情況下,如下所述,節點通常使用他們看到的第一個塊。
最終,一個礦工產生另一個塊,它只附加在一個競爭同時開採的塊中。這使得叉的那側比另一側更強。假設一個分叉僅包含有效區塊,正常節點通常緊接著最難的鏈來增長,拋棄那些屬於短分叉的到期區塊。(到期塊有時也稱為孤兒或孤兒塊,但是這些術語也用於沒有已知父塊的真孤兒塊)
如果不同的礦工工作在相反的目的,例如一些礦工努力擴充塊鏈,同時其他礦工正在嘗試發起51%的攻擊來修改交易曆史,則長期分叉是可能的。
由於在區塊鏈 的分叉中,多個塊可以具有相同的高度 ,區塊高度不應該被用作通用唯一識別碼。反而,塊通常由它們的塊頭的雜湊引用(通常以位元組順序顛倒,十六進位形式)。
交易資料
每個塊必須包含一個或多個交易。這些交易中的第一個必須是一個幣基交易,也稱為產生交易,它應該收集並花費塊獎勵(包括塊補貼以及由塊中包含的交易支付的任何交易費用)。
幣基交易的未花費的交易輸出UTXO有一個特殊的條件,它至少需要100個塊產生之後才能使用(用作輸入)。這暫時阻止礦工花費從一個分叉鏈上以後可能被淘汰的區塊(因此幣基交易也被刪除)上花費交易費和區塊獎勵。
區塊不需要包括任何非幣基交易,但是礦工幾乎總是包含額外的交易,以便於獲得他們的交易費。
包括幣基交易在內的所有交易都以二進位原始交易格式編碼入塊。
原始交易格式被散列為交易標識符(txid)。通過這些txid,merkle樹是通過將每個txid與另一個txid配對,然後將它們組合在一起構成的。如果有奇數個txids,那麼沒有夥伴的txid會使用自己的副本進行散列。
所產生的雜湊本身每個都與另一個雜湊配對,並且散列在一起。沒有夥伴的雜湊求自身的hash值。該過程重複,直到只剩下一個散列,這就是merkle根。
例如,如果交易僅是加入(不是求雜湊),那麼一個五個交易的merkle樹將如下圖所示:
根據在簡單支付驗證(SPV)子節的討論, merkle樹允許從一個完全分區的塊頭和一系列中間hash值得到的merkle根來驗證區塊中的一個交易。完整的分區不需要都被信任:偽造塊頭是昂貴的,中間雜湊值不能被偽造或者會驗證失敗。
例如,為了驗證事務D被添加到區塊,SPV用戶端除了merkle根之外只需要C,AB和EEEE散列的副本;客戶不需要知道任何其他交易。如果這個塊中的五個交易都處於最大值,下載整個塊將需要超過500,000個位元組,但是下載三個散列加上塊頭只需要140個位元組。
注意:如果在相同的塊中找到相同的txids,則可能merkle樹可能與塊,其中一些或所有重複項由於如何不平衡而被刪除merkle樹被實現(複製孤島雜湊)。由於使用相同的txids的單獨事務是不切實際的,所以這不會對誠實軟體造成負擔,但是必須檢查塊的無效狀態是否為緩衝;否則,重複資料刪除項的有效塊可以具有相同的merkle根和塊雜湊,但被緩衝的無效結果拒絕,結果在安全性漏洞中,如CVE-2012-2459。
共識規則更改
為了維護共識,所有全部節點使用相同的共識規則驗證塊。然而,有時共識規則要被改變以引入新功能或阻止網路被濫用。當新規則實施時,可能會有一段時間,當未升級的節點遵循舊規則並且升級節點遵循新規則時,導致兩種可能的方式打破共識:
遵循新共識規則的塊被升級後節點接受,但被未升級的節點拒絕。例如,在塊中使用新的交易功能:升級節點瞭解該功能並接受該功能,但未升級的節點拒絕因為它違反了舊的規則。
違反新的共識規則的塊被升級後節點拒絕,但被未升級的節點接受。例如,在塊中使用了濫用交易功能:升級後節點拒絕它,因為它違反了新規則,但未升級的節點接受它,因為它遵循舊的規則。
第一種情況,被未升級的節點拒絕,那些從其他未升級節點擷取區塊鏈資料的挖礦軟體拒絕和那些從升級過的節點擷取資料的挖礦軟體在同一條鏈上建立。這將建立永久性發散的鏈 - 一個用於未升級的節點,一個連結用於升級節點-- 這被稱為硬分叉。
第二種情況,被升級後的節點拒絕,如果升級後的節點控制著主要的hash速率則可能阻止區塊鏈永久發散。這是因為,在這種情況下,未升級節點和升級過的節點一樣接受相同的快,所以升級後的節點可以建立一個更強的鏈,也被未升級節點所接受。這被稱為軟分叉。
雖然一個分叉實際上是區塊鏈上發散,共識規則的改變經常被描述為它們潛在地建立一個硬分叉或者軟分叉。例如,“將塊的大小增加到1 MB以上需要一個硬分叉。在這個例子中,一個實際的塊鏈 分叉不是必需的 - 但這是一個可能的結果。
共識規則的改變可能會以各種方式啟用更改。在Bitcoin的前兩年,中本聰同過發布立刻強制使用新規則的向後相容的用戶端改變執行了幾次軟分叉。已經通過標記日啟用了多個軟叉,例如BIP30,其中新規則開始在預設時間或塊高度強制執行。通過標記日啟用的分叉被稱為使用者啟用軟分叉,因為他們取決於足夠多的使用者節點在標記日之後強制使用新規則。
稍後軟分叉等待多數雜湊速率(通常為75%或95%)來顯示他們對執行新共識規則準備就緒。一旦信令閾值已經通過,所有節點將開始執行新規則。這樣的分叉被稱為礦工活動軟分叉(MASF),因為它們依賴於礦工進行啟用。
資源: BIP16,BIP30和BIP34被實現為可能導致軟分叉。BIP50描述了一個意外的硬分叉和一個蓄意的硬分叉可以通過臨時降級升級後節點的能力來解決。來自Gavin Andresen的文檔概述了如何實施未來的規則更改。
檢測分叉
未升級的節點可以在兩種類型的分叉中使用和分發不正確的資訊,從而出現可能導致財務損失的幾種情況。特別地,未升級的節點可以中繼和接受被升級的節點認為無效的交易,因此永遠不會成為普遍認可的最佳區塊鏈的一部分。未升級的節點可能拒絕中繼那些已經或者即將添加到最佳區塊鏈裡面的區塊或者交易,因此它們提供不完整的資訊。
比特幣核心包括通過查看塊鏈 工作證明檢測硬分叉。如果一個未升級的節點接收到的區塊鏈頭顯示至少比最佳鏈的工作量多6個區塊,這個節點就會在getinfo RPC裡報一個錯誤,並在設定的情況下執行-alertnotify命令。這會提醒操作者未升級的節點不能切換到可能的最佳區塊鏈。
完整節點也可以檢查區塊和交易的版本號碼。如果當前幾個區塊中的區塊或者交易的版本號碼比這個節點使用的版本號碼高,可以假設它沒有使用當前的共識規則。Bitcoin Core 0.10.0如果設定了會通過getinfo RPC和-alertnotify命令報告此情況。
無論哪種情況,區塊和交易資料都不能被信任如果它們來自於一個明顯不使用當前共識規則的節點。
串連到全節點的SPV用戶端通過串連多個全節點,確保他們在同一個鏈上具有相同的塊高,或者根據賬戶傳輸時延和到期與否增減幾個區塊,能夠測到一個可能的硬分叉。如果存在分歧,用戶端可以使用較弱的鏈從節點中斷連線。
SPV用戶端還應該監控塊和交易的版本號碼增加,以確保它們用當前的共識規則處理接收到的交易。