1. 程式人生 > >區塊鏈基礎入門

區塊鏈基礎入門

原文標題的“Electronic Cash”[2]一詞,有別於通俗意義上的電子化的貨幣,比如:信用卡、借記卡,某銀行間兩個賬戶的轉賬,或者基於支付寶的線上支付交易。上述提及的之所以不能稱為Electronic Cash,是因為它們不具備Cash的2個基本要素:匿名性和持有者之間線下交易的能力。[3]

一個基於簡易Electronic Cash System的交易過程大致如下:

  1. A在銀行有1000.00 CNY的存款,A要求取出10.00 CNY,銀行給A一個10.00 CNY的“硬幣”(經過銀行認證的、可以儲存在電子郵件、USB等電子裝置上),並且將A的餘額修改為990.00 CNY。
  1. A把這張“硬幣”通過網路傳送給B,用於購買一杯咖啡。
  2. B收到“硬幣”後驗證錢是否是偽造的,如果驗證通過,B會收下錢並交給A一杯咖啡,交易完成。

可以看到作交易雙方的A和B並不需要知道任何對方的資訊(即匿名性),也無需第三方的介入(即持有者之間線下交易),就完成了一次完整的交易過程。

然而,上述的過程有個很明顯的問題:電子現金不具備現實中貨幣天然的防偽功能,A甚至通過簡單的複製、黏貼就可以再造出與之前消費的一模一樣的“硬幣”,並將這筆錢再次用於購買另一款商品,這是數字現金中著名的Double-Spending問題。

為了解決這個問題,絕大部分文獻都會在驗證過程中引入一個可信的第三方,通常也就是銀行。通過銀行來記錄A已經花費掉這個10.00 CNY硬幣的事實,當A嘗試第二次花費時,銀行會拒絕認可該行為,從而防止Double-Spending的產生。

一種基於銀行的數字現金交易模式

可以看到這是一種“中心化”的模式,銀行是每一筆交易所必須要經過的中心節點,銀行或者說可信第三方的引入很大程度上違背了上述數字現金的基本特性。那麼,是否存在一種不依賴於中心機構的數字現金體系,讓交易雙方可以完成點對點的貨幣支付?

Satoshi Nakamoto通過他的白皮書提出了一個近乎完美的構思,並以“比特幣”的形式將其付諸實踐。區塊鏈就是比特幣支付體系中所涉及的底層技術之一。

區塊鏈

要去掉前文所提及的對於銀行的依賴,需要解決的問題就是B在收到“硬幣”後如何驗證“硬幣”是否已經被花費過。銀行本身通過對每筆交易記賬(如果某個硬幣消費過,就將硬幣的狀態標記為已消費)和查賬(檢視硬幣消費狀態)的方式來防止重複消費。如果B不需要跟銀行直接通訊就可以直接查詢這樣一個賬本,在某種程度上就消除了部分對於銀行的依賴(查賬)。

而區塊鏈承擔的角色就是公開賬簿,全網所有的節點通過查詢這本賬來判斷某筆交易的合法性。

既然作為全網賬簿,需要解決的本質問題就是公信力問題,其中一點就是:已有的交易紀錄一旦記入賬本就不可篡改,即使是“記賬人員”本身也無法修改任意一條已存在的紀錄。

一個簡單的構思

假設區塊就是某個時間段內若干條交易記錄的簡單集合,如何保證這個記錄不可篡改?一個簡單的做法就是雜湊!一旦記錄了區塊的雜湊值,試圖修改其中任何一筆交易都會導致雜湊值的變化,從而達到了防篡改的目的。

下圖是比特幣體系採用的Merkle樹[4],通過對於交易TxA和TxB生成雜湊HAB並通過與HCD的再次雜湊得到樹根HABCD,當客戶端需要校驗交易TxC是否存在於區塊時,只需要對該交易做雜湊生成HC並依次與HD和HAB依次取雜湊值,再與樹根的雜湊值對比,如果一致則說明交易存在於區塊中。這樣的方式在白皮書中稱為“Simplified Payment Verification”在演算法上優於交易集合的遍歷。

Merkle樹

同時對於每個區塊都需要加蓋“時間戳”用以確定某個交易發生在某個時間點之前。

時間和雜湊值共同保證了某一筆交易一旦入賬則不可更改。

更近一步

上文通過Bn = H(tn, M(Txsn))的方式達到了某個區塊防篡改的目的。其中tn表示區塊n的時間戳, M(Txsn)表示交易合集的Merkle值,H表示雜湊函式。“記賬員”通過不停的對區塊雜湊並加蓋時間戳來記賬,一切看起來很完美。但是假設某一筆交易存在於時間戳為2016-11-11 01:00:00的區塊,怎麼保證另一筆存在於另一個區塊的交易,實際上發生在2016-11-11 02:00:00,卻不會被“記賬員”因為某種利益偷偷把時間戳改成2016-11-11 00:00:00?上述的“記賬員”對於時間擁有絕對權力,甚至可以隨意更改任意一個區塊的時間戳。需要有一個方法保證區塊中紀錄的每一筆交易都是按照時間順序產生的。哪怕是“記賬員”也不可以隨意更改這個時間。[5]

