比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

lyning發表於2019-03-03

前言

文章拋開技術的實現細節,著重講解比特幣如何解決分散式儲存帶來的一致性問題,如果讀者已經對區塊鏈的分散式儲存和同步的原理和解決方案非常清楚,為了不浪費讀者的時間,可以忽略。

為了避免讀者缺少對比特幣、區塊鏈、挖礦知識點的瞭解而產生過多的疑惑,文章前小部分專門為這部分讀者準備,通過簡單瞭解比特幣是什麼?區塊鏈是什麼?挖礦的原理,方便部分讀者消化接下來的知識點,希望可以給讀者一些收穫,如果發現本人有理解不對的地方,或者有需要補充的地方,歡迎評論交流。

比特幣是什麼

2008 年中本聰發表了一篇《比特幣:一種點對點式的電子現金系統》(Bitcoin: A Peer-to-Peer Electronic Cash System)論文,它在論文中構思出比特幣的雛形(建模),描述了一種去中心化、對等式、基於數學和密碼學構建的加密貨幣——比特幣。正由於這個革命性的發明,2015 年,加州大學洛杉磯分校金融學教授 Bhagwan Chowdhry 曾提名中本聰為 2016 年諾貝爾獎經濟學獎的候選人。

2009 年中本聰釋出了首個比特幣軟體,並正式啟動了比特幣金融系統,截止至今日(2018-02-16)1 BTC ≈ ¥6.4萬,最高時 1 BTC ≈ ¥12萬,最低 1 BTC ≈ ¥0.4。

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

如果你問目前挖礦還來得及嗎?那我們先來看一組資料。

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

該系統截止至 2018-02-15 08:00:00,已經有 16,867,188 個比特幣被挖出,佔總發行量 2100 萬的 80.3%,只剩下不到 20% 的比特幣未被開採,所以現在才想去出挖礦有點為時已晚。

區塊鏈是什麼

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

比特幣去中心化底層採用的技術就是區塊鏈其本質是一個分散式資料庫,用於儲存每一筆比特幣交易記錄。比特幣網路僅僅認可和維護比特幣網路上每一個節點儲存著的那條完全相同且長度最長的區塊鏈,所有經過檢驗並符合要求的交易記錄都會被“礦工”打包成進區塊,然後傳送給比特幣網路上所有的客戶端節點,客戶端節點檢查區塊沒有問題之後,將區塊連線起來串成一條鏈,這條鏈很形象的就被稱為區塊鏈。

挖礦的原理

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

區塊是由比特幣網路上被稱為“礦工”的節點所生成,他們負責接收到網路上的所有的比特幣交易記錄,逐個檢查這些交易記錄是否符合要求,比如檢查每條記錄是否有正確的數字簽名,交易是否重複使用等等;然後將符合要求的交易記錄新增到自己增加製作的新區塊中。

中本聰為了讓新增區塊的變得困難,當“礦工”成功製作好這個新區塊時,還需要完成兩個額外的工作。

  1. 建立一個字串,字串 = 前一個區塊的SHA256函式值 + 新區塊的基本資訊 + 新區塊的所有交易記錄
  2. 尋找一個隨機數,使得 SHA256(字串 + 隨機數) 滿足某個 256 位的二進位制 Hash 值(比如滿足 Hash 值的前 n 位為 0,當 n = 50,計算出這個隨機數的概率就是 1 / (2 的 50 次方))。

通過設定 n 的大小即可改變隨機數被計算出來的概率,導致第二點的難度非常高,高到比特幣網路平均每 10 分鐘才會有一個礦工產生一個新區塊;隨著現在挖礦裝置不斷的升級,計算 hash 值的速度也越來越快,目前該難度值控制在每產生 2016 個區塊(兩個星期)就會動態改變一次,使得整個比特幣網路平均每隔 10 分鐘才會計算出一個符合要求的隨機數。

當礦工計算出這個隨機數之後,馬上把這個隨機數新增到新區塊中,馬上把這個新區塊傳送給比特幣網路上的各個客戶端節點,各個節點檢查沒問題之後就會把這個區塊新增到自己的區塊鏈的尾部,這樣子礦工才有可能得到比特幣的獎勵。

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

一致性問題的產生

對於比特幣來說,每一筆轉賬記錄都代表著“錢”,它是系統執行的基礎,如果把交易記錄儲存在一臺電腦上,當電腦發生故障時,那麼整個交易系統將癱瘓無法正常執行,所以這種做法不具備高可用性;交給專業的值得信賴的公司管理和維護?比如銀行,那麼誰能保證公司或個人在巨大的金錢誘惑下或在他人的威脅下,不會篡改交易記錄呢?中本聰發明比特幣的其中一個目的,就是消除對銀行等經融機構的依賴。所以比特幣採用的方案是,將每一條比特幣轉賬資訊都傳送到網路上,讓所有執行比特幣客戶端的計算機都儲存所有的比特幣交易資訊,這樣,每一條記錄都會被很多計算機儲存,不用擔心記錄缺失,而這樣會帶來三個一致性方面的問題:

  1. 交易記錄如何同步?
  2. 如何防止紀錄被篡改?
  3. 如何防止同一筆比特幣交易被重複使用?

