區塊鏈系列教程之:比特幣中的共識

簡介

在比特幣的P2P網絡中是怎麼達成共識的呢?達成共識需要做哪些交易的校驗呢?交易和區塊是怎麼傳播到整個區塊鏈網絡的呢?看完這篇文章你就明白了。

比特幣中的共識

之前我在講分佈式系統的時候有講過分佈式系統的幾個共識算法,包括raft,Paxos和拜占庭容錯算法。

比特幣的共識和之前講的都不同,它使用的是工作量證明(POW)的算法。

比特幣的去中心化共識由所有網絡節點的4種獨立過程相互作用而產生:

▷ 每個全節點依據綜合標準對每個交易進行獨立驗證

▷ 通過完成工作量證明算法的驗算,挖礦節點將交易記錄獨立打包進新區塊

▷ 每個節點獨立的對新區塊進行校驗並組裝進區塊鏈

▷ 每個節點對區塊鏈進行獨立選擇,在工作量證明機制下選擇累計工作量最大的區塊鏈

交易的校驗

比特幣網絡中,交易是由網絡中的節點獨立校驗的。

在交易傳遞到臨近的節點前,每一個收到交易的比特幣節點將會首先驗證該交易,這將確保只有有效的交易纔會在網絡中傳播,而無效的交易將會在第一個節點處被廢棄。

每一個節點在校驗每一筆交易時,都需要對照一個長長的標準列表:

▷交易的語法和數據結構必須正確。

▷輸入與輸出列表都不能爲空。

▷交易的字節大小是小於MAX_BLOCK_SIZE的。

▷每一個輸出值,以及總量,必須在規定值的範圍內 (小於2,100萬個幣,大於0)。

▷沒有哈希等於0,N等於-1的輸入(coinbase交易不應當被中繼)。

▷nLockTime是小於或等於INT_MAX的。

▷交易的字節大小是大於或等於100的。

▷交易中的簽名數量應小於簽名操作數量上限。

▷解鎖腳本(scriptSig)只能夠將數字壓入棧中,並且鎖定腳本(scriptPubkey)必須要符合isStandard的格式 (該格式將會拒絕非標準交易)。

▷池中或位於主分支區塊中的一個匹配交易必須是存在的。

▷對於每一個輸入,如果引用的輸出存在於池中任何的交易,該交易將被拒絕。

▷對於每一個輸入,在主分支和交易池中尋找引用的輸出交易。如果輸出交易缺少任何一個輸入,該交易將成爲一個孤立的交易。如果與其匹配的交易還沒有出現在池中,那麼將被加入到孤立交易池中。

▷對於每一個輸入,如果引用的輸出交易是一個coinbase輸出,該輸入必須至少獲得COINBASE_MATURITY (100)個確認。

▷對於每一個輸入,引用的輸出是必須存在的,並且沒有被花費。

▷使用引用的輸出交易獲得輸入值,並檢查每一個輸入值和總值是否在規定值的範圍內 (小於2100萬個幣,大於0)。

▷如果輸入值的總和小於輸出值的總和,交易將被中止。

▷如果交易費用太低以至於無法進入一個空的區塊,交易將被拒絕。

▷每一個輸入的解鎖腳本必須依據相應輸出的鎖定腳本來驗證。

經過這麼多長長的校驗之後,交易就準備被寫入區塊了。

區塊的構建

驗證交易後,比特幣節點會將這些交易添加到自己的內存池中。內存池也稱作交易池,用來暫存尚未被加入到區塊的交易記錄。與其他節點一樣,挖礦節點會收集、驗證並中繼新的交易。而與其他節點不同的是,挖礦節點會把這些交易整合到一個候選區塊中。

比特幣節點需要爲內存池中的每筆交易分配一個優先級,並選擇較高優先級的交易記錄來構建候選區塊。交易的優先級是由交易輸入所花費的 UTXO的“塊齡”決定,交易輸入值高、“塊齡”大的交易比那些新的、輸入值小的交易擁有更高的優先級。如果區塊中有足夠的空間,高優先級的交易行爲將不需要礦工費。

然後,挖礦節點會選出那些包含最小礦工費的交易,並按照“每千字節礦工費”進行排序,優先選擇礦工費高的交易來填充剩下的區塊,區塊大小上限爲MAX_BLOCK_SIZE。

如區塊中仍有剩餘空間,挖礦節點可以選擇那些不含礦工費的交易。有些礦工會竭盡全力將那些不含礦工費的交易整合到區塊中,而其他礦工也許會選擇忽略這些交易。

在區塊被填滿後,內存池中的剩餘交易會成爲下一個區塊的候選交易。因爲這些交易還留在內存池中,所以隨着新的區塊被加到鏈上,這些交易輸入時所引用 UTXO的深度(即交易“塊齡”)也會隨着變大。由於交易的優先值取決於它交易輸入的“塊齡”,所以這個交易的優先值也就隨之增長了。最後,一個零礦工費 交易的優先值就有可能會滿足高優先級的門檻,被免費地打包進區塊。

區塊的校驗

在區塊中打包好了交易之後,會將該區塊廣播出去,而接收到區塊的節點就會進行區塊的校驗。

當一個節點接收到一個新的區塊,它將對照一個長長的標準清單對該區塊進行驗證,若沒有通過驗證,這個區塊將被拒絕。

這些標準可以在比特幣核心客戶端的CheckBlock函數和CheckBlockHead函數中獲得,它包括:

▷ 區塊的數據結構語法上有效

▷ 區塊頭的哈希值小於目標難度(確認包含足夠的工作量證明)

▷ 區塊時間戳早於驗證時刻未來兩個小時(允許時間錯誤)

▷ 區塊大小在長度限制之內

▷ 第一個交易(且只有第一個)是coinbase交易

▷ 使用檢查清單驗證區塊內的交易並確保它們的有效性

區塊鏈的分叉

因爲區塊鏈是去中心化的數據結構,所以不同副本之間不能總是保持一致。區塊有可能在不同時間到達不同節點,導致節點有不同的區塊鏈視角。解決的辦法是,每一個節點總是選擇並嘗試延長代表累計了最大工作量證明的區塊鏈,也就是最長的或最大累計難度的鏈。

在第一張圖中,網絡有一個統一的區塊鏈視角,以藍色區塊爲主鏈的“頂點”

當有兩個候選區塊同時想要延長最長區塊鏈時,分叉事件就會發生。正常情況下,分叉發生在兩名礦工在較短的時間內,各自都算得了工作量證明解的時候。

兩個礦工在各自的候選區塊一發現解,便立即傳播自己的“獲勝”區塊到網絡中,先是傳播給鄰近的節點而後傳播到整個網絡。

每個收到有效區塊的節點都會將其併入並延長區塊鏈。如果該節點在隨後又收到了另一個候選區塊,而這個區塊又擁有同樣父區塊,那麼節點會將這個區塊連接到候選鏈上。

其結果是,一些節點收到了一個候選區塊,而另一些節點收到了另一個候選區塊,這時兩個不同版本的區塊鏈就出現了。

假如工作在“綠色”區塊上的礦工找到了一個“粉色”區塊延長了區塊鏈(藍色-綠色-粉色),他們會立刻傳播這個新區塊,整個網絡會都會認爲這個區塊是有效的。

所有在上一輪選擇“綠色”區塊爲勝出者的節點會直接將這條鏈延長一個區塊。

然而,那些選擇“紅色”區塊爲勝出者的節點現在會看到兩個鏈:“藍色-綠色-粉色”和“藍色-紅色”。

如圖所示,這些節點會根據結果將“藍色-綠色-粉色”這條鏈設置爲主鏈,將“藍色-紅色”這條鏈設置爲備用鏈。這些節點接納了新的更長的鏈,被迫改變了原有對區塊鏈的觀點,這就叫做鏈的重新共識。

因爲“紅”區塊做爲父區塊已經不在最長鏈上,導致了他們的候選區塊已經成爲了“孤塊”,所以現在任何原本想要在“藍色-紅色”鏈上延長區塊鏈的礦工都會停下來。

全網將“藍色-綠色-粉色”這條鏈識別爲主鏈,“粉色”區塊爲這條鏈的最後一個區塊。全部礦工立刻將他們產生的候選區塊的父區塊切換爲“粉色”,來延長“藍色-綠色-粉色”這條鏈。

區塊鏈分叉的種類

通常來說區塊鏈的分叉可以分爲兩種:

硬分叉,是當比特幣協議規則發生改變,舊節點拒絕接受由新節點創造的區塊的情況。違反規則的區塊將被忽視,礦工會按照他們的規則集,在他們最後見證的區塊之後創建區塊。

軟分叉,是當比特幣協議規則發生改變,舊的節點並不會意識到規則是不同的,它們將遵循改變後的規則集,繼續接受由新節點創造的區塊。礦工們可能會在他們完全沒有理解,或者驗證過的區塊上進行工作。

通過硬分叉,區塊鏈早已經不是原來的那個區塊鏈了。

從上圖可以看到,比特幣從最初的的版本已經發展了很多個分叉,他們的本質都是一樣的,問題就在於你到底認可哪條鏈。

總結

本文介紹了區塊鏈的共識機制,和交易的校驗步驟,最後講解了區塊鏈的分叉。希望大家能夠喜歡。

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/bitcoin-consensus/

本文來源:flydean的博客

歡迎關注我的公衆號:程序那些事,更多精彩等着您!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章