溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python區(qū)塊鏈如何實(shí)現(xiàn)簡(jiǎn)版工作量證明

發(fā)布時(shí)間:2022-05-25 09:16:49 來源:億速云 閱讀:205 作者:zzz 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“python區(qū)塊鏈如何實(shí)現(xiàn)簡(jiǎn)版工作量證明”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“python區(qū)塊鏈如何實(shí)現(xiàn)簡(jiǎn)版工作量證明”吧!

工作量證明

區(qū)塊鏈的一個(gè)關(guān)鍵點(diǎn)就是,一個(gè)人必須經(jīng)過一系列困難的工作,才能將數(shù)據(jù)放入到區(qū)塊鏈中。正是由于這種困難的工作,才保證了區(qū)塊鏈的安全和一致。此外,完成這個(gè)工作的人,也會(huì)獲得相應(yīng)獎(jiǎng)勵(lì)(這也就是通過挖礦獲得幣)。

這個(gè)機(jī)制與生活現(xiàn)象非常類似:一個(gè)人必須通過努力工作,才能夠獲得回報(bào)或者獎(jiǎng)勵(lì),用以支撐他們的生活。在區(qū)塊鏈中,是通過網(wǎng)絡(luò)中的參與者(礦工)不斷的工作來支撐起了整個(gè)網(wǎng)絡(luò)。礦工不斷地向區(qū)塊鏈中加入新塊,然后獲得相應(yīng)的獎(jiǎng)勵(lì)。在這種機(jī)制的作用下,新生成的區(qū)塊能夠被安全地加入到區(qū)塊鏈中,它維護(hù)了整個(gè)區(qū)塊鏈數(shù)據(jù)庫的穩(wěn)定性。值得注意的是,完成了這個(gè)工作的人必須要證明這一點(diǎn),即他必須要證明他的確完成了這些工作。

整個(gè) “努力工作并進(jìn)行證明” 的機(jī)制,就叫做工作量證明(proof-of-work)。要想完成工作非常地不容易,因?yàn)檫@需要大量的計(jì)算能力:即便是高性能計(jì)算機(jī),也無法在短時(shí)間內(nèi)快速完成。另外,這個(gè)工作的困難度會(huì)隨著時(shí)間不斷增長(zhǎng),以保持每 10 分鐘出 1 個(gè)新塊的速度。在比特幣中,這個(gè)工作就是找到一個(gè)塊的哈希,同時(shí)這個(gè)哈希滿足了一些必要條件。這個(gè)哈希,也就充當(dāng)了證明的角色。因此,尋求證明(尋找有效哈希),就是礦工實(shí)際要做的事情。

哈希計(jì)算

獲得指定數(shù)據(jù)的一個(gè)哈希值的過程,就叫做哈希計(jì)算。一個(gè)哈希,就是對(duì)所計(jì)算數(shù)據(jù)的一個(gè)唯一表示。對(duì)于一個(gè)哈希函數(shù),輸入任意大小的數(shù)據(jù),它會(huì)輸出一個(gè)固定大小的哈希值。下面是哈希的幾個(gè)關(guān)鍵特性:

  • 無法從一個(gè)哈希值恢復(fù)原始數(shù)據(jù)。也就是說,哈希并不是加密。

  • 對(duì)于特定的數(shù)據(jù),只能有一個(gè)哈希,并且這個(gè)哈希是唯一的。

  • 即使是僅僅改變輸入數(shù)據(jù)中的一個(gè)字節(jié),也會(huì)導(dǎo)致輸出一個(gè)完全不同的哈希。

本質(zhì)上哈希是一個(gè)摘要算法。

哈希函數(shù)被廣泛用于檢測(cè)數(shù)據(jù)的一致性。軟件提供者常常在除了提供軟件包以外,還會(huì)發(fā)布校驗(yàn)和。當(dāng)下載完一個(gè)文件以后,你可以用哈希函數(shù)對(duì)下載好的文件計(jì)算一個(gè)哈希,并與作者提供的哈希進(jìn)行比較,以此來保證文件下載的完整性。