三個一致性問題各自的痛點

  1. 交易記錄如何同步
比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

如果一部分客戶端沒聯網、沒有登入比特幣客戶端或者電腦關機,導致沒有接收到交易記錄,那交易記錄肯定是沒有被這部分計算機儲存的,這樣不同計算機上面的比特幣交易記錄就會不一致,那到底以誰為準?如何讓他們互相同步從而儲存相同的交易記錄呢?

  1. 如何防止交易記錄被篡改
比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

如果黑客篡改了網路上某個節點的一條或多個交易記錄,導致比特幣網路上的多個節點的交易記錄不一致,甚至出現交易資訊前後矛盾的問題,從而導致比特幣網路無法執行,那麼如何保證交易記錄不被篡改呢?

  1. 如何防止同一筆比特幣交易記錄被重複使用

假設只有 S 轉賬 10BTC 給 A,並且交易記錄已經得到驗證且有效,此時 A 賬號中只有 S 轉賬給他的 10 BTC,而 A 幾乎同時向 B 和 C 賬號轉入 10 BTC,如下表格:

序號 交易記錄 數字簽名
記錄1 “S賬號”支付10BTC給“A賬號” S用自己的私鑰加密SHA-256(“S賬號”支付10BTC給“A賬號”)】
記錄2 “S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“B賬號” A用自己的私鑰加密SHA-256(“S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“B賬號”)】
記錄3 “S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“C賬號” A用自己的私鑰加密SHA-256(“S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“C賬號”)】

由於地域問題和網路等問題,不同礦工節點先接收到的交易記錄可能會發生這樣的情況

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

不同的客戶端先接收的比特幣交易記錄不一致,而客戶端只認可最先接收到的交易記錄是有效的,比如記錄 2 先被接收,則記錄 3 作廢,同理,記錄 3 先被接收,則記錄 2 作廢,不同計算機對同一交易記錄的有效性產生分歧,導致不同節點的交易記錄不一致要如何解決呢?

如何解決一致性問題

比特幣底層使用區塊鏈技術解決一致性問題,那它是如何解決的呢?下面開始講解區塊鏈如何解決上面提到的三個一致性問題。

  1. 交易記錄如何同步

區塊鏈會被儲存在網路上每一個節點中(客戶端),如果你有一個比特幣交易的客戶端,一段時間沒有聯網之後再次連線到網路,客戶端會自動向網路中的其它節點發起同步自己沒有的區塊的操作,檢查無誤之後才逐一把區塊新增到自己的區塊鏈上

圖片來源於網上

這樣,每一個啟動並聯網的客戶端都會同步所有的比特幣交易記錄了。而檢查的過程是十分嚴格的,包括了每一區塊中每一筆的交易記錄是否符合要求,區塊間的交易記錄是否符合要求,下個區塊是否包含上一個區塊的 SHA-256(上個區塊的所有記錄) 值,檢查區塊是否符合要求等。

  1. 如何防止記錄被篡改?

在講解區塊鏈如何防止交易記錄被篡改之前,我們有必要了解一下區塊鏈中關於區塊的基礎知識。

在區塊鏈中,每個區塊可以看成由訊息頭訊息體組成。

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析
  • 訊息頭:包含區塊的建立時間、區塊的 hash 值,上個區塊所有交易資料的 hash 值等。
  • 訊息體:區塊的交易記錄。

區塊鏈中的每一個區塊都會包含上一個區塊的 Hash 值,構成如下圖:

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

這裡的 Hash 值其實就是一種雜湊函式,比特幣中使用的 Hash 函式是 SHA256。只要給定一個輸入值 x, 就可以得到一個固定長度的輸出值 H(x) ,例如字串 123 輸入到 SHA256 hash 函式的值為:

SHA256("123") = a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3

將返回值轉換成 256 位的二進位制數:

1010011001100101101001000101100100100000010000100011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

該演算法目前還沒有存在有效的破解手段,所以是安全的。

到這裡可以開始講解防篡改問題了,當交易記錄被存放到區塊中,並且這個區塊被加入到區塊鏈上,那麼這個區塊中的所有資訊都是不可修改,一旦修改,就會出現前後 hash 不一致,導致區塊鏈斷裂。

比特幣如何使用區塊鏈解決分散式儲存帶來的一致性問題——原理解析

除非惡意的節點總數的 CPU 算力比誠實節點總數的 CPU 算力還要強,那才有可能被“壞人”得逞,因為他可以依靠自己的算力,將節點之後的所有區塊重新打包併發布到比特幣網路上所有的節點,最終成為那條最長的區塊鏈從而被比特幣網路所認可。

