Go語言版本區(qū)塊鏈第二部分:工作量證明

引入:

上一篇文章中,雖然我們只設(shè)計(jì)了一個(gè)簡單的區(qū)塊鏈原型,但它體現(xiàn)了區(qū)塊鏈數(shù)據(jù)庫的本質(zhì)。我們可以向它里面添加區(qū)塊,這些區(qū)塊呈鏈狀的,后一個(gè)區(qū)塊指向前一個(gè)區(qū)塊。然而,我們實(shí)現(xiàn)的區(qū)塊鏈有一個(gè)非常明顯的瑕疵:添加區(qū)塊到這個(gè)鏈上特別容易。比特幣或者其他區(qū)塊鏈的一個(gè)要旨是向鏈中添加區(qū)塊具有一定的困難性。今天我們就來修復(fù)這個(gè)瑕疵。

PoW(工作量證明):

區(qū)塊鏈中一個(gè)關(guān)鍵的理念是你要想往里面添加數(shù)據(jù)需要完成一些艱難的工作(如解難題,或者叫挖礦)才行。這些艱難的工作保證著區(qū)塊鏈安全和一致性。所以區(qū)塊鏈會(huì)獎(jiǎng)勵(lì)這些完成艱難工作的人(這就是為什么人們挖礦會(huì)獎(jiǎng)勵(lì)比特幣)。

這種機(jī)制與生活中的一個(gè)現(xiàn)象非常相似:一個(gè)人需要努力工作從而獲得報(bào)酬去維持他的生活。在區(qū)塊鏈中,一些網(wǎng)絡(luò)參與者(礦工)努力工作從而維持此網(wǎng)絡(luò)的運(yùn)行,他們向鏈中添加區(qū)塊,并且從中獲得獎(jiǎng)勵(lì)(如比特幣)。 他們的工作使得一個(gè)區(qū)塊被安全的正確無誤的添加到區(qū)塊鏈中,這也維持著整個(gè)區(qū)塊鏈數(shù)據(jù)庫的穩(wěn)定。值得注意的是,誰完成這件工作的必須有一個(gè)證明。

整個(gè)“解難題和證明”的機(jī)制稱作“工作量證明”。說他難是因?yàn)椤敖怆y題”需要大量的計(jì)算:即使是性能很好的計(jì)算機(jī)也不能快速的完成。并且這個(gè)工作的難度會(huì)隨著時(shí)間持續(xù)增大以保證大約6塊/h的出塊速度。在區(qū)塊鏈中這種工作(挖礦工作)的目標(biāo)是為一個(gè)區(qū)塊找到一個(gè)滿足一些要求的的hash值。并且這個(gè)hash值也起到證明的作用。因此,挖礦實(shí)際上就是尋找這種證明。

最需要強(qiáng)調(diào)的是,“工作量證明算法”必需滿足一個(gè)需求:求解這個(gè)難題很困難,但是驗(yàn)證它很簡單。

哈希:

在這一小節(jié)中,我們將討論哈希。如果你對(duì)這一塊很熟悉,請(qǐng)?zhí)^這一部分。

哈希的過程就是給某一數(shù)據(jù)找到對(duì)應(yīng)的一個(gè)hash值的過程。哈希函數(shù)可以接受任意大小的數(shù)據(jù)并生成固定大小的hash值。哈希有如下幾個(gè)特性:

1.給定一個(gè)hash值,不能由此反推出原始數(shù)據(jù)。因此,哈希不是加密。

2.確定的數(shù)據(jù)只有一個(gè)hash值,并且這個(gè)hash值是唯一的。

3.僅僅改動(dòng)數(shù)據(jù)中的一個(gè)字節(jié),得到的hash值就完全不同。

哈希函數(shù)在數(shù)據(jù)一致性方面有著廣泛的應(yīng)用。一些軟件提供商將軟件的驗(yàn)證碼印在軟件的包裝上面。

用戶下載文件后可以用一個(gè)給定的哈希函數(shù)生成一個(gè)哈希值與軟件提供商提供的hash對(duì)比一下,看是否一致。

在區(qū)塊鏈中,哈希用來保證區(qū)塊的(添加到區(qū)塊鏈前后的)一致性。區(qū)塊鏈中哈希算法的入?yún)耙粋€(gè)區(qū)塊的哈希值,這使得惡意修改一個(gè)區(qū)塊變的不可能,或者至少非常困難。因?yàn)檫@需要重新計(jì)算這個(gè)區(qū)塊的哈希值以及所有之后的區(qū)塊的哈希值。

