03-BTC-共識協議

聲明:本文是要點筆記,介紹和系列筆記均收錄在專題:區塊鏈技術與應用

雙花攻擊

數字貨幣和紙質貨幣區別是,數字貨幣可以複製,叫作雙花攻擊(double spending attack)。

去中心化貨幣要解決兩個問題:

  1. 數字貨幣的發行
  2. 怎麼驗證交易的有效性,防止雙花攻擊(double spending attack)。

它的解決辦法是:

  1. 比特幣的發行是由挖礦決定的,
  2. 依靠區塊鏈的數據結構。

如上圖,比特幣的發行者 A 擁有鑄幣權(createcoin),假如發行 10 個比特幣,A(10) 分別給 B 和 C 各五個 → B(5)C(5), 該交易需要有 A 的簽名,證明經 A 同意(signed by A)。同時還要說明花掉的 10 個比特幣從哪來的。我們可以看到第二個方框中 A 的錢是從第一個框內鑄幣交易中來的。

比特幣系統中每個交易都包含輸入和輸出兩部分。輸入部分要說明幣的來源,輸出部分要給出收款人公鑰的哈希。

有的交易部分比較複雜,如 C 的貨幣來源是第二、第三個方框的交易,要標識清楚。

上圖就構成了一個小型的區塊鏈,這裏有兩種哈希指針,一種哈希指針是連接在各個區塊之間的,把它們串起來構成一個鏈表,前面學的就是這種哈希指針。而在該圖中還有第二種哈希指針,是指向前面某個交易的指針,用來指明幣的來源。

爲什麼要說明幣的來源?:證明幣不是憑空捏造的,是有記錄的,同時也是防範雙花攻擊(double spending attack)。

現在來看第二個方框裏 A 向 B 的轉賬,該交易需要 A 的簽名和 B 的地址。比特幣系統裏收款的地址是通過公鑰推算出來的。比如 B 的地址就是 B 的公鑰取哈希,然後經過一些轉換得到的。

A 如何知道 B 的地址呢?比特幣系統中沒有查詢對方地址的功能,必須通過其他渠道。比如某個電商網站,接受比特幣支付,就可以公開它的地址或公鑰。

A 需要知道 B 的地址,B 需要知道 A 的什麼信息嗎?B 其實也要知道 A 的公鑰,這代表 A 的身份。不僅是 B,所有節點都需要知道 A 的公鑰。而簽名是用私鑰簽名、公鑰驗證(注意不要跟前面知識弄混了,加密是用接收人的公鑰加密私鑰解密),所以區塊鏈上每個節點都要獨立驗證。

那如何才能知道 A 的公鑰?實際上交易裏就包含了。輸入時不僅要輸入幣的來源,還要輸入公鑰。那這就存在了安全漏洞,假如 B 的同夥僞造了這次交易呢?其實第一個方框裏鑄幣交易的輸出就有 A 的公鑰的哈希,所以第二個方框交易裏 A 的公鑰要跟前面哈希對的上。

比特幣腳本(BitCoinScript)

在比特幣系統當中,前面這些驗證過程,是通過執行腳本來實現的。每個交易的輸入是一段腳本,包括給出公鑰的過程,公鑰也是在輸入的腳本里指定的。每個交易的輸出也是一段腳本,驗證其的合法性,就需要把當前交易的輸入腳本跟前面交易(提供幣來源的交易)的輸出腳本拼在一起,然後看看能不能順利執行,如果能執行說明是合法的。

上圖是對交易系統進行的簡化,實際上每個區塊(對應圖中的每個方框)可以有很多交易,這些交易組成默克爾樹(merkle tree)。每個區塊分爲塊頭和塊身。

區塊

塊頭
塊頭包含的是區塊的宏觀信息,比如包含的域有:

  • version(用的是比特幣哪個版本的協議),
  • hashPre(區塊鏈當中指向前一個區塊的指針(hash of previous block header)),
  • merkleRootHash(整顆 merkle tree 的根哈希值),
  • target(挖礦的難度目標預值),
  • nonce(隨機數)。

這裏的 target,就是前面講到的,整個塊頭的哈希要小於這個預值,即 H(block header)≤target。block header 裏存的就是這個目標預值的編碼(nBits)。這裏需要注意,前一個區塊的哈希只算的是前一個區塊的塊頭,所以前面畫的,一個區塊引出一個箭頭指向另一個區塊中間,是不正確的,所以有的書箭頭是指向一個區塊的上面。取哈希時,是把塊頭的所有部分都取哈希。