然而這種情況幾乎是不可能的,第一,因為比特幣每次打包區塊,都需要完成一個難度非常高的工作,這個工作就是猜隨機數,專業術語叫做工作量證明(Proof-of-Work,PoW),難度隨著礦工算力的總和動態變化的,比特幣網路通過使用這個策略,讓全網平均每 10 分鐘只會產生一個新區塊,限制了惡意節點批量修改區塊的可能性;第二,比特幣經過了 8 年時間的發展,隨著比特幣價格的攀升,越來越多的礦工加入到“挖礦”當中,這使得比特幣網路算力不斷增強,想要超過全網的算力總和的可能性微乎其微。

為了解決防止篡改問題,比特幣也付出了非常大的代價,它讓全網幾乎所有的算力都花在了計算錯誤的 hash 上,導致了非常多的資源浪費。

  1. 如何防止同一筆交易被重複使用?

中本聰在他的論文中提到:

We propose a solution to the double-spending problem using a peer-to-peer network. The network timestamps transactions by hashing them into an ongoing chain of hash-based proof-of-work, forming a record that cannot be changed without redoing the proof-of-work.

大致意思:中本聰提出通過對等式網路(peer-to-peer network)來解決雙重支付(double-spending) 問題。網路上的交易記錄按照時間的先後順序(這個時間是由礦工記賬時決定的)被雜湊成一個持續的基於Hash的工作證明,形成一種不重新驗證(hash),就無法更改記錄的工作證明鏈。

嚴格來講,對等式網路 + 時間戳 + Hash 才是解決雙重支付的主要手段,而區塊鏈只是它們的儲存形式而已。

知道雙重支付的解決方案,在講解解決雙重支付原理之前,還需要知道一個知識點,比特幣軟體是如何計算使用者的餘額(剩下多少可用的比特幣)?

在比特幣中,計算某個錢包餘額的過程,是通過計算這個錢包地址的所有相關的轉賬記錄,來得出這個錢包地址對應還剩多少比特幣未被使用

舉例說明如何計算 A 錢包的餘額:

序號 交易記錄 數字簽名
記錄1 “S賬號”支付10BTC給“A賬號” S用自己的私鑰加密SHA-256(“S賬號”支付10BTC給“A賬號”)】
記錄2 “S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“B賬號” A用自己的私鑰加密SHA-256(“S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“B賬號”)】
記錄3 “S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“C賬號” A用自己的私鑰加密SHA-256(“S賬號”支付10BTC給“A賬號” -> “A賬號”支付10BTC給“C賬號”)】

假設有上面的比特幣轉賬記錄,並且交易記錄時有效的,比特幣客戶端通過計算 A 錢包相關的每一筆交易記錄的輸入(接收 BTC 轉賬記錄)和輸出(消費 BTC 轉賬記錄)值來得出 A 錢包所剩可用的比特幣數量,如下表格:

錢包 轉賬 可用比特幣
A +10 BTC 10 BTC
A -10 BTC 0 BTC
A -10 BTC -10 BTC

上面的 -10 BTC 只是為了演示計算比特幣的過程,真正的比特幣中不可能會出現這種情況。

瞭解餘額計算原理之後再回頭來看看,區塊鏈如何解決雙重支付問題。

這個過程中可能會出現三種情況:

  1. 兩條記錄被同一個成功製作新區塊的礦工節點接收:由於平均每隔 10 分鐘全網才能有一位“礦工”生成一個新區塊,這個礦工在接收到兩條交易記錄的時候,假設記錄 2 先接收,記錄 3 慢接收,“礦工”根據接收的前後順序檢查這兩條交易記錄是否有效,使用者餘額是否足夠支援本次的轉賬交易,很明顯,記錄 3 作廢。
  2. 兩條交易記錄被先後兩個不同的區塊的礦工節點接收:此時,先接收的交易記錄會被新增到新區塊中,假設比特幣客戶端節點驗證沒問題,然後把區塊新增到區塊鏈尾部;慢接收的交易記錄礦工在檢查該錢包地址在轉賬餘額時(檢查餘額並不是只在侷限在當前的區塊的交易記錄,而是會檢查主鏈上的其它區塊中的記錄),發現該錢包地址在上一筆交易之後,餘額已經不滿足下一筆轉賬交易,所以慢接收的交易記錄作廢。
  3. 兩條交易記錄被不同的礦工同時打包進新區塊併傳送給所有客戶端節點:這個情況是當礦工 A 先接收到記錄 2,然後才接收到記錄 3;礦工 B 先接收到記錄 3,然後才接收到記錄 2,並且兩個礦工都同時計算出隨機數,同時將新區塊傳送給比特幣網路上的所有客戶端節點,這個時候區塊鏈可能會出現分叉,比特幣協議規定,分叉之後最先達到 6 個區塊的那個分支,被認定為主鏈,此時短叉鏈作廢,包括裡面的交易記錄。

綜上所述,比特幣網路總是有辦法知道你把一分錢花兩次,所以雙重支付是不可能的。

參考資料

相關文章