在區(qū)塊鏈中,哈希被用于保證一個(gè)塊的一致性。哈希算法的輸入數(shù)據(jù)包含了前一個(gè)塊的哈希,因此使得不太可能(或者,至少很困難)去修改鏈中的一個(gè)塊:因?yàn)槿绻粋€(gè)人想要修改前面一個(gè)塊的哈希,那么他必須要重新計(jì)算這個(gè)塊以及后面所有塊的哈希。

Hashcash

比特幣使用 Hashcash ,一個(gè)最初用來防止垃圾郵件的工作量證明算法。它可以被分解為以下步驟:

取一些公開的數(shù)據(jù)(比如,如果是 email 的話,它可以是接收者的郵件地址;在比特幣中,它是區(qū)塊頭)

給這個(gè)公開數(shù)據(jù)添加一個(gè)計(jì)數(shù)器。計(jì)數(shù)器默認(rèn)從 0 開始

將 data(數(shù)據(jù)) 和 counter(計(jì)數(shù)器) 組合到一起,獲得一個(gè)哈希

檢查哈希是否符合一定的條件:

  • 如果符合條件,結(jié)束

  • 如果不符合,增加計(jì)數(shù)器,重復(fù)步驟 3-4

因此,這是一個(gè)暴力算法:改變計(jì)數(shù)器,計(jì)算新的哈希,檢查,增加計(jì)數(shù)器,計(jì)算哈希,檢查,如此往復(fù)。這也是為什么說它的計(jì)算成本很高,因?yàn)檫@一步需要如此反復(fù)不斷地計(jì)算和檢查。

現(xiàn)在,讓我們來仔細(xì)看一下一個(gè)哈希要滿足的必要條件。在原始的 Hashcash 實(shí)現(xiàn)中,它的要求是 “一個(gè)哈希的前 20 位必須是 0”。在比特幣中,這個(gè)要求會(huì)隨著時(shí)間而不斷變化。因?yàn)榘凑赵O(shè)計(jì),必須保證每 10 分鐘生成一個(gè)塊,而不論計(jì)算能力會(huì)隨著時(shí)間增長(zhǎng),或者是會(huì)有越來越多的礦工進(jìn)入網(wǎng)絡(luò),所以需要?jiǎng)討B(tài)調(diào)整這個(gè)必要條件。

為了闡釋這一算法,我從前一個(gè)例子(“I like donuts”)中取得數(shù)據(jù),并且找到了一個(gè)前 3 個(gè)字節(jié)是全是 0 的哈希。

實(shí)現(xiàn)

這里我們實(shí)現(xiàn)一個(gè)簡(jiǎn)易的區(qū)塊鏈,就不動(dòng)態(tài)調(diào)節(jié)難度了,使用固定的難度。

class ProofOfWork(object):
    """
    pow 
    """
    _N_BITS = 16
    MAX_BITS = 256
    MAX_SIZE = sys.maxsize
    def __init__(self, block, n_bits=_N_BITS):
        self._n_bits = n_bits
        self._target_bits = 1 << (self.MAX_BITS - n_bits)
        self._block = block

這里的_n_bits就是難度值。 在比特幣中,當(dāng)一個(gè)塊被挖出來以后,“n_bits” 代表了區(qū)塊頭里存儲(chǔ)的難度,也就是開頭有多少個(gè) 0。這里的 16 指的是算出來的哈希前 16 位必須是 0,如果用 16 進(jìn)制表示,就是前 6 位必須是 0,這一點(diǎn)從最后的輸出可以看出來。目前我們并不會(huì)實(shí)現(xiàn)一個(gè)動(dòng)態(tài)調(diào)整目標(biāo)的算法,所以將難度定義為一個(gè)全局的常量即可。

16 其實(shí)是一個(gè)可以任意取的數(shù)字,其目的只是為了有一個(gè)目標(biāo)而已,這個(gè)目標(biāo)占據(jù)不到 256 位的內(nèi)存空間。同時(shí),我們想要有足夠的差異性,但是又不至于大的過分,因?yàn)椴町愋栽酱?,就越難找到一個(gè)合適的哈希。這里的
_target_bits則表示滿足要求的最大值,即一個(gè)上界,它是由1左移256-n_bits位來的。計(jì)算出來的哈希只要滿足小于它就滿足條件了。