塊身
塊身裏面有交易列表(transaction list)。

前面還有一個內容講的時候簡化了:每個節點都需要驗證所有的交易,實際上系統中的節點分全節點(full node)和輕節點(light node)。

  • 全節點是保存區塊鏈所有的信息的,驗證每一個交易,所以全節點,又叫 fully validating node。
  • 輕節點只保存 block header 的信息,一般來說輕節點沒法獨立驗證交易的合法性。

比如一個交易是不是雙花攻擊(double spending attack),輕節點沒有存之前的所有交易信息,所以它沒法驗證。系統中大多數節點是輕節點。我們現在主要講的是全節點,因爲輕節點沒有參與區塊鏈的構造和維護,只是利用了區塊鏈的一些信息做一些查詢。

區塊鏈裏的內容是如何寫到區塊鏈裏面的呢?:每個節點,每個賬戶都可以發佈交易,交易是廣播給所有節點的。有些交易是合法的,有些是非法的。

誰來決定哪些交易應該被寫入下一個區塊中呢?按照什麼順序寫呢?如果每個節點自己決定,可以嗎?:如果每個人在本地維護一個區塊鏈,那區塊鏈的統一性得不到保證,而賬本的內容是要取得分佈式的共識(distributed consensus)。

分佈式共識理論(瞭解)

分佈式的共識一個簡單的例子就是分佈式的哈希表(distributed hash table),比如系統裏有很多臺機器,共同維護一個全局的哈希表。

這裏需要取得共識的內容是什麼?哈希表中包含了哪些鍵值對(key valve pair)。假如有人在自己電腦上插入一個鍵值對,如 'xiao' 這個鍵對應的是 12345,即 'xiao'→12345。那麼別人在另一臺讀的時候也要能把這個讀出來,這就叫一個全局的哈希表。

關於分佈式系統有很多不可能理論(impossibility result),其中最著名的是 FLP理論。這三個字母是三個專家的名字縮寫,他們的結論是:在一個異步(asynchronous)的系統裏(網絡傳輸遲延沒有上限就叫異步系統),即使只有一個成員是有問題的(faulty),也不可能取得共識。

還有一個著名理論:CAP Theorem。CAP 是指分佈式系統的三個我們想要的性質:

  • Consistency:系統狀態的一致性,
  • Availability:大家都能用的可用性,
  • Partition tolerance:分區容錯性。

該理論內容是:任何一個分佈式系統,比如分佈式哈希表,這三個性質中,最多隻能滿足兩個,假如想要前
兩個性質,那麼就不會得到第三個性質。

比特幣分佈式共識一個著名的協議是 Paxos,該協議能夠保證一致性,即第一個性質。如果該協議打成了共識,那麼這個共識一定是一致的,即每個成員所認爲的共識都是相同的。但是,某些情況下,該協議可能永遠無法達成共識,這種可能性比較小但是客觀存在的。

比特幣共識協議(consensus in BitCoin)

比特幣中共識要解決的一個問題是,有些節點可能是有惡意的。我們假設系統中大多數節點是好的,那麼該如何取得共識協議?

第一種方案是投票,首先應該確定哪些區塊有投票權,有些 membership 是有嚴格要求的,這種情況下基於投票的方案是可行的。但比特幣系統創建賬戶是很容易的,一個人產生公私鑰對,別人是無法得知,只有轉賬時,別人才知道。所以有些人可以不停的創建賬戶,當超過賬戶總數的一半時就有了控制權,這種稱爲女巫攻擊(sybil attack)。因此投票方法不可取。

比特幣賬戶巧妙的解決了這個問題,不是按照賬戶數目投票,而是按照計算力來投票。每個節點都可以在本地組裝出一個候選區塊,把它認爲合法的交易放在裏面,然後開始嘗試各種 nonce 值(佔 4 byte),看哪一個能滿足不等式 H(block header)≤target 的要求。如果某個節點找到了符合要求的 nonce,它就獲得了記賬權。

所謂的記賬權,就是往比特幣賬本里寫入下一個區塊的權利。只有找到這個 nonce,獲得記賬權的節點纔有權利發佈下一個區塊。其他節點收到這個區塊之後,要驗證這個區塊的合法性。