假設我們在上述公式中引入因子Bn-1,則:Bn = H(tn, M(Txsn), Bn-1),其中:Bn-1 = H(tn-1, M(Txsn-1), Bn-2)

即新產生的區塊需要引用上一個產生的區塊的雜湊值,區塊間形成一個鏈條,B0->B1->...Bt-1->Bt->...->Bn,假設當前區塊鏈已公佈,要篡改紀錄將某筆交易對應的區塊插入Bt-1和Bt之間,勢必需要在Bt-1之後插入Bt-1',並試圖使Bt=H(tt, M(Txst), Bt-1'),根據雜湊函式的性質,顯然這是不可能的。同時假設要修改t-1時刻的某筆交易,勢必導致Bt-1變化隨後的所有區塊的雜湊值將會全部發生變化。

以下是真實的比特幣系統中區塊鏈的示意圖[6]所示:

比特幣的區塊頭結構

人人都是記賬員

賬本的問題解決了,客戶端可以放心的查賬,而且保證這本全網賬簿是具有公信力的,那麼如何產生賬本的紀錄,就成了下一個需要解決的問題。一旦解決了不依賴銀行的記賬問題,那麼這種基於“記賬員”的中心化的體系也就不再必要了。

事實上,比特幣網路中的每一個節點都有資格產生下一個合格的區塊,也就是記賬。所謂合格,即:從創世區塊(區塊鏈的第0個區塊)開始,每個區塊都對於下一個區塊的雜湊值有一個要求,已下圖為例:

創世區塊

要求當下一個區塊產生時,區塊對應的雜湊值必須小於00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048這個數,如上述所說,計算區塊的雜湊Bn = H(tn, M(Txsn), Bn-1),如果結果不滿足父區塊的要求怎麼辦?在公式中,再引入一個干擾因子,則Bn = H(tn, M(Txsn), Bn-1, nonce),干擾因子的值從0開始一直累加,直到某個雜湊值滿足父區塊的要求為止。

基於雜湊函式的特性,從數學上來說上述過程只能通過窮舉完成,也就是誰計算的速度快,誰就可以先得到合法的下一個區塊,並通過P2P網路傳播出去,其他礦工校驗了這個區塊的合法性後,將該區塊加入到該礦工自己的記憶體中(一個完全的礦工節點在記憶體中存有從創世區塊開始一直到當前時間所有的區塊)。上述的過程稱之為Proof-of-Work,即工作量證明,在比特幣體系中有個形象的名詞叫“挖礦”。

最長鏈

假設上一個合法區塊要求子區塊的雜湊值滿足小於H1,同時有兩個節點,各自獨立計算出了兩個合法的雜湊值均滿足要求,此時就帶來了一個新的問題,區塊鏈分叉,[7]如下圖所示:

形象化的區塊鏈分叉事件:同時發現兩個區塊

全網本來都基於藍色區塊鏈,接下來,全網節點分成2個陣營(紅和綠)。

形象化的區塊鏈分叉事件:兩個區塊的傳播將網路分裂了

當前2個陣營都是合法的,因為他們完全符合區塊鏈延伸的要求,同時兩個陣營的區塊鏈長度一致。除非保證兩個陣營的算力永久平均分配,否則總有一個陣營搶在另一個陣營前發現工作量證明解並將其傳播出去。在這個例子中我們可以打個比方,假如工作在“綠色”區塊上的礦工找到了一個“粉色”區塊延長了區塊鏈(藍色-綠色-粉色),他們會立刻傳播這個新區塊,整個網路會都會認為這個區塊是有效的。

形象化的區塊鏈分叉事件:新區塊延長了分支

所有在上一輪選擇“綠色”區塊為勝出者的節點會直接將這條鏈延長一個區塊。然而,那些選擇“紅色”區塊為勝出者的節點現在會看到兩個鏈:“藍色-綠色-粉色”和“藍色-紅色”。如下圖所示,這些節點會根據結果將“藍色-綠色-粉色”這條鏈設定為主鏈,將“藍色-紅色”這條鏈設定為備用鏈。這些節點接納了新的更長的鏈,被迫改變了原有對區塊鏈的觀點,這就叫做鏈的重新共識。因為“紅”區塊做為父區塊已經不在最長鏈上,導致了他們的候選區塊已經成為了“孤塊”,所以現在任何原本想要在“藍色-紅色”鏈上延長區塊鏈的礦工都會停下來。全網將“藍色-綠色-粉色”這條鏈識別為主鏈,“粉色”區塊為這條鏈的最後一個區塊。全部礦工立刻將他們產生的候選區塊的父區塊切換為“粉色”,來延長“藍色-綠色-粉色”這條鏈。

形象化的區塊鏈分叉事件:全網在最長鏈上重新共識

以上稱之為區塊鏈的共識演算法。