哈?,F(xiàn)金:

比特幣中使用了Hashcash算法,這是一個(gè)PoW算法,設(shè)計(jì)的初衷是用來防止垃圾郵件。該算法可分解為以下幾個(gè)步驟:

1.準(zhǔn)備公開的數(shù)據(jù)(data):在郵件系統(tǒng)中為接收方的地址;在比特幣中為區(qū)塊頭

2.添加一個(gè)計(jì)數(shù)器(counter)。從0開始計(jì)數(shù)。

3.計(jì)算data+counter組合的hash值

4.校驗(yàn)hash值是否滿足特定的要求

1).是,恭喜你成功了

2).否,counter++ 并且重復(fù)步驟3和4

所以,這是一個(gè)強(qiáng)制暴力計(jì)算的算法:改變counter,計(jì)算一個(gè)新的哈希值,檢驗(yàn)它,不符合繼續(xù)增加counter,繼續(xù)計(jì)算一個(gè)新的哈希,等等,所以這是一個(gè)計(jì)算困難型的算法。

現(xiàn)在我們來看看目標(biāo)哈希值需要滿足的條件。在最早的Hashcash實(shí)現(xiàn)中,目標(biāo)哈希值需要滿足前20個(gè)比特都是0這樣的要求。在比特幣中,目標(biāo)哈希滿足的條件是隨著時(shí)間變化的,因?yàn)樵诒忍貛诺脑O(shè)計(jì)中,不管是計(jì)算能力隨著時(shí)間推移的增長還是越來越多的員工加入到網(wǎng)絡(luò)當(dāng)中,出塊的速度需要保持在每10分鐘一個(gè)。

為了演示這一算法過程,我們使用前面例子中的數(shù)據(jù)("I like donuts") ,目標(biāo)哈希滿足前三個(gè)字節(jié)全部為0:

圖中 ca07ca是十六進(jìn)制表示的計(jì)數(shù)器(counter)的值,相當(dāng)于十進(jìn)制中的13240266。

實(shí)現(xiàn):

上面我們分析了理論基礎(chǔ),現(xiàn)在我們來編寫代碼。首先,我們定義挖礦的難度:

比特幣中,是在被挖出的區(qū)塊的區(qū)塊頭中存儲(chǔ)挖礦難度的。我們不打算實(shí)現(xiàn)一個(gè)目標(biāo)哈希調(diào)整(挖礦難度的調(diào)整)的算法,現(xiàn)在我們僅僅定義一個(gè)全局的常量表示挖礦難度。

24是隨意選取的,我們的目標(biāo)是目標(biāo)值占用內(nèi)存空間在256個(gè)比特以內(nèi)。并且我們希望這個(gè)"難度"足夠有意義但是不能太大,因?yàn)?難度"越大就越難找到一個(gè)合適的哈希值。

創(chuàng)建一個(gè)ProofOfWork結(jié)構(gòu),它持有兩個(gè)指針,一個(gè)指向區(qū)塊,一個(gè)指向“目標(biāo)值”?!澳繕?biāo)值”就是算出的哈希滿足的需求。我們之所以使用big.Int類型是因?yàn)槲覀冃枰容^哈希值和“目標(biāo)值”:我們將哈希值轉(zhuǎn)換為一個(gè)bigInt類型然后檢驗(yàn)它是否比目標(biāo)值小。

在NewProofOfWork函數(shù)中,我們初始化一個(gè)big.Int類型的變量,設(shè)置其值為1,然后左移256-targetBits?個(gè)比特位。256指的是SHA-256的比特位數(shù),我的區(qū)塊鏈中將使用SHA-256哈希算法。十六進(jìn)制表示的“目標(biāo)值”如下圖所示:

它占用29個(gè)字節(jié)的內(nèi)存空間。下面是之前計(jì)算的哈希與“目標(biāo)值”的比較:

第一個(gè)哈希值("I like donuts"計(jì)算得出的哈希值)大于目標(biāo)值,因此它是無效的。第二個(gè)哈希值("I like donutsca07ca"計(jì)算得出的哈希值)小于目標(biāo)值,因此它是有效的。