H(block header)≤target,如果括號裏 block header 的內容填的不對,block header 裏面有一個域,叫 nBits 域,實際上它是目標預值的一個編碼,檢查一下 nBits 域設置的值是不是符合比特幣協議中規定的難度要
求來判斷該不等式是否成立。假設都符合要求,然後檢查 block body 裏面的交易列表,驗證一下每個交易都是合法的:1、要有合法的簽名,2、以前沒有被花過。如果有一項不符合要求,這個區塊就是不能被接受的。如果所有條件都符合,也不一定能被接受。

看上圖,假如生成了一個新區塊,怎麼知道新區塊插在了哪裏呢?根據生成區塊的上一個區塊指針(hashPre)。有可能存在一個問題是,看上圖,這兩個交易: A 轉賬給 B 以及 A 轉賬給自己(A')。這種情況不是雙花攻擊(double spending attack),判斷一個交易是不是雙花攻擊(double spending attack),是看這個區塊所在的分支上幣又沒有被花掉。如圖,一直到第三個區塊,幣都沒有花過,所以這兩個交易都是合法的。雖然交易都是合法的,但是轉給自己的交易不在最長合法鏈(longest valid chain)上。這種常稱之爲分叉攻擊(forking attack)。所以接收的區塊應該是擴展最長合法鏈。

區塊鏈在正常情況下也可能出現分叉:兩個節點同時獲得記賬權。每個節點在本地自己組裝一個它認爲合適的區塊,然後去試各種 nonce,如果兩個節點在差不多同一個時間找到了符合要求的 nonce,就都可以把區塊發佈,這時會出現兩個等長的分叉。這兩條都是最長合法鏈,那該接受哪條呢?比特幣協議當中,在缺省(默認的意思)情況下,每個節點是接受它最早收到的那個。所以不同節點根據在網絡上的位置不同,有的節點先接收到新生成的其中一個區塊,那就接受這個區塊;有些節點先接收到另一個區塊,那就接受另一個區塊。

如何判斷接收了一個區塊?比特幣協議中用到了隱性委託(implicit consign),如果沿着這個區塊往下繼續
擴展,就算認可了這個發佈的區塊。比如在新生成的其中一個區塊後面又拓展一個區塊,表明就認可了這個新區塊。

等長的臨時性的分叉會維持一段時間,直到一個分叉勝出。也就是哪一個鏈搶先一步生成了新的區塊,哪一條就是最長合法鏈。另一個作廢的就叫孤兒塊(orphan block)。這兩個新區塊有可能會各自拉攏,兩個區塊鏈看誰的算力強,有時候也是看誰的運氣好,就會勝出。

競爭記賬權的好處:首先獲得記賬權的節點本身有一定的權力,可以決定哪些交易寫到下一個區塊裏。但這些不應該被設定爲競爭記賬權的動力,所以比特幣巧妙地建立了一個機制:區塊獎勵(block reward)。

比特幣協議中規定獲得記賬權的節點在發佈的區塊裏可以有一個特殊的交易:鑄幣交易。在這個交易裏可以獲得一定數量的比特幣。

這裏要回到前面的問題1——誰來決定貨幣的發行?幣基交易(coinbase transaction)是比特幣系統中發行新的比特幣的唯一方法,其他的交易都是比特幣的轉移。這個交易不用指出幣的來源。

那麼能造多少幣呢?開始時比特幣剛上線的時候,每一個發佈的區塊可以產生 50BTC(BTC 就是比特幣的符號)。協議中規定,21 萬個區塊以後,初塊獎勵就要減半,就變成了 25BTC。再過 21 萬個區塊,又要減半。

因此當一個區塊勝出後,另一個作廢的區塊得到的比特幣是沒有作用的,其他誠實的區塊是不會承認的。

比特幣系統中要取得什麼共識?要取得去中心化的賬本共識。

誰又能決定賬本的內容呢?只有獲得記賬權的節點才能寫東西。怎麼獲得記賬權呢?就是解算力(挖礦)。按照算力記票,算力可以用每秒能試多少 nonce 數值表示。

那怎樣防範女巫攻擊呢?按算力記票,即使創建再多的賬戶,也無法使算力增強。

比特幣爭奪記賬權的過程叫作挖礦(mining),比特幣被稱爲數字黃金(digital gold),爭奪記賬權的節點被稱爲礦工(miner)。

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