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

前言

文章拋開技術的實現細節,着重講解比特幣如何解決分佈式存儲帶來的一致性問題,若是讀者已經對區塊鏈的分佈式存儲和同步的原理和解決方案很是清楚,爲了避免浪費讀者的時間,能夠忽略。html

爲了不讀者缺乏對比特幣、區塊鏈、挖礦知識點的瞭解而產生過多的疑惑,文章前小部分專門爲這部分讀者準備,經過簡單瞭解比特幣是什麼?區塊鏈是什麼?挖礦的原理,方便部分讀者消化接下來的知識點,但願能夠給讀者一些收穫,若是發現本人有理解不對的地方,或者有須要補充的地方,歡迎評論交流。算法

比特幣是什麼

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 個區塊的那個分支,被認定爲主鏈,此時短叉鏈做廢,包括裏面的交易記錄。

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

參考資料

相關文章
相關標籤/搜索