比特幣協議是怎樣工作的(上)
作者:Michael Nielsen
譯者:楊碩
原文鏈接:比特幣協議是怎樣工作的(上) | 巴比特
成千上萬的文章試圖去解釋比特幣,一個在線的、點對點(Peer-to-Peer)的貨幣。大多數文章對其底層的協議一筆帶過,省略了許多細節。就算是那些很深入的文章也在關鍵的地方搪塞過去。這篇文章的目的是用儘可能清晰的、易理解的方式解釋比特幣協議背後的要點。我們從第一原則開始,建立一個廣義的理論上理解比特幣協議,然後深入到細節去,檢查比特幣交易里的元數據。
深入的理解這個協議是困難的,因為很容易就將比特幣視為給定的,並且去想如何利用它投機發財、想其是不是泡沫、想比特幣是否意味著對稅收的終結等等。想這些很有趣,但是這些想法嚴重的限制了你的理解。而理解比特幣的協議本身將會打開其他渠道不可達到的視角。比如說這個協議是比特幣內置的腳本語言的基礎,這個腳本語言讓你可以用比特幣創造新的金融工具,比如智能合同(smart contracts)。新的金融工具反過來可以創造新的市場和新的人和人之間的合作行為,說到樂趣,這才是真正的樂趣所在!
我會在以後的文章中解釋比特幣腳本和智能合同。這篇文章我會集中在比特幣協議的具體細節。理解這篇文章你需要大概熟悉一下公鑰密碼 和 與其相關的數字簽名,(請了解一下兩個概念)。同時還大概熟悉一下(哈希)Hash函數 (把任意長度的輸入變換成固定長度的輸出)。這些概念都很棒,如果你不了解,建議你花一些時間熟悉一下他們。
比特幣的基礎是密碼學,這點可能會讓你吃驚,不是說比特幣是一種貨幣嗎?難道它是一個發送秘密信息的方式嗎?實際上,比特幣想要解決的問題絕大部分是關於保護交易的——保證人們不能偷別人的東西或冒充別人等等。在原子組成的物質世界裡,我們通過鎖,簽名,銀行保險箱等等來保證安全。在信息世界裡我們通過密碼學來保證安全性。這就是為什麼比特幣的核心是密碼學的協議。
這篇文章的策略是一層一層的建立起比特幣。我們會從一個非常簡單的數字貨幣開始,我們暫時叫他「Infocoin」,用來區分於Bitcoin。當然我們第一版本的Infocoin會有很多的缺點,所以我們會經過幾次迭代,每次迭代會新介紹一到兩個新的概念。經過若干次之後,我們就會得到一個完整的比特幣協議了。我們會一起重新發明比特幣。
這種辦法比一開始就直接解釋比特幣要慢一些。但是即使你可以一下了解比特幣的原理,你也很難理解為什麼比特幣要設計成這個樣子。而慢慢的一步一步迭代式的解釋,其優點就在於它可以讓你對比特幣的每個元素有更清晰的理解。
最後我應該說的是我在比特幣世界相對來講是新人。我2011年有粗略的關注,但是真正認真研究其細節,是2013年初。歡迎任何人對我錯誤的部分進行糾正。
第一步:簽了名的意向書
怎麼設計一個貨幣呢?
從表面判斷,一個數字貨幣聽起來不可能。假設一個人——我們叫她Alice——有一些想要花掉的數字貨幣。如果Alice可以用一串字元作為錢的話,我們怎麼能阻止她用同樣的那串字元反覆的使用呢?如果我們能解決這個問題,我又怎樣能防止其他人偽造一串字元,從Alice那邊偷走呢?
這只是用信息做貨幣要解決的眾多問題中的兩個。在第一版的Infocoin中,我們想辦法讓Alice供一個字元串來作為錢,並且想個辦法保護它不被偽造。假設Alice要把一個infocoin給另一個人Bob。Alice需要寫下一個消息:「我Alice要給Bob一個infocoin」。 她然後用數字簽名的辦法將這個信息和一個私鑰(這個私鑰是隨機生成的一個64位數)一起簽下名產生一個結果。並且將這個簽了名的結果字元公布給整個世界。
這個辦法並不怎麼出眾,但還是有一些優點的。世界上任何人都可以用Alice的公鑰去驗證Alice確實是那個簽了名的人。其他任何人都不可能產生那個簽名的結果(這個簽名只可能從Alice擁有的私鑰產生,原理請看上文提到的數字簽名),所以Alice不能反悔說「不,我沒有給Bob那個infocoin」。這樣,這個協議提供了Alice確實有意向給Bob一個infocoin的證明。同樣,其他任何人都不能產生那樣一個簽了名的信息,這樣防止了其他人偽造Alice的信息。當然,當Alice已經發布了她的消息之後,其他人是有可能複製這個消息的,但是發布之前不可能偽造。所以,證明意向和防止消息發布之前被偽造這兩個功能是這個協議里真正值得注意的特性。
我還沒有說這個協議里的錢到底是什麼呢。明確的說:錢其實就是這個消息本身。也就是說那一串代簽了名的代表著「我Alice要給Bob一個infocoin」的字元。後面協議將會在這一點上類似,也就是所有的數字貨幣只是越來越詳細的消息字元。
用序列號來給貨幣一個唯一的標識
我們第一版的Infocoin的問題是Alice可以重複地給Bob發送同一個簽了名的消息。假設Bob收到了10份這樣的消息「我,Alice,要給Bob一個infocoin」。這是說Alice給Bob了10個不同的infocoin呢?還是Alice給Bob一個infocoin,只是不小心消息重複了?或者是她想要欺騙Bob讓給他相信她給了他10個infocoin,而實際上給外面世界發出的消息只證明了她只給了一個infocoin。
我們想要的是讓infocoin有個唯一的標識。它需要一個標籤或者序列號。Alice可以在消息「我Alice要給Bob一個序列號為8740348的infocoin」上簽名。之後Alice如果在另一個消息里簽名 「我Alice要給Bob一個序列號為8770431的 infocoin」,這樣,Bob和其他人就會知道這裡兩個是不同的infocoin。
為了讓這個方案可行,我們就必須要一個可信的序列號來源。一種產生序列號的辦法是建立一個機構比如銀行。這個銀行將會為infocoin產生序列號,記錄誰擁有著哪個infocoin,並且驗證交易的真實性。
更詳細的說,我們假設Alice去一個銀行,說「我要從我的賬戶里取一個infocoin」。這個銀行從她的賬戶里減掉一個infocoin,然後給她一個新的從沒用過的序列號,假設是「1234567」。然後,當Alice想要給Bob發一個infocoin的時候,她給這個新的消息簽名「我Alice要給Bob一個序列號為1234567的infocoin」。但是Bob不只接受這個infocoin,而且他去聯繫銀行,確認兩件事,第一,序列號為1234567的infocoin確實是屬於Alice的。第二,Alice還沒有花掉那個infocoin。然後銀行更新它的記錄來顯示那個infocoin現在是屬於Bob而不是Alice。
讓每個人都成為銀行
上面的這個解決方法看起來很有潛力。但是,我們可以做到更有野心的事。我們可以從這個協議里剔除掉銀行。這樣大幅的改變了這個貨幣的本身屬性。這意味著將不會有一個單獨的組織負責這個貨幣。當你想中央銀行擁有著多麼大權利的時候(控制貨幣發行)——這意味著巨大的改變。
方法是讓每個人共同合作成為銀行。尤其是,我們假設每個用infocoin的人保存一份完整的記錄,這個記錄包括哪個infocoin屬於哪個人。你可以把它想像成一個共享的公開的賬本,這個賬本記錄著所有的infocoin的交易記錄。我們就將它叫做「區塊鏈 blockchain」,因為比特幣裡面就是這麼叫的。
現在,我們假設Alice要將一個infocoin給Bob。她在消息「我Alice要給Bob一個序列號為1234567的infocoin」上簽名。並且將簽了名的消息輸出結果給Bob,Bob可以用他自己的那份block chain去檢驗,「OK,確實那個infocoin是Alice給我的」。如果他檢查沒問題,他就將Alice的消息和自己接受這個infocoin的消息公布給全網路。然後所有的人更新他們的blockchain。
我們仍然存在「序列號從哪裡來」的問題,但是這件事其實很容易解決,所以我推後再解釋。更加難的問題是這個協議允許Alice重複的花費她的infocoin。她可以發布一個簽了名的消息「我Alice要給Bob一個序列號為1234567的infocoin」 ,同時她也可以發布一個簽名的消息說「我Alice要給Charlie一個序列號為1234567的infocoin」。Bob和Charlie兩個人都用他們自己的blockchain去檢驗那個infocoin確實是Alice發過來的。假設他們在同一時間進行的檢驗(在他們兩個互相知道另一個的消息之前),他們兩個都會發現,是的,我的blockchain證明那個幣是屬於Alice。所以他們都接受了那個交易,並且公布他們的接受信息給整個網路。現在就有問題了。網路上其他的人應該怎樣更新他們的blockchain呢?這樣看來貌似不能簡單的達到統一交易賬本。而且即使每個人都同意用一樣的辦法更新他們的blockchain,Bob和Charlie兩個人之間有一個是肯定被騙了。
我們把這個問題叫做「雙重花費 double spending」(後文稱「雙花」), 一眼看來,這樣的雙花似乎很難成功。畢竟,如果Alice先將消息發給Bob,然後Bob將消息發送給其他所有人(包括Charlie),其他人更新了他們的blockchain。這時候,Charlie就不會被Alice騙了。所以似乎雙重花費只有在短暫的一段時間內可能。然而,即使這個時間很短,有這個問題也是不可取的。更糟的是,Alice可以用一些技巧讓這一段時間按延長。比如說她可以用網路分析軟體找到Bob和Charlie之間的交流的延遲時間很長的時候。或者可以做一些事情故意打擾他們之間的網路連接。如果她可以減慢這個交流一點點,就可以使得她的雙花成功變得容易許多。
那怎麼解決這個問題呢?最簡單的辦法是當Alice給Bob發送infocoin的時候,Bob不應該獨自的檢驗這個交易。而他應該將這個可待定的交易公布到整個infocoin網路里,讓其他人幫忙判斷這個交易是否合理。如果他們共同決定這個交易是合理的,那麼Bob可以去接受這個infocoin,然後所有人更新他們的blockchain。這種類協議可以防止雙花,因為如果Alice想要同時給Bob和Charlie發送同樣的infocoin時,網路上的其他人會注意到,並且告訴Bob和Charlie這個交易有問題,然後這個交易就不允許通過。
更具體的來說,假設Alice想要給Bob一個infocoin。和之前一樣,她給一個消息簽名,「我Alice要給Bob一個序列號為1234567的infocoin」,並將簽好名的消息給Bob。也和之前一樣,Bob用他自己的blockchain做一個檢查,這個幣確實屬於Alice。但是協議不一樣了,Bob並不直接接受這個,而是公布Alice的消息給整個網路。網路上的其他成員檢查Alice是否擁有這個infocoin,如果是,那麼他們公布消息說「沒錯,Alice確實有infocoin 1234567, 現在可以將其轉給Bob了」。一旦有足夠的人公布這個消息,每個人更新他的blockchain來顯示infocoin 1234567現在屬於Bob,交易完成。
這個協議現在還有很多不確定的因素。比如,「一旦有足夠的人公布這個消息」到底是什麼意思,多少個人算是足夠?不可能是整個infocoin網路,因為我們事先不知道誰在infocoin網路上。同樣,也不能是固定的一部分用戶。我們現在先不著急將這些問題弄清楚。在這裡,我將要指出一個這交易個方案的嚴重的問題,解決那個問題將會同時幫助上面的問題弄清楚。
工作證明 Proof-of-work
假設Alice想要在上述的協議中雙花,他需要掌管整個的infocoin網路。假設她用一個自動的系統在infocoin網路上建立很多個不同身份的賬戶,假設有10億個。和之前一樣,她試圖進行雙花,將同樣的infocoin給Bob和Charlie,但是當Bob和Charlie詢問infocoin網路的來檢驗這個交易時,Alice的馬甲們淹沒整個網路,告訴Bob和Charlie他們可以通過這個交易,並且可能欺騙他們其中一個或者兩個人都接受這個交易。
有一個聰明的辦法,用一個叫做「工作證明Proof-of-work」的方法。方法並不直觀,需要結合兩個概念,1)人工的讓檢驗交易的過程花費較大的計算開銷;2)獎賞他們幫忙檢驗這個交易。用獎賞的辦法激勵在該網路上的人去驗證交易。加大交易驗證開銷的優點是驗證不會再被那些擁有很多賬戶的人控制,而是只會被他能提供的總共計算能力控制。我們將會看到,通過一些聰明的設計,我們可以讓欺騙者必須花費非常大的計算資源來達到欺騙的目的,讓它變的不切實際。
這就是工作證明的要點。但是要真正弄明白工作證明,我們需要深入更加具體的細節。
假設Alice給整個網路公布消息「我Alice要給Bob一個序列號為1234567的infocoin」。當網路上的其他人聽到這個消息後,每個人將其加入到一列待定的交易之中,這些交易都還沒有被整個網路通過。比如說網路上一個叫做David的人可能有下面這一列待定的交易:
我Tom要給Sue一個序列號為1201174的infocoin。
我Sydney要給Cynthia一個序列號為1295618的infocoin。
我Alice要給Bob一個序列號為1234567的infocoin。
David檢查他自己的blockchain,看到上述這些交易是合理的。他要幫助將這個驗證消息公布到整個網路中去。但是,在這之前,檢驗交易協議需要David去解決一個計算難題——也就是工作證明。若他沒有得到難題的解,網路上的其他成員不會接受他的驗證。
那麼David到底要解決一個什麼的難題呢?要解釋這個,我們用一個網路上面每個人都知道的固定的哈希函數hash function——將其包括在協議本身。比特幣用一個眾所周知的SHA-256哈希函數,但是任何密碼學的哈希函數在這裡都可以用。我們給David的這一組待定的交易一個標記,」L」吧,為了之後可以引用。這一組待定的交易也就相當於blockchain裡面的block(區塊)(-理解這個Block很重要,block也就是一組交易信息組成的集合,一個block包括很多個交易)。假設David在這個區塊」L」後添加一個數字x(叫做nonce,暫時的隨機數)然後hash他們的結合。比方說,我們用L=「Hello, world!」 作為一些交易的標記。然後加上一個暫時的隨機數,我們從「x=0」開始吧。
h("hello", world! 0) =n
1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64n
David將要解決的問題(工作證明)是找到一個隨機數x,當我們將這個x添加到L後面並且hash這個組合的時候,得到的結果開始為幾個0開頭。這個難題的難度可以通過調整開頭零的個數來調節。一個簡單的」工作證明」只需要3或4個零開頭的hash,一個難的「工作證明」則可能需要更多的零開頭,比如說15個連續的零。在上述情況下,x=0的到的hash結果不成功,因為結果不是由0開始的。那麼我們就嘗試x=1,
可以看到x=1的時候也不成立
h("Hello, world!1") = n e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8n
然後嘗試x=2, 然後x=3 ,4,5…. 知道最後,發現x=4350的時候,我們得到了
h("Hello, world!4250") = n 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9n
這個隨機數x給了我們一個結果是四個零開頭的hash。這個就足夠解決一個簡單的「工作證明」的難題了。
讓這個難題不容易解決的是其密碼哈希函數結果永遠是隨機的,對輸入值做任何細小的改變將會完全該別整個哈希函數的輸出結果,以至於很難去預測。所以如果我們需要輸出結果必須是開始於10個0,那麼David將平均需要 1610 ≈ 1012 個不同的x才能找到那個合適的值。這是一個非常有挑戰性的任務,需要很多的計算能力。
顯然,我們可以通過規定需要零的多少來控制工作證明難題的難易程度。事實上,比特幣協議通過對上述的工作證明稍加修改,可以對難題的難易程度有更良好的控制。不再是規定需要多少個開始的零,而是規定block的hash輸出結果要小於或等於一個目標值,這個目標值是自動調節的,用來保證比特幣的每一個區塊(block)平均要花10分鐘來解。
好了,我們假設David很幸運,找到了一個合適的x(nonce),恭喜他!(他將會得到找到這個答案的獎賞)。他會公布他已經證明了這個區塊裡面的交易是合理的,並且與之同時公布她找到的x值,其他infocoin里的參與者可以證明x那個工作證明的有效解。然後他們就更新自己的blockchain,來包括David所公布的這些交易。
為了讓工作證明這個方案的運作,網路的參與者應該需要一個激勵機制來幫助驗證交易。沒有激勵機制的話,沒有人會願意花費自己的計算機算力來幫助檢驗交易。如果網路參與者不願意花費算力,那麼整個系統就不會運轉。因此,我們可以通過給他們一些infocoin的方式來獎勵任何成功驗證了交易的人。若給他們提供的infocoin獎勵足夠的多,可以激勵他們來參與驗證。
在比特幣的協議里,這個驗證的過程被稱作「mining」 (挖礦)。每一個交易區塊的驗證成功者都會獲得比特幣作為獎勵。最開始的時候,是50個比特幣的獎勵。但是每格21萬個驗證的區塊(也就是大概每4年左右),獎勵會減半。現在為止只發生了一次,也就是說現在驗證一個block獲得的獎勵是25個比特幣。 減半的過程會持續發生,直到大概2140年。那時候,挖礦的獎勵的將會降低到10-8個比特幣。而10-8個比特幣是比特幣最小的單位(被稱作一個Satoshi),因此到2140年,總共的比特幣將會停止增長。然而,這並不會消除驗證交易的激勵機制,比特幣可以允許參與者加入驗證交易的費用,用來獎賞驗證交易的人。早期的比特幣,交易費幾乎為零,但是隨著比特幣的普及,交易費會逐漸升高,現在已經成為除了25個比特幣獎勵之外的額外激勵了。
你可以將工作證明(proof-of-work)看做一個競相驗證交易的過程。每個參與者會花費一部分的計算機算力。一個挖礦者獲勝的機會大概等於他們控制的計算計算力的大小和整個網路的算力的比例。比如說,一個挖礦者控制著整個網路算力量百分之一的計算能力,那麼他的獲勝的概率也大概是百分之一。所以提供大量計算能力是支撐競爭能力的因素,一個不誠實的挖礦者只有很小的機會去破壞驗證過程,除非他們花費巨大的計算機資源。
當然,就算是不誠實的挖礦者僅有很小的機會破壞整個blockchain,我們也沒有足夠的信心拿它來當成貨幣。特別是,我們還沒有最終解決雙花的問題。
我會馬上分析雙花的問題,但是在那之前,我想在Infocoin的概念里補充一個重要的細節。理想情況下,我們希望Infocoin網路能夠統一交易發生的順序。如果我們沒有統一的順序,那麼誰在哪個特定的時候有哪個infocoin就不是很清楚了。為了幫著解決這一點。我們要求新的區塊(block)必須要包含指向上一個區塊的指針,這個指針也其實就是上一個block的哈希(hash)結果。因此,基本上說,區塊鏈 (block chain)本身也就是一個線性的一串包含著交易信息的區塊(blocks),一個接著一個,每一個block都包含著指向上一個block的指針。
偶然情況下,一個blockchain上會產生分支。這種情況是因為,有時候兩個挖礦者幾乎同時驗證出來一個區塊的交易。他們同時公布到網路里,有些人用一個方法更新他們的blockchain,另一些人用另外一個方法更新他們的blockchain。
這就造成了我們想要避免的情況 ——這種情況,交易的順序就不清楚了,而且誰有哪個infocoin也就不清楚了。幸運的是,有一個簡單的辦法可以用來挪去分支。規則是這樣的:如果分支情況出現,那麼網路上的人們繼續保持兩個分支,任何情況下,挖礦者只在最長的那個blockchain上工作。
假設我們有一個分支,有一些挖礦者先收到block A,另一些挖礦者先收到的是block B。那些收到block A的挖礦者將要繼續沿著他們的分支挖礦,而其他人沿著Block B的分支挖礦。我們假設在B分支上的挖礦者先成功挖到下一個block:
當他們收到這個消息後,在A分支的人會注意到現在B分支是最長的,於是就會轉換到B的分支。在A分支上的工作就會迅速的停止,這樣每個人就會都在同一個順序的blockchain上工作了。然後block A就會被忽略。當然,所有在block A裡面的待定交易將會繼續保持待定狀態,隨後會在B分支上被放到新的block里,這樣,所有的交易最終還是會被驗證的。
同理,如果在分支A上的挖礦者先挖到下一個block,那麼在B分支上工作的人就是停止,轉到A分支上。
不論結果是什麼,這個過程保證了blockchain有統一的順序。在比特幣中,一個交易能不算作確認直到 1)它存在於最長的分支中的block里,2)至少有5個驗證過的block在其後面得到驗證。這種情況,我們說這個交易有了「6個確認」。這給了整個網路時間去統一block的順序。我們在Infocoin里,也用同樣的方案。
現在我們理解了時間順序,那我們回去想想如果一個不誠實的人想要雙重花費的話會怎麼樣。假設Alice要同時給Bob和Charlie同樣的交易。一個可能性就是讓她去驗證同時帶有兩個交易的一個block。假設她擁有百分之一的計算能力,那麼她有可能比較幸運的驗證出了這一個block。不幸的是,這個雙重花費將會馬上被其他人發現並且拒絕,儘管她解決了工作證明裡的難題。所以這個可能性我們不用擔心。
但是另一種可能性是,她試圖分別公布兩個交易。她可能給一部分挖礦者公布一個交易,給另一部分挖礦者公布另一個交易,她希望讓兩個交易都得到驗證。幸運的是,這種情況下,如我們剛才所說,網路最終只會確認其中一個交易。所以,這個也不是問題。
還有一種可能是,Alice = Bob,也就是說Alice試圖將一個幣給Charlie,同時她又將那個幣給她自己,因為她自己可以有多個賬戶。這種情況下,Alice的策略是等到Charlie接受了這個Infocoin,也就是大概在交易在最長的blockchain中被確認6次之後。她再試圖去解決另外一個擁有她發給自己的交易的那個block分支。
可惜的是,這個時候Alice已經比最長的blockchain晚了6步。她很難在跟得上最長的分支了。其他的挖礦者不會幫助她,因為他們都需要在最長的分支上工作才能得到獎賞。除非Alice在解決工作證明的時候能夠比網路上其他人結合起來還快(也就是說她大概有多於整個網路50%的計算能力)。當然,她可能會偶然幸運,在百分之一的算力的情況下能解決一個block,但是同時趕上6個的花相當於是 1/1006 = 10-12 。這種情況可以說是想到於零。
當然這不是非常嚴格的說Alice肯定不能雙花了。這只是一個合理的推論。比特幣的白皮書原文並沒有進行一個嚴格的安全分析,只是和我這裡類似的非正式推論。安全團體任然在分析比特幣的安全性和潛在的缺陷,具體可以看這個列表。
推薦閱讀:
※覃超的知乎Live(第二場)- 如何更好地申請到北美計算機學校和留美工作
※靠譜的代碼和DRY (圖片是GacUI)
※現在有很多做網站的站長,做網站怎麼贏利呢?
※他們也在用北郵人導航
TAG:比特币Bitcoin | 区块链Blockchain | 互联网 |