交易

在比特幣體系中,並沒有“餘額”的概念,所謂某某人的餘額是100.00 CNY,意味著的是整個系統中A可以解鎖使用的“錢”的總和是100.00 CNY。一次交易的過程,如:A花費10CNY給B購買1杯咖啡,B給A找零2.00 CNY,實際上是指:A解鎖10.00 CNY的“錢”,系統“銷燬”該筆資金,並生成8.00 CNY只有B能解鎖的新錢,以及2.00 CNY只有A能解鎖的新錢。從巨集觀上看,A的賬戶消費了10.00 CNY的餘額並收到2.00 CNY的找零;同時,B的賬戶增加了8.00 CNY的餘額。

鎖定和解鎖指令碼

比特幣源自於加密貨幣,因此涉及了大量密碼學的知識,除了上述提到的雜湊函式,還使用了非對稱密碼學的概念:

名詞 可公開性 用途
Private Key 不可公開 生成數字簽名
Public Key 可公開 校驗數字簽名
Public Key Hash 可公開 收款和解鎖

所以,為什麼只有A能解鎖?

比特幣的鎖定/解鎖指令碼

只有通過A提供的PubKHash160才能得到PubKHash,才能解開指令碼的前半部分,之後再通過sigPubK校驗該簽名是否合法,並以此判斷是否是A主動發起的操作。完整的校驗過程如下:[8]

解鎖步驟一

解鎖步驟二

上述步驟在有些地方也被推廣定義為“智慧合約”。

匿名性

通過上述的步驟,可以看到私鑰由某個使用者妥善儲存,用於收款的地址通過私鑰推匯出公鑰再經過Hash160得到,因此在網路上,收款人是完全匿名的。

再論Double-Spending

通常說區塊鏈是不可修改的,然而區塊鏈真的是不可修改的麼?從以上的介紹可以看到,只要區塊的Hash值滿足父區塊的要求,即被認可為合法區塊,而合法區塊的最多工作量證明(最長合法區塊鏈)即為區塊鏈的主鏈,被記錄在主鏈上的交易被認為是不可篡改的。試想一下,如果某個組織佔有了全網51%的算力,當ta向你支付價值22億刀的比特幣,你等待了若干個區塊後確認收到錢並支付了一架F22戰機,這時候組織陰險的嘴臉開始顯露,ta啟動了超越全網50%算力的礦機,並從你的交易所在的那個區塊開始重建一條更長的區塊鏈,並將你從交易的收款人中剔除並更換為另一個人。只要算的夠快,很容易出現軟分叉,並且最終原本正常的區塊被惡意替代。

因此一般的大額交易需要“得到6個區塊確認後”才能說安全,如果是鉅額的交易需要等待12個以上區塊,大約就是2個小時時間。

或許你覺得控制全網51%的算力是一件不可思議的事情,但事實上,比特幣並沒有按照白皮書所設計的那樣通過每個單獨的小礦工均參與的模式來生成區塊,而是演變為若干小礦工集合形成大礦池模式,並通過leader分配任務,礦工間平行計算,以礦池為單位和其它礦工競爭。可以預見的是,後續礦池還會繼續合併,而最終演變為若干巨鱷間的遊戲,這不是技術問題,而是經濟問題。一旦全網從無數個節點變為若干個巨大礦池很容易出現的問題就是,一些礦池間形成聯盟從而掌握50%以上算力。

即使在過去,也曾出現過中國礦池超越全網算力50%以上的事實。更別說那些山寨共有鏈體系下全網算力或許還不如一臺超算的情況。

POW的問題

POW是比特幣採用的共識演算法,其中一個最主要的問題是,計算無意義的雜湊值會導致資源(電能)的大量浪費。

與此同時,比特幣網路對於工作量的要求為__平均__10分鐘產生下一個區塊,這一限制使得整個網路的總體效能急劇下降。區塊需要包含這10分鐘所有的交易記錄,當前比特幣區塊的限制是1M,平均1筆交易的大小是0.25K,那麼當前的極限交易量是:1*1024K/0.25K/Tx/600s大約7Tx/s,同期支付寶的交易承載峰值是100000Tx/s。

或許可以通過降低2個區塊產生的間隔來解決問題,但實際上一節已經提到一般交易需要6個區塊確認,更準確的說法是:需要記錄在區塊鏈的某個區塊中,並且此區塊後面至少連結了5個區塊,總體來說就是60分鐘。如果每個區塊的生產速度是1分鐘,那麼攻擊的難度也就相對降低了,為了保證交易不會被51%的算力篡改,依然還需要等待大約60分鐘。

那麼是否可以通過增加區塊的大小來增加效能?事實上一個巨大的區塊在網路上有效傳播對於頻寬等硬體設施的要求是極高的。縱使忽略這些客觀因素,要提供一個對於當前系統完全無影響,又能同時修改全網上千萬個礦工的系統引數的方案几乎也是不可行的。

作者:elon_wen 連結:https://www.jianshu.com/p/6b67c87777ce