Hash算法是區(qū)塊鏈中最核心的算法贩挣,在了解區(qū)塊鏈前我們必須先了解關(guān)于Hash算法的一些基本概念喉前。
2.1 Hash的種類:
Hash算法有很多種,其中有MD5王财、SHA卵迂,而SHA算法又分為SHA-1、SHA-224绒净、SHA-256见咒、SHA-384和SHA-512五種變體,區(qū)塊鏈中用到的是SHA256挂疆,,所以我們在這里會重點(diǎn)關(guān)注改览,后面會講到。
2.2缤言、Hash算法的特點(diǎn):
1宝当、輸入任意長度的字符串(x)可以得到長度固定的結(jié)果(H(x)),例如使用MD5算法:
MD5("version1") = "966634ebf2fc135707d6753692bf4b1e";
MD5("version2") = "2e0e95285f08a07dea17e7ee111b21c8";
2、輸入敏感胆萧,輸入數(shù)據(jù)的稍微改變就會引起Hash運(yùn)算結(jié)果的面目全非庆揩,上面的例子中“version1”和“version2”僅僅是最后一位“1”和“2”的區(qū)別,得出來的結(jié)果卻截然不同。
3订晌、免碰撞虏辫,即不會出現(xiàn)輸入x≠y但是H(x) = H(y)的情況,也就是強(qiáng)抗沖突性锈拨。
4砌庄、原像不可逆,通俗地說推励,指的是知道輸入值鹤耍,很容易通過哈希函數(shù)計算出哈希值;但知道哈希值验辞,沒有辦法計算出原來的輸入值稿黄。也就是說,對于一個給定的輸出哈希結(jié)果H(x)跌造,想要逆推出輸入x杆怕,在計算上是不可能的,比如上面將“version1”的字符串經(jīng)過MD5算法得出"966634ebf2fc135707d6753692bf4b1e"壳贪,但是沒有方法在知道輸出值"966634ebf2fc135707d6753692bf4b1e"的情況下陵珍,反推出原始值是“version1”。
4)難題友好性违施,不存在比窮舉更好的方法互纯,以使哈希結(jié)果H(x)落在特定的范圍,換一種說法就是磕蒲,沒有便捷的方法去產(chǎn)生一滿足特殊要求的哈希值留潦。
哈希函數(shù)的難題友好性構(gòu)成了基于工作量證明的共識算法的基礎(chǔ),例如辣往,給定字符串“blockchain”兔院,并在這個字符串后面連接一個整數(shù)值串x,對連接后的字符串進(jìn)行SHA256哈希運(yùn)算站削,要求得到的哈希結(jié)果(以十六進(jìn)制的形式表示)以若干個0開頭的坊萝。按照這個規(guī)則,由x=1出發(fā)许起,遞增x的值十偶,我們需要經(jīng)過2688次哈希計算才能找到前3位均為0的哈希值,而要找到前6位均為0的哈希值园细,則需進(jìn)行620969次哈希計算扯键。也就是說,沒有更快捷的方法來產(chǎn)生一個滿足要求的哈希結(jié)果珊肃。
2.3荣刑、SHA-256算法
SHA-256屬于Hash算法中的一種馅笙,由美國國家安全局研發(fā),又屬于SHA算法的變種之一厉亏,是SHA-1的后繼者董习。
SHA256相對于其他的Hash算法來說,特點(diǎn)是對于任意長度的消息爱只,SHA256都會產(chǎn)生一個256bit長的哈希值皿淋,稱作消息摘要。這個摘要相當(dāng)于是個長度為32個字節(jié)的數(shù)組恬试,通常用一個長度為64的十六進(jìn)制字符串來表示窝趣。
Hash算法作為區(qū)塊鏈中的主要算法對于區(qū)塊鏈來說有著怎樣的意義,和區(qū)塊鏈的工作原理又有什么關(guān)系训柴?
別急哑舒,慢慢往下看。
現(xiàn)在假設(shè)一種場景:
網(wǎng)絡(luò)傳輸數(shù)據(jù)的時候幻馁,A收到B的傳過來的文件洗鸵,需要確認(rèn)收到的文件有沒有損壞。如何解決仗嗦?
最簡單的方法是對整個原始數(shù)據(jù)做Hash運(yùn)算得到固定長度的Hash值膘滨,然后把得到的Hash值公布在網(wǎng)上,這樣用戶從可信的渠道下載到公布的Hash值之后稀拐,對數(shù)據(jù)再次進(jìn)行Hash運(yùn)算火邓,比較運(yùn)算結(jié)果和網(wǎng)上公布的Hash值進(jìn)行比較,如果兩個Hash值相等德撬,說明數(shù)據(jù)在傳輸過程沒有損壞(篡改)铲咨,反之說明數(shù)據(jù)經(jīng)過篡改或損壞。
如果從一個穩(wěn)定的服務(wù)器(可信的渠道)進(jìn)行下載砰逻,采用單一Hash是可取的鸣驱。但如果數(shù)據(jù)源不穩(wěn)定泛鸟,一旦數(shù)據(jù)損壞蝠咆,就需要整個數(shù)據(jù)重新下載,這種下載的效率是很低的北滥。
為了解決這個問題刚操,在P2P網(wǎng)絡(luò)中做數(shù)據(jù)傳輸?shù)臅r候,往往需要把文件拆分很多小的數(shù)據(jù)塊各自傳輸再芋,同時從多個機(jī)器上下載拆分過后不同的小數(shù)據(jù)塊菊霜,這樣的好處是,如果小數(shù)據(jù)塊在傳輸過程中損壞了济赎,那么只要重新下載這一塊數(shù)據(jù)就行了鉴逞,不用重新下載整個文件记某。
但是這么做的話,新的問題又來了构捡,怎么去驗(yàn)證小的數(shù)據(jù)塊有沒有損壞液南?
答案是,下載之前我們會對每個小的數(shù)據(jù)塊分別做Hash運(yùn)算最終得到一個Hash List勾徽。下載的時候滑凉,在下載到真正數(shù)據(jù)之前,我們會先下載這個Hash List喘帚。
同樣的問題畅姊,怎么確定這個Hash List是正確的呢?
有一種辦法是對所有的小數(shù)據(jù)塊進(jìn)行Hash運(yùn)算得到每個小數(shù)據(jù)塊的Hash值然后再用遍歷的辦法與原數(shù)據(jù)塊的Hash值做一一對比吹由,只有hash list中的每一個hash都是正確的若未,我們才會認(rèn)為這個hash list是有效的,嗯溉知,好像是可以陨瘩,但這種方法代價是不是太大呢,正常場景下數(shù)據(jù)量可是相當(dāng)巨大的级乍,這種方法的效率明顯比較低下舌劳。
解決辦法是最開始在生成HashList的時候把每個小塊數(shù)據(jù)的Hash值拼到一起,然后對這個長字符串再做一次Hash運(yùn)算玫荣,這樣就能得到一個最終的hash甚淡,這個最終的Hash值我們稱之為Hash Root(Top Hash)。
這就是Hash算法的作用捅厂,利用了Hash算法中的敏感性贯卦,某一條數(shù)據(jù)中只要有任何一點(diǎn)小的改動,會導(dǎo)致計算出來的Hash List中的某一條Hash值的不同焙贷,而Hash List中的某一條Hash值的不同又會導(dǎo)致最后算出來Hash root與原數(shù)據(jù)的Hash Root有著天差地別撵割,簡單來說,我們只需要一個長度固定的字符串(Hash Root)就能輕易識別任意大小的數(shù)據(jù)是否損壞或者經(jīng)過篡改辙芍,識別成本很低啡彬。
所以,最終處理就是故硅,下載數(shù)據(jù)的時候庶灿,首先確保從可信的數(shù)據(jù)源得到正確的根Hash,用它來校驗(yàn)整個Hash List吃衅,然后通過校驗(yàn)后的Hash List校驗(yàn)整個數(shù)據(jù)塊往踢。
如圖,收件人可以在收到信息后徘层,先比對節(jié)點(diǎn)1的Hash值,若節(jié)點(diǎn)1沒有錯誤則無需進(jìn)行進(jìn)一步的比對峻呕。若發(fā)現(xiàn)節(jié)點(diǎn)1錯誤可以繼續(xù)比對節(jié)點(diǎn)2和3的值利职。發(fā)現(xiàn)節(jié)點(diǎn)3無誤則可以放棄比對節(jié)點(diǎn)6和7. 找到錯誤來自節(jié)點(diǎn)2,再依次對節(jié)點(diǎn)4和5運(yùn)算Hash值并發(fā)現(xiàn)錯誤源于自節(jié)點(diǎn)4.然后收件人可以重新要求發(fā)信人發(fā)送節(jié)點(diǎn)4的數(shù)據(jù)從而使整個數(shù)據(jù)和發(fā)件人的保持一致瘦癌。
現(xiàn)實(shí)生活中我們常用的BT(BitTorrent眼耀,一種分布式文件下載協(xié)議)下載就是采用這一套技術(shù)流程,代表性的有迅雷下載佩憾,所以大家在用迅雷下載時哮伟,有沒有想過,為什么用迅雷下載的時候有時候需要先下載一個“種子”文件呢妄帘,這個“種子文件到底是什么楞黄?
其實(shí)這個種子文件就包含了我們前面所說的Hash List和Hash Root尿贫,用法自然也是前面的所說的——驗(yàn)證數(shù)據(jù)塊是否損壞或者被篡改渣聚,保證下載原始數(shù)據(jù)的的完整性和正確性性昭。
這里講了這么多火焰,好像沒有感受到與區(qū)塊鏈有任何聯(lián)系,實(shí)際上這些只是對基本概念的普及薪前,利用這些基礎(chǔ)信息我們才能開展后面的工作伯襟。
OK,進(jìn)入重點(diǎn)啃匿。
三馏锡、區(qū)塊鏈工作原理—區(qū)塊結(jié)構(gòu)篇
在了解區(qū)塊鏈之前雷蹂,我們需要知道很重要的一點(diǎn)就是,區(qū)塊鏈?zhǔn)怯伞皡^(qū)塊”這個基本單元所構(gòu)成杯道。
字面意思就可以看出來匪煌,區(qū)塊鏈?zhǔn)怯伞皡^(qū)塊”組成的鏈條,從技術(shù)的角度來說党巾,區(qū)塊鏈?zhǔn)且环N分布式數(shù)據(jù)庫萎庭。
如果把區(qū)塊鏈比作一支賬本,那么區(qū)塊就是這個賬本的一頁齿拂。
“區(qū)塊”的概念如此重要驳规,以至于我們只有真正理解了區(qū)塊,才能真正理解區(qū)塊鏈署海。
所以吗购,下面我們將會詳細(xì)“解剖”區(qū)塊,看看區(qū)塊的“五臟六腑”叹侄,由內(nèi)往外窺探整個區(qū)塊鏈的原理巩搏。
3.1昨登、先來區(qū)塊基本組成趾代,如圖
首先,一個完整的區(qū)塊分為區(qū)塊頭(Block Header)和區(qū)塊體(Block Body)丰辣。
什么是區(qū)塊體撒强?區(qū)塊體內(nèi)包含的是一條條交易數(shù)據(jù)禽捆,列如張三給李四轉(zhuǎn)了一筆賬,轉(zhuǎn)賬者飘哨,接收者胚想,金額,時間等等芽隆,這些信息構(gòu)成一條交易數(shù)據(jù)浊服,每一個區(qū)塊的區(qū)塊體都包含著無數(shù)條數(shù)據(jù),可以理解為胚吁,區(qū)塊體才是數(shù)據(jù)真正存儲的地方牙躺。
了解了區(qū)塊體,那什么是區(qū)塊頭腕扶?區(qū)塊頭是整個區(qū)塊的核心也是區(qū)塊的元數(shù)據(jù)孽拷,它的成員變量全都是公共的,這使得它可以很方便的向調(diào)用者提供關(guān)于Block屬性的操作半抱。區(qū)塊頭的組成相對復(fù)雜脓恕,我們一一來看。
1窿侈、Hash
由SHA256算法計算得出得當(dāng)前區(qū)塊的哈希值炼幔,也是代表當(dāng)前區(qū)塊的唯一值,可以理解成我們通常開發(fā)中Id的概念史简。每個區(qū)塊都有自己的唯一Hash江掩。
2、父哈希(Pre Hash)
上一個區(qū)塊的哈希值乘瓤。每個一區(qū)塊當(dāng)中都保存著上一個區(qū)塊的Hash环形,可以理解為父子關(guān)系,因?yàn)槌说谝粋€區(qū)塊(創(chuàng)世區(qū)塊)衙傀,所有區(qū)塊的產(chǎn)生都是基于前一個區(qū)塊抬吟。
3、子哈希(Next Hash)
基于當(dāng)前區(qū)塊所產(chǎn)生的下一個區(qū)塊的哈希值统抬,當(dāng)前區(qū)塊也就是子區(qū)塊的父區(qū)塊火本。
看到1、2聪建、3這里可以解決我們一直以來的一個疑惑钙畔,區(qū)塊鏈里面的“鏈”到底是什么?其實(shí)就是由于每個區(qū)塊有當(dāng)前Hash 金麸、父Hash擎析、子Hash的概念,這些所謂的“父”挥下,“子”形成了一套完整的順序鏈條揍魂,換句話說桨醋,區(qū)塊與區(qū)塊之間并非雜亂無章,而是存在著嚴(yán)格的順序關(guān)系现斋。而這種順序關(guān)系像極了鏈表的概念喜最,二者的邏輯順序均是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的。
鏈表:
區(qū)塊鏈:
注:有一點(diǎn)點(diǎn)小的區(qū)別是區(qū)塊鏈?zhǔn)欠茄h(huán)的庄蹋,而鏈表是可以有循環(huán)的瞬内。
4限书、版本號(Version)
系統(tǒng)版本號遂鹊,可以理解成日常開發(fā)中開發(fā)的軟件版本。
5、區(qū)塊高度(Height)
區(qū)塊鏈網(wǎng)絡(luò)中第幾個誕生的區(qū)塊序號裆装,例如第一個區(qū)塊通常也被稱為創(chuàng)世區(qū)塊,高度為0(這很程序員),第十個產(chǎn)生的區(qū)塊高度為9(區(qū)塊并不是一下子就全有的工扎,例如比特幣區(qū)塊就是每10分鐘產(chǎn)生一個,也就說區(qū)塊的“出生”都是有著先后順序的贞远,這個順序我們會打上標(biāo)簽,這個標(biāo)簽就是”高度“)溢吻。
6而晒、時間戳(TimeStamp)
區(qū)塊創(chuàng)建的時間,同時也交易數(shù)據(jù)打包進(jìn)區(qū)塊的時間颤专,區(qū)塊的誕生是伴隨著交易數(shù)據(jù)的打包記錄垦写,保存的地方就是我們前面提到的區(qū)塊體分蓖。
7、隨機(jī)數(shù)(Nonce)
一個從0開始窍荧,最大長度為32位的隨機(jī)數(shù)茉贡,這里就涉及到挖礦了腔丧,所謂的挖礦影暴,就是不停地變更區(qū)塊頭中的隨機(jī)數(shù),并對每次變更后的區(qū)塊頭(block_header,)做雙重SHA-256運(yùn)算(即SHA256 (SHA 256(Block_Header)))狈癞,將結(jié)果值哈希反轉(zhuǎn)并與當(dāng)前網(wǎng)絡(luò)的目標(biāo)值對應(yīng)的十進(jìn)制字符串做對比,如果小于目標(biāo)值,則解題成功脂信,工作量證明完成恒序。(這里先簡單了解即可,后面會重點(diǎn)講到)谁撼。
9歧胁、難度目標(biāo)(Target Bits)
難度值是礦工們挖礦的重要參考指標(biāo)滋饲,它決定了礦工大約需要經(jīng)過多少次Hash運(yùn)算才能產(chǎn)生一個合法的區(qū)塊。比特幣的區(qū)塊大約每10分鐘生成一個喊巍,如果要在不同的全網(wǎng)算力條件下屠缭,新區(qū)塊的產(chǎn)生都基本保持這個速率,難度值必須根據(jù)全網(wǎng)算力的變化進(jìn)行調(diào)整崭参。簡單地說呵曹,難度值被設(shè)定在無論挖礦能力如何,新區(qū)塊產(chǎn)生速率都保持在10分鐘一個何暮。
難度值的調(diào)整是在每個完整節(jié)點(diǎn)中獨(dú)立自動發(fā)生的奄喂。每隔2016個區(qū)塊,所有節(jié)點(diǎn)都會按統(tǒng)一的公式自動調(diào)整難度值
公式如下:
新難度值 = 舊難度值*(過去2016個區(qū)塊花費(fèi)時長/20160分鐘)
難度目標(biāo)值= 最大目標(biāo)值/新難度值
而最大目標(biāo)值為一個恒定值(常量):0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
解題(挖礦)成功的依據(jù)是:
SHA256(SHA256(block_header)) < F(nBits)
? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? (挖礦結(jié)果)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (目標(biāo)值)
10海洼、跨新、Merkle Root(默克爾樹根)
Merkle Root的計算過程相對復(fù)雜,一起放到最后的算法環(huán)節(jié)進(jìn)行統(tǒng)一詳細(xì)講解坏逢。
區(qū)塊鏈的工作原理—核心算法篇
在這一篇中我們將介紹幾點(diǎn)核心算法域帐,同時也是整個區(qū)塊鏈的核心原理。
我們將會講到:
1是整、上一篇中提到的Merkle樹是什么肖揣?Merkle樹的樹根 —Merkle Root 的算法。
2浮入、區(qū)塊Hash值的算法龙优。
3、挖礦合法性算法驗(yàn)證事秀。
一彤断、Merkle Tree
1、Merkle Tree是一種樹秽晚,大多數(shù)是二叉樹瓦糟,也可以多叉樹,無論是幾叉樹赴蝇,它都具有樹結(jié)構(gòu)的所有特點(diǎn)菩浙;
2、Merkle Tree的葉子節(jié)點(diǎn)的value是數(shù)據(jù)集合(區(qū)塊體中的數(shù)據(jù))的單元數(shù)據(jù)或者單元數(shù)據(jù)HASH句伶。
3劲蜻、非葉子節(jié)點(diǎn)的value是根據(jù)它下面所有的葉子節(jié)點(diǎn)值,然后按照Hash算法計算而得出的考余。
Merkle Tree可以看做前面所說Hash List的泛化先嬉,Hash List可以看作一種特殊的Merkle Tree,即樹高為2的多叉Merkle Tree楚堤,(前面Hash List沒理解清楚的可以往回翻重新理解一下)疫蔓。
在最底層含懊,和哈希列表一樣,我們把數(shù)據(jù)分成小的數(shù)據(jù)塊衅胀,有相應(yīng)地哈希和它對應(yīng)岔乔。但是往上走,注意滚躯,這里并不是和Hash List一樣直接去運(yùn)算根哈希雏门,而是把相鄰的兩個數(shù)據(jù)哈希合并成一個字符串,然后將這個由兩個Hash值拼成的字符串計算出新的Hash掸掏,茁影,這樣每兩個哈希就結(jié)婚生子,得到了一個”子哈仙シ铮“募闲。如果最底層的哈希總數(shù)是單數(shù)息裸,那到最后必然出現(xiàn)一個單身哈希蝇更,這種情況就直接對它進(jìn)行哈希運(yùn)算沪编,所以也能得到它的子哈希呼盆。于是往上推,依然是一樣的方式蚁廓,可以得到數(shù)目更少的新一級哈希访圃,最終必然形成一棵倒掛的樹,到了樹根的這個位置相嵌,這一代就剩下一個根哈希了腿时,我們把它叫做 Merkle Root,而這就是所謂的Merkle Root的生成過程饭宾。
在p2p網(wǎng)絡(luò)下載網(wǎng)絡(luò)之前批糟,先從可信的源獲得文件的Merkle Tree樹根。一旦獲得了樹根看铆,就可以從其他從不可信的源獲取Merkle tree徽鼎。通過可信的樹根來檢查接受到的Merkle Tree。如果Merkle Tree是損壞的或者虛假的弹惦,就從其他源獲得另一個Merkle Tree否淤,直到獲得一個與可信樹根匹配的Merkle Tree。
Merkle Tree和Hash List的主要區(qū)別是棠隐,Merkle Tree可以直接下載并立即驗(yàn)證Merkle Tree的一個分支石抡。因?yàn)榭梢詫⑽募蟹殖尚〉臄?shù)據(jù)塊,這樣如果有一塊數(shù)據(jù)損壞助泽,僅僅重新下載這個數(shù)據(jù)塊就行了啰扛。如果文件非常大嚎京,那么Merkle tree和Hash list都很難做到,但是Merkle tree可以一次下載一個分支隐解,然后立即驗(yàn)證這個分支挖藏,如果分支驗(yàn)證通過,就可以下載數(shù)據(jù)了厢漩。而Hash list只有下載整個hash list才能驗(yàn)證膜眠。(前面花了比較大的篇幅介紹了Hash算法,就是為了讓大家提前了解溜嗜,如何利用Hash去保證數(shù)據(jù)的一致性宵膨,這里的merkle root也是這個作用,只不過算法上有區(qū)別)
說了這么多炸宵, Hash Root也好辟躏、Merkle Root也罷,不管算法如何土全,剝開層層外殼捎琐,對于我們而言,它們的核心價值就是——確保數(shù)據(jù)的真?zhèn)涡怨祝覀兂Uf區(qū)塊鏈的數(shù)據(jù)不可篡改性也就是基于這一點(diǎn)瑞凑。
區(qū)塊的工作原理—區(qū)塊Hash的生成。
區(qū)塊Hash是代表區(qū)塊的唯一值概页,這個值并不是憑空創(chuàng)造籽御,而是和merkle root 、timestamp惰匙、nonce息息相關(guān)技掏。
我們采用驗(yàn)證法來看看這個值是如何產(chǎn)生的,以比特幣區(qū)塊277316為例项鬼。
其信息來自網(wǎng)站http://blockchain.info
以上是區(qū)塊高度為277316的區(qū)塊的區(qū)塊頭的所有數(shù)據(jù)哑梳。
現(xiàn)在開始對區(qū)塊277316的Hash值進(jìn)行驗(yàn)證。
第一步绘盟,準(zhǔn)備數(shù)據(jù)
1鸠真、版本號的十進(jìn)制:2
2、merkle root+pre_hash的16進(jìn)制:
0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569 c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e
3奥此、2013-12-27 23:11:54 的時間戳:1388185914
4弧哎、難度目標(biāo)(Bits)的十進(jìn)制:419668748
5、隨機(jī)數(shù)(nonce)的十進(jìn)制:924591752
第二步稚虎,全部轉(zhuǎn)換為16進(jìn)制
1撤嫩、00000002
2、0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569
? ? ? c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e
3蠢终、52be093a
4序攘、1903a30c
5茴她、371c2688
第三步,從big-endian轉(zhuǎn)化為little-endian
先解釋一下什么是endian程奠?簡單理解就是Big-endian是高字節(jié)在低地址丈牢,Litter-endian則高字節(jié)在高地址。
比如 瞄沙,int a = 0x05060708
在big-endian的情況下存放為:
字節(jié)號 0 1 2 3
數(shù)據(jù) 05 06 07 08
在little-endian的情況下存放為:
字節(jié)號 0 1 2 3
數(shù)據(jù) 08 07 06 05
發(fā)明人中本聰可能為了讓機(jī)器計算更快己沛,而變?yōu)榱烁咏鼨C(jī)器的編碼方式little-endian.
好,回到正題距境,所以第二步的數(shù)據(jù) 我們再進(jìn)行一次轉(zhuǎn)化申尼,得到了
1、02000000
2垫桂、69054f28012b4474caa9e821102655cc74037c415ad2bba70200000000000000
? 2ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc9(到這里的時候已經(jīng)拼成一個字符串了)
3师幕、3a09be52
4、0ca30319
5诬滩、88261c37
第四步霹粥,拼接字符串,開始驗(yàn)證
1疼鸟、我們將上面準(zhǔn)備的字符數(shù)據(jù)重新拼接成一個新的字符串后控,這個字符串我們稱之為“block_header”:
02000000
+
69054f28012b4474caa9e821102655cc74037c415ad2bba702000000000000002ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc9
+
3a09be52
+
0ca30319
+
88261c37
最終拼接得到的字符串block_header為:
0200000069054f28012b4474caa9e821102655cc74037c415ad2bba702000000000000002ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc93a09be520ca3031988261c37
2、將上面的 block_header轉(zhuǎn)成hex形式得到:
b'\x02\x00\x00\x00i\x05O(\x01+Dt\xca\xa9\xe8!\x10&U\xcct\x03|AZ\xd2\xbb\xa7\x02\x00\x00\x00\x00\x00\x00\x00.\xcf\xc7L\xebQ,PU\xbc\xff~Ws_s#\xc3/\x8b\xbbH\xf5\xe9c\x07\xe5&\x8c\x00\x1c\xc9:\t\xbeR\x0c\xa3\x03\x19\x88&\x1c7'
3愚臀、對這個值進(jìn)行兩次SHA256運(yùn)算忆蚀,為什么要兩次矾利,這是因?yàn)镾HA1在2017年被攻破姑裂,采用的方法是birthday collision attack。社區(qū)覺得SHA2被攻破也是時間的問題男旗,而抵御birthday collision attack的有效方法為雙重哈希算法舶斧,當(dāng)然這種說法只是網(wǎng)上傳言,沒有得到具體確認(rèn)察皇。
偽代碼:SHA256(SHA256(Hex(block_header)))茴厉,最終得到:
b'\xc4\xbd\xc7,\x1b\xb3\xa9D\xd9\xf2~\xb9(\xa9\xc4A\xdb\x96^\t;\xa1\xb9\xb6\x01\x00\x00\x00\x00\x00\x00\x00'
3、重新編碼得到:
c4bdc72c1bb3a944d9f27eb928a9c441db965e093ba1b9b60100000000000000
看到后面有一堆0什荣,感覺勝利的曙光快來了矾缓。其實(shí)這里實(shí)際上已經(jīng)完成了,但是得到這個值是little-endian小端模式的稻爬,比特幣區(qū)塊上所記錄的值也確實(shí)是這個值嗜闻,但是我們在平常使用和網(wǎng)頁瀏覽展示時,都是使用Big-endian大端順序
所以這里我們再進(jìn)行一次從little-endian轉(zhuǎn)化為big-endian桅锄,就能得到:
0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4
大功告成琉雳,看看http://blockchain.info所查詢到的样眠,完全一致,說明我們的方法是正確的翠肘,區(qū)塊Hash的算法就是我們前面的驗(yàn)算步驟檐束。
總的來說,算法不難束倍,最難的地方就在于親自驗(yàn)算的過程中被丧,要把所有的隱藏知識都挖掘出來。中文資料中绪妹,極少有人做詳細(xì)的通篇驗(yàn)算晚碾,而一旦真正理解了驗(yàn)算的過程,我們會發(fā)現(xiàn)比特幣的算法真的不難喂急。
附:
整個第四步的Python代碼如下:
有興趣的可以將這一段代碼copy到python開發(fā)工具中運(yùn)行試試格嘁,看看得到的值是否如上所說。也可以依照上面的步驟驗(yàn)證其他區(qū)塊加強(qiáng)理解廊移。
區(qū)塊的合法性驗(yàn)證
如何確認(rèn)區(qū)塊的合法性糕簿,前面在介紹區(qū)塊頭時有提及過,簡而言之就是區(qū)塊Hash必須要小于Target Bits (目標(biāo)難度值)狡孔,這里我們繼續(xù)采用驗(yàn)算法懂诗。
區(qū)塊Hash值在上一節(jié)已經(jīng)得到驗(yàn)證,我們算出的是
0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4
Target Bits在上面也已經(jīng)記錄了苗膝,是
419668748
數(shù)據(jù)都準(zhǔn)備好了殃恒,要驗(yàn)證區(qū)塊是否合法還不簡單嗎,直接對比兩個值的大小不就完了辱揭?
真有這么簡單嗎离唐?
事實(shí)上所謂的“對比大小”也是有一套完整的換算流程的。
具體怎么換算问窃,這里還們還是按照老套路亥鬓,采用驗(yàn)證法一步步走。
1域庇、準(zhǔn)備數(shù)據(jù)
Bits :419668748?
最大目標(biāo)值:0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Hash:0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4
2嵌戈、將Bits 轉(zhuǎn)成 16進(jìn)制得到:
1903a30c
3、將1903a30c進(jìn)行拆分听皿,前2位我們稱為冪者指數(shù)熟呛,后面6位稱為系數(shù),拆分后得到
19? 03a30c
3尉姨、將拆分的值代入固定公式:
目標(biāo)值=系數(shù)*2^(8*(冪者指數(shù)-3))次方
即:目標(biāo)值 = 0x03a30c*2^(8*(0x19-3))
最終計算出來的就是真正意義上的目標(biāo)值了庵朝。
0000000000000003a30c00000000000000000000000000000000000000000000
4、驗(yàn)算結(jié)果
target bits:
0000000000000003a30c00000000000000000000000000000000000000000000
target:
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
>
0000000000000003a30c00000000000000000000000000000000000000000000
計算結(jié)果小于難度目標(biāo),符合要求偿短,那這個結(jié)果就一定是網(wǎng)站上公布的數(shù)字了欣孤。
正確的hash值
在挖礦時,nonce隨機(jī)數(shù)是未知的昔逗,要從0試到2^32降传,但是這個數(shù)字其實(shí)不大,只有4294967296次勾怒。以現(xiàn)在的一臺礦機(jī)動輒14T每秒的算力婆排,全部算完到上限也不需要一秒。所以需要使用創(chuàng)幣交易中的附帶信息笔链,額外的字符串成為extra nonce段只,例如中本聰在比特幣的創(chuàng)世區(qū)塊中寫道“The Times 03/Jan/2009 Chancellor on brink of second ballout for banks”(英國泰晤士報2009年1月3日文,財政大臣正處于實(shí)施第二輪銀行緊急援助的邊緣)嘲諷中心化的銀行鉴扫。
在2013年年底時赞枕,區(qū)塊產(chǎn)生,這需要算力達(dá)到8T/s的設(shè)備坪创,即每秒8*10^15次暴力驗(yàn)證炕婶,連續(xù)工作10分鐘。這對于2018年的現(xiàn)在來說的確不算什么莱预,一臺礦機(jī)柠掂,不比兩三塊磚頭大多少,就擁有14T/s的算力依沮,只需要6涯贞,7分鐘單獨(dú)就可以挖到。但在當(dāng)時危喉,8T也是全網(wǎng)千分之一的算力了宋渔,需要當(dāng)時最好的礦機(jī)上百臺一起工作。而如果這個計算使用一臺普通的桌面電腦姥饰,需要26年傻谁。如果使用一臺iphoneX的話,每秒可以做70次計算列粪,那么將需要四百萬年。
通過上面的算法我們完整地回顧了比特幣區(qū)塊鏈的工作量證明算法谈飒,如果各位完全理清了其中的思路岂座,也就可以手動實(shí)現(xiàn)自己的挖礦程序,或者另外嘗試設(shè)計一些新的區(qū)塊鏈產(chǎn)品了杭措。最艱深的技術(shù)费什,我們希望能夠在底層去了解,然而撥開云霧手素,其實(shí)底層的邏輯并不難鸳址。
不過比特幣里面的技術(shù)遠(yuǎn)不止挖礦算法瘩蚪,加密算法,Script智能合約稿黍,各種協(xié)議疹瘦,各種網(wǎng)絡(luò),交易的驗(yàn)證巡球,每一個都充滿了魔性言沐,進(jìn)出之間,不由得讓人驚嘆發(fā)明人知識的深度與廣度酣栈。無論比特幣是什么险胰,將會怎樣,但是以比特幣為第一個大規(guī)模應(yīng)用的區(qū)塊鏈技術(shù)矿筝,已經(jīng)擴(kuò)散了開來起便,整個系統(tǒng)的嚴(yán)密與邏輯的復(fù)雜,的確讓人著迷窖维。
更多
對于創(chuàng)世區(qū)塊缨睡,版本號是1,高度為0(這很程序員)陈辱,奖年。
前一區(qū)塊的hash值,猜想會是什么呢沛贪?對于創(chuàng)世區(qū)塊陋守,是沒有前一區(qū)塊,中本聰默認(rèn)寫成了0000000000000000000000000000000000000000000000000000000000000000利赋。
難度目標(biāo)是1水评,這是定義為一個sha256結(jié)果的前32位是0,也就是對應(yīng)的16進(jìn)制字符串要有8個0媚送,那么難度bits此時是0x1d00ffff中燥。這個數(shù)字的得出需要概率論的知識,同時也是中本聰?shù)囊粋€規(guī)定塘偎。
更多區(qū)塊信息可以前往http://blockchain.info查詢疗涉,或許會有更多發(fā)現(xiàn)哦。
其他工具
https://hash.online-convert.com/sha256-generatorSHA-256在線驗(yàn)證
https://webbtc.com/? 獲取區(qū)塊的json數(shù)據(jù)
http://blockexplorer.com/q/getdifficulty查詢比特幣的當(dāng)前難度
http://bitcoin.sipa.be/查看難度的變化情況
http://blockexplorer.com/q/getblockcount查詢比特幣的區(qū)塊數(shù)
https://bitcoin.org/en/developer-reference比特幣區(qū)塊鏈更詳細(xì)的講解(英文)
參考文章:
https://blog.csdn.net/wo541075754/article/details/54632929
http://www.reibang.com/p/c6ef67755105
http://www.cnblogs.com/zhaoweiwei/p/difficulty.html
https://blog.csdn.net/jason_cuijiahui/article/details/79011118
https://blog.csdn.net/chaiyu2002/article/details/81237971
https://www.8btc.com/article/9688
第三章—java簡單實(shí)現(xiàn)區(qū)塊鏈
前面兩章說了許多關(guān)于區(qū)塊鏈的理論知識吟秩,這一章我們將會將前面的所有的理論知識結(jié)合起來咱扣,用java簡答實(shí)現(xiàn)一套區(qū)塊鏈。
基于面向?qū)ο蟮乃枷牒溃紫?/p>
1闹伪、定義區(qū)塊鏈的類塊
import java.util.Date;
public class Block {
public String hash;//區(qū)塊Hash
public String previousHash;//前導(dǎo)Hash
private String data; //可以理解為前面講到的區(qū)塊結(jié)構(gòu)里的區(qū)塊體里打包的交易數(shù)據(jù)
private long timeStamp; //時間戳
//Block Constructor.
public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
}
}
2、創(chuàng)建數(shù)字簽名
創(chuàng)建一個StringUtil,封裝了sha256方法偏瓤,方便后面調(diào)用杀怠,因?yàn)檫@是一個工具類,所以我們可以不關(guān)心它的具體實(shí)現(xiàn)方式厅克,只要知道它是sha256的java實(shí)現(xiàn)即可赔退。
import java.security.MessageDigest;
public class StringUtil {
//Applies Sha256 to a string and returns the result.
public static String applySha256(String input){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256"); ? ? ? ?
//Applies sha256 to our input,
byte[] hash = digest.digest(input.getBytes("UTF-8")); ? ? ? ?
StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if(hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
catch(Exception e) {
throw new RuntimeException(e);
}
}
}
接下來讓我們在Block類中應(yīng)用 方法 applySha256 方法,其主要的目的就是計算hash值已骇,我們計算的hash值應(yīng)該包括區(qū)塊中所有我們不希望被惡意篡改的數(shù)據(jù)离钝,再加上preHash,data和timeStamp褪储,這在上面已經(jīng)演示過了卵渴,是一套固定公式,所以這里沒有什么爭議鲤竹。
//簡化了計算方式
public String calculateHash() {
String calculatedhash = StringUtil.applySha256(
previousHash +
Long.toString(timeStamp) +
data
);
return calculatedhash;
}
然后把這個方法加入到Block的構(gòu)造函數(shù)中去
public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
this.hash = calculateHash();
}
3浪读、測試
在主方法中讓我們創(chuàng)建一些區(qū)塊,并把其hash值打印出來辛藻,來看看是否一切都在我們的掌控中碘橘。
第一個塊稱為創(chuàng)世紀(jì)區(qū)塊,因?yàn)樗穷^區(qū)塊吱肌,所以我們只需輸入“0”作為前一個塊的previous hash痘拆。
public class NoobChain {
public static void main(String[] args) {
Block genesisBlock = new Block("Hi im the first block", "0");
System.out.println("Hash for block 1 : " + genesisBlock.hash);
Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
System.out.println("Hash for block 2 : " + secondBlock.hash);
Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
System.out.println("Hash for block 3 : " + thirdBlock.hash);
}
}
打印:
Hash for block 1: f6d1bc5f7b0016eab53ec022db9a5d9e1873ee78513b1c666696e66777fe55fb
Hash for block 2: 6936612b3380660840f22ee6cb8b72ffc01dbca5369f305b92018321d883f4a3
Hash for block 3: f3e58f74b5adbd59a7a1fc68c97055d42e94d33f6c322d87b29ab20d3c959b8f
每一個區(qū)塊都必須要有自己的數(shù)據(jù)簽名即hash值氮墨,這個hash值依賴于自身的信息(data)和上一個區(qū)塊的數(shù)字簽名(previousHash)纺蛆,但這個還不是區(qū)塊鏈,下面讓我們存儲區(qū)塊到數(shù)組中规揪,這里我會引入gson包桥氏,目的是可以用json方式查看整個一條區(qū)塊鏈結(jié)構(gòu)。
import java.util.ArrayList;
import com.google.gson.GsonBuilder;
public class NoobChain {
public static ArrayList<Block> blockchain = new ArrayList<Block>();
public static void main(String[] args) {
//add our blocks to the blockchain ArrayList:
blockchain.add(new Block("Hi im the first block", "0"));
blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));
blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));
String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
System.out.println(blockchainJson);
}
}這樣的輸出結(jié)構(gòu)就更類似于我們所期待的區(qū)塊鏈的樣子猛铅。
4字支、檢查區(qū)塊鏈的完整性
在主方法中增加一個isChainValid()方法,目的是循環(huán)區(qū)塊鏈中的所有區(qū)塊并且比較hash值奸忽,這個方法用來檢查hash值是否是于計算出來的hash值相等堕伪,同時previousHash值是否和前一個區(qū)塊的hash值相等。(第二章講到過月杉,驗(yàn)證區(qū)塊的有效性即重新計算區(qū)塊的Hash值并與鏈上記錄的區(qū)塊Hash值是否一致刃跛,而上一個區(qū)塊的Hash值—preHash,又影響了當(dāng)前Hash的計算)
所以我會的驗(yàn)證方法就會這么寫:
public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock;
//遍歷整個區(qū)塊鏈
for(int i=1; i < blockchain.size(); i++) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i-1);
//當(dāng)重新計算區(qū)塊Hash發(fā)現(xiàn)和鏈上記錄的不相等時
if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
System.out.println("Current Hashes not equal");
return false;
}
//當(dāng)上一個區(qū)塊上的Hash和當(dāng)前區(qū)塊記錄的preHash不相等時
if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
System.out.println("Previous Hashes not equal");
return false;
}
}
return true;
}
任何區(qū)塊鏈中區(qū)塊的一絲一毫改變都會導(dǎo)致這個函數(shù)返回false苛萎,也就證明了區(qū)塊鏈無效了。
5、挖礦
這里我們要求挖礦者做工作量證明腌歉,具體的方式是在區(qū)塊中嘗試不同的參數(shù)值直到它的hash值是從一系列的0開始的蛙酪。讓我們添加一個名為nonce的int類型以包含在我們的calculatehash()方法中,以及需要的mineblock()方法
public class Block {
public String hash;
public String previousHash;
private String data; //our data will be a simple message.
private long timeStamp; //as number of milliseconds since 1/1/1970.
private int nonce;
//區(qū)塊的構(gòu)造?
public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
this.hash = calculateHash();
}
//基于交易數(shù)據(jù)信息和其他數(shù)據(jù)生成當(dāng)前區(qū)塊的hash
public String calculateHash() {
String calculatedhash = StringUtil.applySha256(
previousHash +
Long.toString(timeStamp) +
Integer.toString(nonce) +
data
);
return calculatedhash;
}
public void mineBlock(int difficulty) {
String target = new String(new char[difficulty]).replace('\0', '0');? ? ? ? //計算出的Hash要求前面多少個0(理論上前面的0要求越多代表挖礦難度越大)
while(!hash.substring( 0, difficulty).equals(target)) {
nonce ++;
hash = calculateHash();
}
System.out.println("Block Mined!!! : " + hash);
}
}
mineBlock()方法中引入了一個int值稱為difficulty難度翘盖,低的難度比如1和2桂塞,普通的電腦基本都可以馬上計算出來,我的建議是在4-6之間進(jìn)行測試馍驯,普通電腦大概會花費(fèi)3秒時間阁危,在萊特幣中難度大概圍繞在442592左右,而在比特幣中每一次挖礦都要求大概在10分鐘左右汰瘫,當(dāng)然根據(jù)所有網(wǎng)絡(luò)中的計算能力狂打,難度也會不斷的進(jìn)行修改。
我們在NoobChain類 中增加difficulty這個靜態(tài)變量混弥。
public static int difficulty = 5;
這樣我們必須修改主方法中讓創(chuàng)建每個新區(qū)塊時必須觸發(fā)mineBlock()方法趴乡,而isChainValid()方法用來檢查每個區(qū)塊的hash值是否正確,整個區(qū)塊鏈?zhǔn)欠袷怯行У摹?/p>
public class NoobChain {
public static ArrayList<Block> blockchain = new ArrayList<Block>();
public static int difficulty = 5;
public static void main(String[] args) {
//手動創(chuàng)建幾個區(qū)塊
blockchain.add(new Block("Hi im the first block", "0"));
System.out.println("Trying to Mine block 1... ");
blockchain.get(0).mineBlock(difficulty);
blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));
System.out.println("Trying to Mine block 2... ");
blockchain.get(1).mineBlock(difficulty);
blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));
System.out.println("Trying to Mine block 3... ");
blockchain.get(2).mineBlock(difficulty);
System.out.println("\nBlockchain is Valid: " + isChainValid());
String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
System.out.println("\nThe block chain: ");
System.out.println(blockchainJson);
}
public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock;
String hashTarget = new String(new char[difficulty]).replace('\0', '0');
//遍歷區(qū)塊蝗拿,驗(yàn)證有效性
for(int i=1; i < blockchain.size(); i++) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i-1);
//當(dāng)重新計算區(qū)塊Hash發(fā)現(xiàn)和鏈上記錄的不相等時
if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
System.out.println("Current Hashes not equal");
return false;
}
//當(dāng)上一個區(qū)塊上的Hash和當(dāng)前區(qū)塊記錄的preHash不相等時
if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
System.out.println("Previous Hashes not equal");
return false;
}
//這里涉及到的其實(shí)就挖礦算法晾捏,通過不斷變化的nonce值來生成Hash值,如果生成的Hash值的前幾位的都是0且和target要求的位數(shù)一致哀托,代表這個隨機(jī)數(shù)生成的區(qū)塊是有效的惦辛。
if(!currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
System.out.println("This block hasn't been mined");
return false;
}
}
return true;
}
}
打印:
Trying to Mine block 1...
Block Mined!!! : 0000016667d4240e9c30f53015310b0ec6ce99032d7e1d66d670afc509cab082
Trying to Mine block 2...
Block Mined!!! : 000002ea55735bea4cac7e358c7b0d8d81e8ca24021f5f85211bf54fd4ac795a
Trying to Mine block 3...
Block Mined!!! : 000000576987e5e9afbdf19b512b2b7d0c56db0e6ca49b3a7e638177f617994b
Blockchain is Valid: true
[
? {
? ? "hash": "0000016667d4240e9c30f53015310b0ec6ce99032d7e1d66d670afc509cab082",
? ? "previousHash": "0",
? ? "data": "first",
? ? "timeStamp": 1520659506042,
? ? "nonce": 618139
? },
? {
? ? "hash": "000002ea55735bea4cac7e358c7b0d8d81e8ca24021f5f85211bf54fd4ac795a",
? ? "previousHash": "0000016667d4240e9c30f53015310b0ec6ce99032d7e1d66d670afc509cab082",
? ? "data": "second",
? ? "timeStamp": 1520659508825,
? ? "nonce": 1819877
? },
? {
? ? "hash": "000000576987e5e9afbdf19b512b2b7d0c56db0e6ca49b3a7e638177f617994b",
? ? "previousHash": "000002ea55735bea4cac7e358c7b0d8d81e8ca24021f5f85211bf54fd4ac795a",
? ? "data": "third",
? ? "timeStamp": 1520659515910,
? ? "nonce": 1404341
? }
]
經(jīng)過測試增加一個新的區(qū)塊即挖礦必須花費(fèi)一定時間仓手,大概是3秒左右胖齐,你可以提高difficulty難度來看,它是如何影響數(shù)據(jù)難題所花費(fèi)的時間的
如果有人在你的區(qū)塊鏈系統(tǒng)中惡意篡改數(shù)據(jù):
他們的區(qū)塊鏈?zhǔn)菬o效的俗或。
他們無法創(chuàng)建更長的區(qū)塊鏈
網(wǎng)絡(luò)中誠實(shí)的區(qū)塊鏈會在長鏈中更有時間的優(yōu)勢
因?yàn)榇鄹牡膮^(qū)塊鏈將無法趕上長鏈和有效鏈市怎,除非他們比你網(wǎng)絡(luò)中所有的節(jié)點(diǎn)擁有更大的計算速度,可能是未來的量子計算機(jī)或者是其他什么辛慰。
如果你耐心的看到這里了区匠,恭喜,我們已經(jīng)基本創(chuàng)建了屬于自己的區(qū)塊鏈
它有:
有很多區(qū)塊組成用來存儲數(shù)據(jù)
有數(shù)字簽名讓你的區(qū)塊鏈鏈接在一起
需要挖礦的工作量證明新的區(qū)塊
可以用來檢查數(shù)據(jù)是否是有效的同時是未經(jīng)篡改的
結(jié)語:
坦白說帅腌,這篇文章更多的是從代碼講解的角度來剖析區(qū)塊鏈的工作原理驰弄,為的是讓大家更好的吸收前面所講解的知識點(diǎn),雖然有一些偽代碼的成分速客,但是我們確實(shí)完成了區(qū)塊鏈所有應(yīng)該有的功能戚篙。當(dāng)然,真正的區(qū)塊鏈實(shí)現(xiàn)遠(yuǎn)不止這么一點(diǎn)溺职,大量的實(shí)現(xiàn)細(xì)節(jié)值得我們?nèi)パ芯吭染⑻接懞蛯?shí)現(xiàn)剪菱,更多的我們后續(xù)會再講到挠阁。