接下來我們要準(zhǔn)備用于計(jì)算哈希的數(shù)據(jù):

    def _prepare_data(self, nonce):
        data_lst = [str(self._block.block_header.prev_block_hash),
                    str(self._block.block_header.hash_merkle_root),
                    str(self._block.block_header.timestamp),
                    str(self._block.block_header.height),
                    str(nonce)]
        return utils.encode(''.join(data_lst))

nonce就是我們要不斷嘗試要尋找的值,就是上面 Hashcash 所提到的計(jì)數(shù)器,它是一個(gè)密碼學(xué)術(shù)語。其他數(shù)據(jù)都是區(qū)塊頭的數(shù)據(jù)。我們需要把這些數(shù)據(jù)進(jìn)行合并作為計(jì)算哈希的原數(shù)據(jù)。

尋找nonce的方法:

    def run(self):
        nonce = 0
        found = False
        hash_hex = None
        print('Mining a new block')
        while nonce < self.MAX_SIZE:
            data = self._prepare_data(nonce)
            hash_hex = utils.sum256_hex(data)
            hash_val = int(hash_hex, 16)
            sys.stdout.write("try nonce == %d hash_hex == %s \r" % (nonce, hash_hex))
            if (hash_val < self._target_bits):
                found = True
                break
            nonce += 1
        if found: 
            print('Found nonce == %d' % nonce)
        else:
            print('Not Found nonce')
            raise NonceNotFoundError('nonce not found')
        return nonce, hash_hex

為防止溢出,我們要設(shè)定一個(gè)上線為int64的上限。然后我們不斷循環(huán)尋找目標(biāo)值,直到滿足難度要求。當(dāng)然,如果難度設(shè)計(jì)得過高,有可能尋找不到,所以也需要判斷一下。所以我們?cè)傺h(huán)內(nèi)做了一下事:

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

2. 用 SHA-256 對(duì)數(shù)據(jù)進(jìn)行哈希

3. 將哈希轉(zhuǎn)換成一個(gè)大整數(shù)

4. 將這個(gè)大整數(shù)與目標(biāo)進(jìn)行比較

然后我們還需要很方便的去檢驗(yàn)這個(gè)塊的難度值是否滿足我們的要求:

    def validate(self):
        """
        validate the block
        """
        data = self._prepare_data(self._block.block_header.nonce)
        hash_hex = utils.sum256_hex(data)
        hash_val = int(hash_hex, 16)
        return hash_val < self._target_bits

最后運(yùn)行以前的main.py,結(jié)果如下:

Mining a new block
...
...
...
Block(_block_header=BlockHeader(timestamp='1548213145.24', hash_merkle_root='', prev_block_hash='', hash='00008fbcbe3a817641195652d9bad37fa8c974536f152f4bc575b3ead9dc6407', nonce=62489, height=0))Block(_block_header=BlockHeader(timestamp='1548213166.65', hash_merkle_root='', prev_block_hash='00008fbcbe3a817641195652d9bad37fa8c974536f152f4bc575b3ead9dc6407', hash='9e851f78295e7933cd9749f712d1f09f1408dff9bd37cc2f79f1c65d1ab39e2e', nonce=16184, height=1))Block(_block_header=BlockHeader(timestamp='1548213171.15', hash_merkle_root='', prev_block_hash='9e851f78295e7933cd9749f712d1f09f1408dff9bd37cc2f79f1c65d1ab39e2e', hash='f88e7a382dafc50b01c43cbbdbbdfa20ac2bffcf5ddf36b97439ff09203f8c2a', nonce=8286, height=2))

可以看到這次我們產(chǎn)生三個(gè)塊花費(fèi)了25秒多,比沒有工作量證明之前慢了很多(也就是成本高了很多)。

到此,相信大家對(duì)“python區(qū)塊鏈如何實(shí)現(xiàn)簡(jiǎn)版工作量證明”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI