1. 程式人生 > 其它 >BTC-比特幣分叉(區塊鏈技術與應用)

BTC-比特幣分叉(區塊鏈技術與應用)

產生分叉的情況

對區塊鏈狀態產生了分歧:state fork

如果兩個節點差不多同時挖到一個區塊,這兩個區塊都是掛在當前的區塊上的,不同節點先收到的區塊不同,就會各自沿著先收到的區塊往下擴充套件,這種時候就會出現臨時性的分叉,稱為state fork,即由於對區塊鏈當前的狀態有意見分歧而產生的分叉。

分叉攻擊(forking attack)也屬於state fork,只不過這種意見分歧是人為造成的,這種情況也稱為deliberate fork。

比特幣的協議發生了改變:protocol fork

要修改比特幣協議需要軟體升級,在去中心化的系統中,沒辦法要求所有的結點都升級軟體(因為它們根本不需要哪個中心化的節點提供服務)

假設大部分節點升級了軟體,少部分節點沒有升級(可能是沒來得及升級,也可能是不同意協議的修改),這種分叉稱為protocol fork,即對比特幣協議產生了分歧,使用不同版本的協議而產生的分叉

在protocol fork中,根據對協議修改的內容的不同,又可以分為硬分叉和軟分叉。

  1. 硬分叉(hard fork)

如果對比特幣協議增加一些新的特性,擴充套件一些新的功能,這時候沒有升級協議的那些結點是不認可這些特性的(認為它們是非法的)。

硬分叉的一個例子就是比特幣中的區塊大小限制,比特幣限制每個區塊不超過1M,這樣算下來大約最多能容納4000個交易。而平均10分鐘產生一個區塊,算下來大約平均每秒只能寫入7個交易,所以有的人就認為區塊太小了,限制了交易上鍊的速度。

假設協議更新了,將區塊大小的限制從1M提高到4M,假設大多節點更新了軟體以支援這個協議。

注意:節點的“多數”和“少數”不是按照賬戶數目來算的,而是根據算力來算的,上面那句話是假設系統中擁有大多雜湊算力的節點都更新了軟體。

假設新節點挖出一個區塊(下圖中藍色),這個區塊是比較大的(因為新的協議只要不小於4M),但舊節點是不認可這個區塊的,不會沿著這個區塊繼續往下挖,而是繼續沿著之前的區塊往下挖下一個區塊(圖中紅色部分)

在這個分叉狀態下,上面那個藍色區塊的分叉新節點認可,舊節點不認可;下面這個紅色區塊的分叉新舊節點都認可(因為新舊協議都符合,不超過1M一定不超過4M)。

然而,假定大多節點都是新節點,即更新了軟體支援新的協議,因為“大多數”即是其算力更強,新節點的新區塊的分叉很快就比舊節點的分叉長了

對新節點而言,上下兩條鏈都是合法鏈,但因為只會去擴充套件最長合法鏈,所以還是會沿著上面的鏈往下挖。因為只是約束了大小不到4M就可以,新節點也可能挖出一些大小不到1M的區塊:

這樣的區塊是新舊節點都承認的,但上面這條鏈上有舊節點認為不合法的區塊,所以舊節點始終不會去擴充套件這條鏈,還是繼續沿著下面這條鏈往下挖:

因此,這樣的分叉是永久性的,只要這些舊節點不更新軟體,這樣的分叉就不會消失。比特幣網路中,會有部分很保守的人,像這樣的協議更新勢必會有一些節點不同意,產生硬分叉。

出現硬分叉之後,就相當於社群分裂了,出現了兩條平行執行的鏈,兩條鏈上的BTC也是不相干的,各挖各的礦。在某條鏈上的出塊獎勵,對於認可這條鏈為最長合法鏈的節點而言是有效的,對認可另一條鏈的則是無效的,而分裂之前產生的BTC則是在兩條鏈上都認可的。

從這個意義上來看,硬分叉可以認為是產生了新的一種加密貨幣。

硬分叉之後,如果不採取任何措施,會產生一些問題:

因為兩條鏈上的賬戶的私鑰、公鑰等都是一樣的,僅僅是執行的協議不同。按理來說兩條鏈上的賬戶餘額應該不一樣才對,但不採取措施時就不行。例如,在新鏈上有一筆交易B->C,那麼對舊鏈而言這筆交易也是完全合法的,所以C可以把這筆交易釋出出去,舊節點挖礦時就會把這個交易回放了。

這樣就相當於B從一個錢包中拿出一定數量的幣給C,導致B的另一個錢包中也轉給了C同樣數額(注意不是價值,如以太幣ETC和硬分叉後的ETH)的幣到相應的錢包中。

為了解決這個問題,可以在硬分叉後設置chain ID,來標識這兩條鏈為兩條獨立的鏈。

  1. 軟分叉

如果對比特幣協議加了一些限制,使得原本某些合法的交易或區塊,在限制後的新協議中變得不合法,那麼形成的分叉是軟分叉。

和前面學習硬分叉時候的例子相對應,假設協議更新將區塊的限制大小變小了,從1M變成了0.5M(實際肯定不會這樣做)。還是假設大多(算力的)節點是新節點,即已經更新了協議,區塊限制為0.5M;少部分(算力的)節點是舊節點,仍然認定區塊限制為1M。

這時,新節點挖出的區塊,舊節點會認為是合法的(因為在1M以內);但是舊節點挖出的區塊,新節點很可能不認為是合法的(因為很可能不在0.5M內):

因為新節點佔了大部分算力,所以很可能先挖到某個區塊,出現上圖的情況。這時舊節點觀察到上面那條是最長合法鏈,就會放棄自己的分叉,接著上面的鏈繼續挖。

某個時刻,舊節點先於新節點挖出一個區塊,將其上鍊:

這個區塊大於0.5M,新節點不認,會繼續擴充套件上一個合法的區塊。這樣舊節點剛剛挖的區塊又成為orphan block了:

所以在這種情況下,會持續出現軟分叉,只要舊節點不更新協議,挖出的區塊就一直無法上鍊。相比硬分叉,軟分叉即是非永久存在的分叉,只會臨時存在一段時間

實際當中可能出現軟分叉的情況

  1. 給某些目前協議中沒有規定的域增加新的含義

這種情況下即是當前協議中未限制的一些域,被賦予了新的規則。

一個例子就是鑄幣交易的CoinBase域,沒人規定也沒人檢查。前面學習挖礦難度時,提到這個域可以作為extra nonce來使用,比如拿出前8個位元組來和nonce一起調整,以增大挖礦的搜尋空間。

CoinBase即便拿出了前8個位元組,後面還是有很長的可調整空間。有人就提出將其作為UTXO的根雜湊值,因為目前這個UTXO集合只是每個全節點自己在維護,目的就是快速查詢,判斷交易合法性,這個集合的內容沒有寫到區塊鏈裡。

前面最開始學過Merkle proof可以證明某個交易存在於某個區塊中,那麼如何證明某個賬戶A中有多少錢?全節點可以在本地的UTXO集合裡算一下,即找到UTXO中所有轉賬給A的交易的輸出,加在一起。

但如果是輕節點呢?例如手機上的比特幣錢包。輕節點要去請求全節點,全節點返回結果給它,如何證明全節點返回給輕節點的是正確的呢?輕節點自己沒有維護一個UTXO集合,所以是證明不出來的

因此有人提出將UTXO中的交易也組織成一個Merkle Tree,將其根雜湊值寫在鑄幣交易的CoinBase域裡面,而鑄幣交易中的此內容也會隨著影響交易的Merkle Tree的根雜湊值,這在輕節點裡是儲存了的。所以在這種方式下就可以像Merkle proof的方式一樣證明賬戶裡有多少錢(需要提供UTXO的Merkle Tree對應位置的雜湊)。

  1. 增加新的功能

前面學的P2SH(Pay to Script Hash)形式的交易指令碼,最開始的比特幣系統中是沒有的,是後來通過軟分叉的方式加進去的。

P2SH即在支付時輸出不是收款人公鑰的雜湊,而是一個贖回指令碼(Redeem Script)的雜湊。

在贖回(把這些BTC花出去)時分為兩階段,第一階段驗證輸入指令碼中給出的贖回指令碼,和前面交易的輸出指令碼中的贖回指令碼的雜湊對得上;第二階段執行贖回指令碼,驗證輸入指令碼中給出的簽名是合法的。

對於舊節點而言,並不知道贖回指令碼的這些特性,舊節點只會做第一階段的驗證,即驗證贖回指令碼是不是正確的(和雜湊對得上)。只有新節點才會把兩階段的驗證都做完。

所以舊節點驗證通過的交易,可能是第二階段驗證無法通過的P2SH形式的交易,在新節點上無法驗證通過。而新節點驗證通過的交易,舊節點也都驗證通過。

總結

軟分叉的特點

只要系統中半數以上(算力)的節點更新了軟體,就不會出現永久性的分叉。這類分叉為軟分叉。

硬分叉的特點

必須系統中所有(算力)的節點都更新了軟體,才不會出現永久性的分叉。