維持人群賬本的一致
接下來我們看如何使分散在世界各地的計(jì)算機(jī)節(jié)點(diǎn)維持賬戶余額保持一致苍苞。
回到最開始的理想模型钻趋,大家的記賬過程是這樣的:
- 在最開始劳殖,每人手里都拿著一個空的賬本;
- 然后在賬本的第一行裳食,大家都記錄A存了10塊進(jìn)來
- 在賬本的第二行,大家又都記錄A給B轉(zhuǎn)了3塊
- 第三行线椰,大家又都記錄C存了8塊
- .....
- 在第4323行胞谈,大家又都記錄W給K轉(zhuǎn)了8塊
- ....
也就是說,從一個空的賬本開始憨愉,在每一筆交易產(chǎn)生的時候烦绳,大家都同時把交易追加到自己的賬本的同一行上。如果這種行為可以一直維持下來配紫,那么每個人余額是多少径密,以及誰給誰轉(zhuǎn)了多少錢,自然會一直保持一致躺孝。
這種做法有點(diǎn)像我們小時候被老師聽寫生字:
- 老師讀一個字享扔,我們在本子上寫一個字;
- 老師問我們有沒有寫完植袍,我們齊聲確認(rèn)惧眠,然后下一個字
- 最后聽寫完成后,每個人交上去的結(jié)果都一模一樣于个。
在最開始我們也分析過氛魁,這種“聽寫”的模式是無法適用于計(jì)算機(jī)世界的,這里再次重溫下原因:
- 不存在真正意義的廣播和確認(rèn)。我們并沒有一個集中暢通的信道秀存,可以讓“老師讀字給我們聽”捶码。計(jì)算機(jī)網(wǎng)絡(luò)中的廣播,都是節(jié)點(diǎn)發(fā)送者把消息傳給周圍的節(jié)點(diǎn)或链,然后再一傳十惫恼、十傳百,從而傳遍網(wǎng)絡(luò)中的所有節(jié)點(diǎn)澳盐。
- 消息的傳播過程中祈纯,可能會有丟失、亂序洞就、偽造盆繁、否認(rèn)等。
- 消息的產(chǎn)生源頭不僅僅是“老師”一個人旬蟋,因?yàn)橥粫r刻可能會有很多人發(fā)起交易油昂。在這樣的情況下,讓所有交易記錄都保持一樣的順序更是困難:因?yàn)榭赡芤徊糠止?jié)點(diǎn)先聽到消息1,另一部分先聽到消息2倾贰。
如果非要用“教室課堂”的模式類比冕碟,比特幣系統(tǒng)有點(diǎn)像一場奇怪的聽力考試:
- 最開始,老師給每個人發(fā)了一個空的筆記本匆浙;
- 每個人都帶著一個耳機(jī)安寺,考試開始后涯曲,耳機(jī)里開始播放單詞增显。大家的單詞可能相同,也可能不同什往,也可能有人的耳機(jī)里根本不播放單詞软能。
- 每個人聽到單詞后迎捺,把單詞記追加到筆記本的空白行上,并且可以把它寫成小紙條傳給別人查排。
- 收到小紙條的人凳枝,可以選擇抄寫并繼續(xù)傳遞這張紙條,或者無視跋核。
- 在考試結(jié)束后岖瑰,老師會把筆記本收走。
-
最后的計(jì)分規(guī)則是這樣的:從第一行開始砂代,如果該行的單詞內(nèi)容在每個人本子上都一模一樣蹋订,那大家都加一分;直到遇到某行的單詞有沖突了刻伊,計(jì)分結(jié)束露戒。
如果我們深入去思考這場“詭異的考試”难礼,一定就會為它難到“急火攻心”。乍一想玫锋,我們也許可以指定某個人是單詞唯一的來源,但我們很難保證他的耳機(jī)里會一直放單詞讼呢。為保險起見撩鹿,還是每個人都可記錄并傳播單詞,并且找一些規(guī)則來維持筆記本內(nèi)容的一致為妙悦屏。
那么我們就需要靜下心來想想节沦,阻止我們就“筆記本內(nèi)容達(dá)成一致”的最大阻礙是什么?主要原因在于:同時產(chǎn)生并傳來傳去的單詞太多了础爬,大家不管記自己的甫贯,還是抄別人的紙條,都會有一種手忙腳亂的感覺看蚜。如果每個時間段內(nèi)只有一個單詞產(chǎn)生叫搁,那么大家記起來就容易多了。
換句話說:只有降低單詞產(chǎn)生的速度供炎,才更有可能讓大家達(dá)成一致渴逻。為了達(dá)到這一目標(biāo),我們可以在考試系統(tǒng)中先引入規(guī)則一:
-
在聽到單詞并傳遞紙條之前音诫,先讓大家在桌上玩一把擲骰子惨奕。成功擲到三個六的人,才允許他傳紙條
道理也很簡單:雖然大家都可以快速記下單詞梨撞,但運(yùn)氣總不會一樣好。在擲骰子的約束之下香罐,單詞的產(chǎn)生速度會瞬間慢下來卧波。最理想的情況:
- 第一行,某個人成功擲出穴吹,然后答案傳遍班級幽勒;
- 第二行,另一個人擲出三個六港令,答案又傳遍班級……
- 最后每一行的單詞都一樣啥容。
可這么做有個很明顯的問題:記單詞的速度太慢了,最后會影響總分的顷霹。為了解決這個問題咪惠,我們引入規(guī)則二:
- 學(xué)生每寫完一頁后,才開始擲骰子淋淀,相應(yīng)的遥昧,紙條傳播的是一整頁的單詞。在這種情況下,大家開始就“某一頁內(nèi)容是什么”尋求一致炭臭。
那么收到別人的整頁單詞后永脓,紙條的接受者該怎么做呢?我們引入規(guī)則三:
- 停下手頭的記單詞或者擲骰子工作鞋仍,驗(yàn)證別人單詞的正確性常摧。如果全部正確,就把它抄到最后一頁上威创;同時落午,傳播這一頁。自己則進(jìn)入下一頁的“記單詞-擲骰子”環(huán)節(jié)肚豺。
- 如果紙條上有錯誤單詞溃斋,就忽略掉,繼續(xù)自己的工作
有了三這個規(guī)則吸申,我們可以在腦子里過一下整個考試的過程:
- 大家開始寫第一頁梗劫,有人第一頁寫完了,比別人都先擲到了骰子呛谜,然后這頁傳遍了整個班在跳;
- 然后都開始第二頁....
好,假設(shè)這樣的方法是奏效的隐岛。但不可避免的猫妙,到某一頁的時候,突然A和B兩個人先后都擲出了六聚凹,也都開始傳播自己的該頁內(nèi)容割坠。很快的,這兩份答案蔓延到了班級的每一個同學(xué)手中妒牙。此時彼哼,大家要么有A的那一份,要么有B的那一份湘今,要么兩份都有敢朱,分歧產(chǎn)生了。
在這種情況下摩瞎,我們需要引入接收者對答案驗(yàn)證的規(guī)則四:
- 先到先得:如果別人傳過來一頁內(nèi)容拴签,但這頁自己已經(jīng)完成了(自己答的,或者抄別人的都可以)旗们,就無視后來的這份
在這一規(guī)則下蚓哩,每個人手上的答案不會有兩份答案。無論是A的那份還是B的那份上渴,誰的先到他們手上他們就選誰的岸梨。
有了這一規(guī)則喜颁,盡管每個人不會擁有多份答案,但就整個集體而言曹阔,兩個幫派還是不可避免的形成了半开。他們就“最近一頁內(nèi)容是什么”這一問題而相持不下。
為了避免這一局面赃份,我們需要再次引入一個新的規(guī)則稿茉。
在介紹下一個規(guī)則之前,我們先擱置爭議芥炭,用發(fā)展的眼光來繼續(xù)審視下這場考試。盡管幫派已經(jīng)產(chǎn)生恃慧,但班級里的每個成員仍在繼續(xù)熱火朝天的進(jìn)行著“寫單詞-擲骰子”過程园蝠。在某個時間點(diǎn),又有新的一頁產(chǎn)生了痢士,這頁內(nèi)容也會和任何其他頁一樣彪薛,迅速在班里擴(kuò)散開來。當(dāng)這頁擴(kuò)散到另一個幫派時怠蹂,我們的規(guī)則五就會起作用了:
-
內(nèi)容多的勝出:如果別人傳過來的頁號比我的大善延,我就按規(guī)則3來驗(yàn)證、傳播他的內(nèi)容城侧。同時易遣,為了防止它前面的內(nèi)容和我記錄的不一樣,我會核對這頁之前的所有內(nèi)容嫌佑,把不一樣的內(nèi)容全換成他的
規(guī)則五其實(shí)給傳紙條悄悄引入了一個新的約束:大家在傳播紙條時豆茫,傳播的根本不是某一頁內(nèi)容,而是一整個筆記本屋摇。因?yàn)椴粋鞑フ麄€筆記本揩魂,沒法對前面的內(nèi)容進(jìn)行對比。
當(dāng)然炮温,這樣的傳答案方式在你看來可能極其搞笑:把別人的一整本筆記抄下來傳紙條似乎會慢的可憐火脉,對整本筆記逐行對比時也算苦逼到家了。這兩個問題并非不可以解決柒啤,我們后面會再次回過頭來看這個問題倦挂。這里,就讓我們暫時無腦的假設(shè)“傳整本筆記”是可行的白修。而且妒峦,我們也可以“鴕鳥心態(tài)”的更徹底一些:
- 假設(shè)我們有無限多的筆記本,可以很快的把手頭的筆記復(fù)制好多份出來兵睛。同時肯骇,給別人扔起筆記來也是又快又容易
- 逐條內(nèi)容檢驗(yàn)也不是什么難事
有了規(guī)則五之后窥浪,即便班級里暫時分成了兩個幫派,也不再是一件非常頭疼的事了笛丙。所有的分歧都是暫時的漾脂、不穩(wěn)定的。隨著筆記頁數(shù)的持續(xù)推進(jìn)胚鸯,一定會有一方產(chǎn)生比別人都新的答案骨稿,這份更多的答案會在傳播中慢慢把別的幫派吞并掉,最后整個班級歸于一致姜钳。再朝深一步想就是:在最近一頁或幾頁的內(nèi)容上大家可能會有不一致坦冠,但一些比較靠前的頁面,大家基本上是會保持一致的哥桥。
如果把上面“考試答題”的過程映射回比特幣系統(tǒng)辙浑,我們大體就可以知道比特幣維持系統(tǒng)一致的雛形方法了。
- “記單詞”的過程就是計(jì)算機(jī)節(jié)點(diǎn)記賬的過程:
- 一行單詞對應(yīng)一條交易, 一頁單詞對應(yīng)一個“區(qū)塊”拟糕。
- 為了降低一頁的沖突判呕,需要每個同學(xué)執(zhí)行擲骰子的過程。相應(yīng)的送滞,為了降低各個節(jié)點(diǎn)的區(qū)塊沖突侠草,每個節(jié)點(diǎn)在組織好一個區(qū)塊后,隨機(jī)等待一段時間
- 傳播的不是一頁試題犁嗅,而是一整個筆記本边涕,內(nèi)容多的筆記勝出。對應(yīng)的褂微,所有的區(qū)塊內(nèi)容也都前后關(guān)聯(lián)形成一個整體奥吩。系統(tǒng)中可能會同時存在多個這樣的區(qū)塊集,在區(qū)塊集相互傳播的時候蕊梧,少的內(nèi)容會被多的覆蓋掉霞赫。最后大家會就最多的內(nèi)容達(dá)成一致。
區(qū)塊鏈
在前面介紹“頁數(shù)多的勝出”這一規(guī)則時肥矢,為了保證其有效實(shí)施端衰,我們要求班級學(xué)生在傳播答案的時候,要傳播“整個筆記本”甘改。之所以要這么做旅东,是為了大家在接受最大的頁面內(nèi)容時,可以檢驗(yàn)并維持前面內(nèi)容的一致十艾。
還拿100頁的例子說事抵代。假如僅僅只傳遞新生成的第101頁,收到該的人無法驗(yàn)證“自己的第100頁”和“收到的101頁的前一頁”內(nèi)容是不是一樣忘嫉;同理荤牍,也無從驗(yàn)證“自己的第99頁”和“收到的101頁的前兩頁”的內(nèi)容是不是一樣案腺;依次類推,前面的每一頁也無從驗(yàn)證康吵。而傳播“整個筆記本”劈榨,從物理上保證了全部內(nèi)容的連貫完整性,從而也給了內(nèi)容驗(yàn)證以強(qiáng)有力的保證晦嵌。
那么同辣,我們能不能找到一種更快速有效的方式來進(jìn)行筆記本內(nèi)容的驗(yàn)證呢?
答案是可以的:只要我們能對班級中產(chǎn)生的每一頁單詞筆記進(jìn)行唯一的編號就可以了惭载。我們在描述一頁的時候旱函,不能僅僅說“第x頁”,而是應(yīng)該說“xxx產(chǎn)生的第xxx頁”描滔。更精確一點(diǎn)陡舅,如果用“學(xué)號+頁號”的方式來編碼,我們就可以避免傳播整個筆記內(nèi)容了伴挚。
例如,當(dāng)X產(chǎn)生出第101頁時灾炭,或者他收到別人新發(fā)來的第101頁時茎芋,他只需把這一頁的完整內(nèi)容抄成紙條傳播即可;而對于所有的前序頁蜈出,他只傳播頁的編號即可田弥。
W在收到X的紙條后,如果自己的內(nèi)容不少于101頁:
- 根據(jù)“先到先得”的規(guī)則铡原,他自然會選擇無視X的紙條偷厦;
- 如若不然,他就會開始把自己頁面的編號和X傳過來的編號燕刻,從后向前進(jìn)行逐頁對比只泼,并且丟棄掉自己不一致的部分;同時卵洗,他也會請求X(或者其他人)把對應(yīng)頁號的完整內(nèi)容發(fā)送一下请唱,以補(bǔ)上自己丟掉的內(nèi)容。
值得強(qiáng)調(diào)的是过蹂,W和X頁面不一致的地方十绑,一定是發(fā)生在W的尾部的。也就是說酷勺,兩人的頁面內(nèi)容本橙,一定是從某一頁開始“分叉”的;交錯式的不一致脆诉,在我們的協(xié)議里一定式不會發(fā)生的甚亭。這里我不打算對原因展開做解釋贷币,有興趣的讀者可以自己想一下原因。
有了“頁面編號”的概念后狂鞋,我們的紙條傳播規(guī)則可以再進(jìn)一步的簡化:每次只傳播新產(chǎn)生的一頁片择,并且把它的前序頁也一起寫到該頁的紙條中去。也就是說骚揍,每一頁紙條的格式是這樣的:
接收者只需要按照頁面前一頁組成的鏈條“順藤摸瓜”解決沖突就好了字管。
在比特幣中,每個“區(qū)塊”都會記錄其前一區(qū)塊的編號信不,從而使得系統(tǒng)中所有的區(qū)塊都串到某一條固定的鏈上嘲叔,就像一個完整的筆記本一樣。這樣的鏈就叫做區(qū)塊鏈抽活。每個記賬人手中的賬目硫戈,就可以對應(yīng)到系統(tǒng)中的某一條鏈中∠滤叮“最長的鏈”丁逝,就是維持大家賬目一致的核心秘密。
有了這個概念后梭姓,我們就可以回答下“A給B轉(zhuǎn)賬霜幼,B如何確認(rèn)收到”的問題了。B無需向系統(tǒng)中的每個節(jié)點(diǎn)進(jìn)行詢問(事實(shí)上誉尖,B也做不到向每個節(jié)點(diǎn)詢問)罪既,他只要耐心的等待A向他發(fā)起的那筆交易被串在鏈中比較靠前的地方就好了。在比特幣中铡恕,如果一個區(qū)塊后面又接了五六個區(qū)塊琢感,就可以確認(rèn)交易了。
數(shù)字摘要
在上一節(jié)中探熔,我們給“考試模型”中的每頁紙條引入了一個非常重要的概念:唯一的頁編號驹针,也給了“學(xué)號+頁碼”這樣一個簡單的編號規(guī)則。在比特幣系統(tǒng)中诀艰,每個區(qū)塊也的確有個“唯一編號”牌捷,但是其編號規(guī)則卻大不相同——其規(guī)則叫“數(shù)字摘要”。
所謂“數(shù)字摘要(也叫數(shù)字指紋涡驮、密碼學(xué)哈希)”暗甥,是這樣一種技術(shù):它可以把給定的普通的電腦文件快速轉(zhuǎn)化成一段固定長度的數(shù)字串(嚴(yán)格來說:是16進(jìn)制數(shù)字串),這個數(shù)字串就叫做原來文件的數(shù)字摘要捉捅。并且撤防,這種數(shù)字串滿足三種性質(zhì):
- 無論兩個文件內(nèi)容多么相似,他們生成的數(shù)字摘要也是大不相同的棒口。而如果兩個文件完全相同寄月,那么他們的數(shù)字摘要也一模一樣辜膝。這種特征保證了:一旦一個文件發(fā)生了極微小的改動,我們也能通過其摘要快速發(fā)現(xiàn)漾肮。而不用把源文件的內(nèi)容進(jìn)行完整比對厂抖。
- 對于一個給定的文件,你想創(chuàng)造一個新的文件和它有相同的數(shù)字摘要克懊,是非常困難的忱辅。這種特征保證了:你無法隨意偽造一個新的文件來把原來的替換掉。
- 你難以構(gòu)造兩個文件谭溉,使得他們有相同的數(shù)字摘要墙懂。這種特征保證了:如果你在一個系統(tǒng)中持續(xù)的產(chǎn)生新的文件,你可以通過摘要這種技術(shù)給不同的文件進(jìn)行“編號”扮念。
數(shù)字摘要的這些性質(zhì)损搬,就跟我們的指紋一樣,是我們每個文件獨(dú)一無二特質(zhì)的一種證明柜与。如果用人的觀點(diǎn)來看這三種性質(zhì)就是:
- 哪怕你是雙胞胎巧勤,你們的指紋也不相同。
- 你想找一個人和你自己的指紋一樣弄匕,這幾乎是不可能的
- 你想從人群中抓兩個人颅悉,讓他們的指紋一樣,這幾乎也是不可能的粘茄。
在比特幣系統(tǒng)中,區(qū)塊的“唯一編號”就是它全部內(nèi)容的數(shù)字摘要秕脓,而之所以能這么干柒瓣,就是利用性質(zhì)3。
數(shù)字摘要的引入吠架,也給比特幣的賬本帶來了一個有趣的特性:修改鏈上任何一個區(qū)塊的任何內(nèi)容芙贫,必須得順帶將所有后續(xù)區(qū)塊做改正。因?yàn)楦鶕?jù)性質(zhì)1:
- 內(nèi)容的改動帶來摘要的改動
- 摘要的改動傍药,相當(dāng)于是后繼1的內(nèi)容改動磺平,從而后繼1的摘要也得改動
-
從而擴(kuò)展到后繼2,直到最后一個區(qū)塊
所以拐辽,記賬人想改了某條賬本且仍舊想維護(hù)賬本的有效性的話拣挪,必須得將所有后繼都做一遍改動。現(xiàn)在請大家默默記住這一平平無奇的特性俱诸。待后面引入其他一些規(guī)則后菠劝,該特性將成為比特幣系統(tǒng)堅(jiān)不可摧的最重要基石。
簡單小結(jié)
到此為止睁搭,我們在不考慮“拜占庭問題”的前提下赶诊,構(gòu)建起了保證各節(jié)點(diǎn)賬本一致的基本方法:
- 收到交易時笼平,驗(yàn)證交易的合法性。
- 把多個交易打包成一個區(qū)塊舔痪,擲骰子到合適點(diǎn)數(shù)后再廣播區(qū)塊寓调,從而減少沖突。
- 收到別人發(fā)來的區(qū)塊后锄码,接受合法的區(qū)塊夺英,且繼續(xù)廣播,加速區(qū)塊在系統(tǒng)中的傳播巍耗。
- 對于相同深度的區(qū)塊秋麸,只接受最先到達(dá)的。
- 當(dāng)接受一個深度更大的區(qū)塊時炬太,順藤摸瓜地檢測前序區(qū)塊灸蟆,產(chǎn)生沖突時丟棄自己那份
- 為了支持5,每個區(qū)塊用數(shù)字摘要來給區(qū)塊編號亲族,且在每個內(nèi)部記錄自己的前序區(qū)塊