你可以認(rèn)為“目標(biāo)值”是有效哈希的上邊界:如果一個(gè)哈希值小于這個(gè)邊界值,它是有效的,反之則反。降低這個(gè)邊界值意味著有效值的減少,因此,找到一個(gè)有效值需要付出更多的工作。

現(xiàn)在,我們準(zhǔn)備計(jì)算哈希的數(shù)據(jù)。

這段代碼很簡單:我們僅僅將區(qū)塊中的字段與目標(biāo)值及nonce合并。nonce就是上文Hashcash中描述的計(jì)數(shù)器,這是一個(gè)密碼學(xué)上的名詞。

好了,所有的準(zhǔn)備工作都完成了,我們可以開始實(shí)現(xiàn)PoW算法的核心了。

首先,我們定義幾個(gè)變量,hashInt:hash轉(zhuǎn)換為整型后的值;nonce:計(jì)數(shù)器。接下來是一個(gè)(偽)"無限循環(huán)",循環(huán)的最大次數(shù)為maxNonce,它與math.MaxInt64相等;這樣是為了防止nonce的溢出。盡管在我們的Pow算法實(shí)現(xiàn)中計(jì)數(shù)器的溢出很難,但是檢查一下更好,以防萬一。

在循環(huán)中執(zhí)行的步驟:

1.準(zhǔn)備數(shù)據(jù)

2.用SHA-256計(jì)算數(shù)據(jù)的hash

3.得到hash的big integer 類型

4.將hash的整型值與目標(biāo)值比較

現(xiàn)在我們可以Block的SetHash方法刪掉了并且我們將NewBlock方法修改如下:

如你所見nonce將作為Block的一個(gè)屬性保存在其中。這樣做是必需的,因?yàn)楣ぷ髁孔C明需要用到noce。Block結(jié)構(gòu)變?yōu)槿缦滤镜臉幼樱?/p>

讓我們啟動(dòng)程序看看我們的程序是否能夠很好的工作。

非常好!現(xiàn)在你可以看到所有區(qū)塊的hash都是以三個(gè)字節(jié)的0開頭,并且生成這些hash值需要一些時(shí)間。

事情還沒完,我們還有一件事要做:驗(yàn)證工作量。

這就是我們使用區(qū)塊中存儲(chǔ)的nonce的地方。

再看看我們的代碼是否能正常運(yùn)行:

結(jié)果:

結(jié)論:

我們的區(qū)塊鏈進(jìn)一步接近它的真實(shí)架構(gòu)了:添加區(qū)塊需要一定的工作量證明,因此可以挖礦了。但是它依然缺少一些至關(guān)重要的特征:區(qū)塊鏈數(shù)據(jù)沒有持久化,缺少錢包,地址,交易以及共識(shí)機(jī)制。所有的這些特性,我們會(huì)在以后的文章中一一介紹。

-盡力而為-

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、快速術(shù)語檢索 比特幣地址:(例如:1DSrfJdB2AnWaFNgSbv3MZC2m74996JafV)由一串...
    不如假如閱讀 16,578評(píng)論 4 87
  • 1 貨幣的演變——從貝殼到比特幣 當(dāng)社會(huì)分工產(chǎn)生之后,人類就產(chǎn)生了商品交換的需求。在貨幣被發(fā)明之前,人類是以以物換...
    longlee閱讀 7,941評(píng)論 1 23
  • 六世情歌 第五首 圣潔的雪域 文/金罡 雪花飄飛 月光下純凈的雪域 紅宮這般美 我在梵音中抖落禪衣 我將尊貴疊起 ...
    倉央嘉措詩社閱讀 324評(píng)論 0 1
  • 使用golang開發(fā),借助字典樹結(jié)構(gòu)+堆的數(shù)據(jù)結(jié)構(gòu),實(shí)現(xiàn)了us級(jí)別的搜索前綴詞和熱門搜索詞的獲取。 相關(guān)鏈接dem...
    playwolf719閱讀 941評(píng)論 0 3
  • 5289——流浪的七月 夢(mèng)想不是在夢(mèng)中使勁的在夢(mèng)中去想,如何去實(shí)現(xiàn)自己的夢(mèng)。夢(mèng)想就是自己走在路上,一步步的去實(shí)現(xiàn)自...
    爐邊雪人閱讀 323評(píng)論 4 4

友情鏈接更多精彩內(nèi)容