欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python區(qū)塊鏈持久化和命令行接口實(shí)現(xiàn)簡(jiǎn)版

 更新時(shí)間:2022年05月31日 10:09:12   作者:曉彬_  
這篇文章主要為大家介紹了python區(qū)塊鏈持久化和命令行接口實(shí)現(xiàn)簡(jiǎn)版,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

說(shuō)明

本文根據(jù)https://github.com/liuchengxu/blockchain-tutorial的內(nèi)容,用python實(shí)現(xiàn)的,但根據(jù)個(gè)人的理解進(jìn)行了一些修改,大量引用了原文的內(nèi)容。文章末尾有"本節(jié)完整源碼實(shí)現(xiàn)地址"。

引言

到目前為止,我們已經(jīng)構(gòu)建了一個(gè)有工作量證明機(jī)制的區(qū)塊鏈。有了工作量證明,挖礦也就有了著落。雖然目前距離一個(gè)有著完整功能的區(qū)塊鏈越來(lái)越近了,但是它仍然缺少了一些重要的特性。在今天的內(nèi)容中,我們會(huì)將區(qū)塊鏈持久化到一個(gè)數(shù)據(jù)庫(kù)中,然后會(huì)提供一個(gè)簡(jiǎn)單的命令行接口,用來(lái)完成一些與區(qū)塊鏈的交互操作。本質(zhì)上,區(qū)塊鏈?zhǔn)且粋€(gè)分布式數(shù)據(jù)庫(kù),不過(guò),我們暫時(shí)先忽略 “分布式” 這個(gè)部分,僅專注于 “存儲(chǔ)” 這一點(diǎn)。

選擇數(shù)據(jù)庫(kù)

目前,我們的區(qū)塊鏈實(shí)現(xiàn)里面并沒(méi)有用到數(shù)據(jù)庫(kù),而是在每次運(yùn)行程序時(shí),簡(jiǎn)單地將區(qū)塊鏈存儲(chǔ)在內(nèi)存中。那么一旦程序退出,所有的內(nèi)容就都消失了。我們沒(méi)有辦法再次使用這條鏈,也沒(méi)有辦法與其他人共享,所以我們需要把它存儲(chǔ)到磁盤(pán)上。

那么,我們要用哪個(gè)數(shù)據(jù)庫(kù)呢?實(shí)際上,任何一個(gè)數(shù)據(jù)庫(kù)都可以。在 比特幣原始論文 中,并沒(méi)有提到要使用哪一個(gè)具體的數(shù)據(jù)庫(kù),它完全取決于開(kāi)發(fā)者如何選擇。 Bitcoin Core ,最初由中本聰發(fā)布,現(xiàn)在是比特幣的一個(gè)參考實(shí)現(xiàn),它使用的是 LevelDB。而我們將要使用的是…

couchdb

因?yàn)樗?

  • 簡(jiǎn)單易用
  • 有一個(gè)web的UI界面,方便我們查看
  • 豐富的查詢支持
  • 良好的python支持

couchdb的安裝

直接安裝,參考http://www.dbjr.com.cn/article/202914.htm

docker版couchdb安裝,使用docker-compose安裝couchdb

# couchdb.yaml
version: '2'
services:
  couchdb:
    image: hyperledger/fabric-couchdb
    ports:
    - 5984:5984

執(zhí)行docker-compose -f couchdb.yaml up -d即可安裝。
使用http://ip:5984/_utils即可訪問(wèn)couchdb的后臺(tái)管理系統(tǒng)。

數(shù)據(jù)庫(kù)結(jié)構(gòu)

在開(kāi)始實(shí)現(xiàn)持久化的邏輯之前,我們首先需要決定到底要如何在數(shù)據(jù)庫(kù)中進(jìn)行存儲(chǔ)。為此,我們可以參考 Bitcoin Core 的做法:

簡(jiǎn)單來(lái)說(shuō),Bitcoin Core 使用兩個(gè) “bucket” 來(lái)存儲(chǔ)數(shù)據(jù):

  • 其中一個(gè) bucket 是 blocks,它存儲(chǔ)了描述一條鏈中所有塊的元數(shù)據(jù)
  • 另一個(gè) bucket 是 chainstate,存儲(chǔ)了一條鏈的狀態(tài),也就是當(dāng)前所有的未花費(fèi)的交易輸出,和一些元數(shù)據(jù)

此外,出于性能的考慮,Bitcoin Core 將每個(gè)區(qū)塊(block)存儲(chǔ)為磁盤(pán)上的不同文件。如此一來(lái),就不需要僅僅為了讀取一個(gè)單一的塊而將所有(或者部分)的塊都加載到內(nèi)存中。而我們直接使用couchdb。

在 blocks 中,key -> value 為:

keyvalue
b + 32 字節(jié)的 block hashblock index record
f + 4 字節(jié)的 file numberfile information record
l + 4 字節(jié)的 file numberthe last block file number used
R + 1 字節(jié)的 boolean是否正在 reindex
F + 1 字節(jié)的 flag name length + flag name string1 byte boolean: various flags that can be on or off
t + 32 字節(jié)的 transaction hashtransaction index record

在 chainstate,key -> value 為:

keyvalue
c + 32 字節(jié)的 transaction hashunspent transaction output record for that transaction
B32 字節(jié)的 block hash: the block hash up to which the database represents the unspent transaction outputs

詳情可見(jiàn) 這里。

因?yàn)槟壳斑€沒(méi)有交易,所以我們只需要 blocks bucket。另外,正如上面提到的,我們會(huì)將整個(gè)數(shù)據(jù)庫(kù)存儲(chǔ)為單個(gè)文件,而不是將區(qū)塊存儲(chǔ)在不同的文件中。所以,我們也不會(huì)需要文件編號(hào)(file number)相關(guān)的東西。最終,我們會(huì)用到的鍵值對(duì)有:

  • 32 字節(jié)的 block-hash(轉(zhuǎn)換為16進(jìn)制字符串) -> block 結(jié)構(gòu)
  • l -> 鏈中最后一個(gè)塊的 hash(轉(zhuǎn)換為16進(jìn)制字符串)

這就是實(shí)現(xiàn)持久化機(jī)制所有需要了解的內(nèi)容了。

序列化

為了方便我們查看,這里我們不直接使用二進(jìn)制數(shù)據(jù),而將其轉(zhuǎn)換為16進(jìn)制字符串。所以我們需要對(duì)區(qū)塊內(nèi)容進(jìn)行序列化。

讓我們來(lái)實(shí)現(xiàn) Block 的 Serialize 方法:

    # class Block
    def serialize(self):
        return {
            "magic_no": self._magic_no,
            "block_header": self._block_header.serialize(),
            "transactions": self._transactions
        }

直接返回我們需要的數(shù)據(jù)構(gòu)成的字典即可,而block_header則需要進(jìn)一步序列化。它的序列化同樣也只需要返回具體的數(shù)據(jù)字典即可,如下:

    # class BlockHeader
    def serialize(self):
        return self.__dict__

反序列化則是把信息轉(zhuǎn)換為區(qū)塊對(duì)象。

# class Block
    @classmethod
    def deserialize(cls, data):
        block_header_dict = data['block_header']
        block_header = BlockHeader.deserialize(block_header_dict)
        transactions = data["transactions"]
        return cls(block_header, transactions)

首先反序列化塊,然后構(gòu)造成一個(gè)對(duì)象,反序列化Header:

# class BlockHeader
    @classmethod
    def deserialize(cls, data):
        timestamp = data.get('timestamp', '')
        prev_block_hash = data.get('pre_block_hash', '')
        # hash = data.get('hash', '')
        hash_merkle_root = data.get('hash_merkle_root', '')
        height = data.get('height', '')
        nonce = data.get('nonce', '')
        block_header = cls(hash_merkle_root, height, prev_block_hash)
        block_header.timestamp = timestamp
        block_header.nonce = nonce
        return block_header

持久化

持久化要做的事情就是把區(qū)塊數(shù)據(jù)寫(xiě)入到數(shù)據(jù)庫(kù)中,則我們要做的事情有:

  • 檢查數(shù)據(jù)庫(kù)是否已經(jīng)有了一個(gè)區(qū)塊鏈
  • 如果沒(méi)有則創(chuàng)建一個(gè),創(chuàng)建創(chuàng)世塊并將l指向這個(gè)塊的哈希
  • 添加一個(gè)區(qū)塊,將l指向新添加的區(qū)塊哈希

創(chuàng)建創(chuàng)世塊如下:

# class BlockChain:
    def new_genesis_block(self):
        if 'l' not in self.db:
            genesis_block = Block.new_genesis_block('genesis_block')
            genesis_block.set_header_hash()
            self.db.create(genesis_block.block_header.hash, genesis_block.serialize())
            self.set_last_hash(genesis_block.block_header.hash)

添加一個(gè)區(qū)塊如下:

    def add_block(self, transactions):
        """
        add a block to block_chain
        """
        last_block = self.get_last_block()
        prev_hash = last_block.get_header_hash()
        height = last_block.block_header.height + 1
        block_header = BlockHeader('', height, prev_hash)
        block = Block(block_header, transactions)
        block.mine()
        block.set_header_hash()
        self.db.create(block.block_header.hash, block.serialize())
        last_hash = block.block_header.hash
        self.set_last_hash(last_hash)

對(duì)couchdb的操作的簡(jiǎn)單封裝如下:

class DB(Singleton):
    def __init__(self, db_server_url, db_name='block_chain'):
        self._db_server_url = db_server_url
        self._server = couchdb.Server(self._db_server_url)
        self._db_name = db_name
        self._db = None
    @property
    def db(self):
        if not self._db:
            try:
                self._db = self._server[self._db_name]
            except couchdb.ResourceNotFound:
                self._db = self._server.create(self._db_name)
        return self._db
    def create(self, id, data):
        self.db[id] = data
        return id
    def __getattr__(self, name):
        return getattr(self.db, name)
    def __contains__(self, name):
        return self.db.__contains__(name)
    def __getitem__(self, key):
        return self.db[key]
    def __setitem__(self, key, value):
        self.db[key] = value

區(qū)塊鏈迭代器

由于我們現(xiàn)在使用了數(shù)據(jù)庫(kù)存儲(chǔ),不再是數(shù)組,那么我們便失去了迭代打印區(qū)塊鏈的特性,我們需要重寫(xiě)__getitem__以獲得該特性,實(shí)現(xiàn)如下:

# class BlockChain(object):
    def __getitem__(self, index):
        last_block = self.get_last_block()
        height = last_block.block_header.height
        if index <= height:
            return self.get_block_by_height(index)
        else:
            raise IndexError('Index is out of range')
# class BlockChain(object):
    def get_block_by_height(self, height):
        """
        Get a block by height
        """
        query = {"selector": {"block_header": {"height": height}}}
        docs = self.db.find(query)
        block = Block(None, None)
        for doc in docs:
            block.deserialize(doc)
            break
        return block

根據(jù)區(qū)塊高度獲取對(duì)應(yīng)的區(qū)塊,此處是利用了couchdb的mongo_query的富查詢來(lái)實(shí)現(xiàn)。

CLI

到目前為止,我們的實(shí)現(xiàn)還沒(méi)有提供一個(gè)與程序交互的接口。是時(shí)候加上交互了:
這里我們使用argparse來(lái)解析參數(shù):

def new_parser():
    parser = argparse.ArgumentParser()
    sub_parser = parser.add_subparsers(help='commands')
    # A print command
    print_parser = sub_parser.add_parser(
        'print', help='Print all the blocks of the blockchain')
    print_parser.add_argument('--print', dest='print', action='store_true')
    # A add command
    add_parser = sub_parser.add_parser(
        'addblock', help='Print all the blocks of the blockchain')
    add_parser.add_argument(
        '--data', type=str, dest='add_data', help='block data')
    return parser
def print_chain(bc):
    for block in bc:
        print(block)
def add_block(bc, data):
    bc.add_block(data)
    print("Success!")
def main():
    parser = new_parser()
    args = parser.parse_args()
    bc = BlockChain()
    if hasattr(args, 'print'):
        print_chain(bc)
    if hasattr(args, 'add_data'):
        add_block(bc, args.add_data)
if __name__ == "__main__":
    main()

測(cè)試一下

# 創(chuàng)世塊創(chuàng)建
$python3 main.py
Mining a new block
Found nonce == 19ash_hex == 047f213bcb01f1ffbcdfafad57ffeead0e86924cf439594020da47ff2508291c
<Document 'l'@'191-2f44a1493638684d9e000d8dd105192a' {'hash': 'e4f7adac65bcbb304af21be52a1b52bb28c0205a3746d63453d9e8c182de927a'}>
Mining a new block
Found nonce == 1ash_hex == 0df1ac18c84a8e524d6fe49cb04aae9af02dd85addc4ab21ac13f9d0d7ffe769
<Document 'l'@'192-168ff7ea493ca53c66690985deb5b7ac' {'hash': '01015004e21d394b1a6574eb81896e1c800f18aa22997e96b79bca22f7821a67'}>
Block(_block_header=BlockHeader(timestamp='1551317137.2814202', hash_merkle_root='', prev_block_hash='', hash='f20f3c74c831d03aaa2291af23e607896a61809b5ced222483b46795a456a1c5', nonce=None, height=0))
Block(_block_header=BlockHeader(timestamp='1551317137.358466', hash_merkle_root='', prev_block_hash='f20f3c74c831d03aaa2291af23e607896a61809b5ced222483b46795a456a1c5', hash='e4f7adac65bcbb304af21be52a1b52bb28c0205a3746d63453d9e8c182de927a', nonce=19, height=1))
Block(_block_header=BlockHeader(timestamp='1551317137.4621542', hash_merkle_root='', prev_block_hash='e4f7adac65bcbb304af21be52a1b52bb28c0205a3746d63453d9e8c182de927a', hash='01015004e21d394b1a6574eb81896e1c800f18aa22997e96b79bca22f7821a67', nonce=1, height=2))
$python3 cli.py addblock --data datas
Mining a new block
Found nonce == 6ash_hex == 0864df4bfbb2fd115eeacfe9ff4d5813754198ba261c469000c29b74a1b391c5
<Document 'l'@'193-92e02b894d09dcd64f8284f141775920' {'hash': '462ac519b6050acaa78e1be8c2c8de298b713a2e138d7139fc882f7ae58dcc88'}>
Success!

一切正常工作。

參考:
[1] persistence-and-cli

[2] 完整實(shí)現(xiàn)源碼

以上就是python區(qū)塊鏈持久化和命令行接口實(shí)現(xiàn)簡(jiǎn)版的詳細(xì)內(nèi)容,更多關(guān)于區(qū)塊鏈持久化命令行接口的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • numpy中np.c_和np.r_的用法解析

    numpy中np.c_和np.r_的用法解析

    本文主要介紹了numpy中np.c_和np.r_的用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Python使用re模塊實(shí)現(xiàn)正則表達(dá)式操作指南

    Python使用re模塊實(shí)現(xiàn)正則表達(dá)式操作指南

    在Python中需要通過(guò)正則表達(dá)式對(duì)字符串進(jìn)?匹配的時(shí)候,可以使??個(gè)python自帶的模塊,名字為re,下面這篇文章主要給大家介紹了關(guān)于Python使用re模塊實(shí)現(xiàn)正則表達(dá)式操作的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Python爬蟲(chóng)基礎(chǔ)之XPath語(yǔ)法與lxml庫(kù)的用法詳解

    Python爬蟲(chóng)基礎(chǔ)之XPath語(yǔ)法與lxml庫(kù)的用法詳解

    這篇文章主要給大家介紹了關(guān)于Python爬蟲(chóng)基礎(chǔ)之XPath語(yǔ)法與lxml庫(kù)用法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • python ForMaiR實(shí)現(xiàn)自定義規(guī)則的郵件自動(dòng)轉(zhuǎn)發(fā)工具

    python ForMaiR實(shí)現(xiàn)自定義規(guī)則的郵件自動(dòng)轉(zhuǎn)發(fā)工具

    這篇文章主要為大家介紹了python ForMaiR實(shí)現(xiàn)自定義規(guī)則的郵件自動(dòng)轉(zhuǎn)發(fā)工具示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • OpenCV 圖像旋轉(zhuǎn)、平移、縮放操作代碼

    OpenCV 圖像旋轉(zhuǎn)、平移、縮放操作代碼

    這篇文章主要介紹了OpenCV 圖像旋轉(zhuǎn)、平移、縮放,本文是 OpenCV圖像視覺(jué)入門(mén)之路的第7篇文章,本文詳細(xì)的進(jìn)行了圖像的縮放 cv2.resize()、旋轉(zhuǎn) cv2.flip()、平移 cv2.warpAffine()等操作,需要的朋友可以參考下
    2022-12-12
  • pytorch nn.Conv2d()中的padding以及輸出大小方式

    pytorch nn.Conv2d()中的padding以及輸出大小方式

    今天小編就為大家分享一篇pytorch nn.Conv2d()中的padding以及輸出大小方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-01-01
  • python中eval與int的區(qū)別淺析

    python中eval與int的區(qū)別淺析

    這篇文章主要給大家介紹了關(guān)于python中eval與int的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 教你用python編寫(xiě)腳本實(shí)現(xiàn)自動(dòng)簽到

    教你用python編寫(xiě)腳本實(shí)現(xiàn)自動(dòng)簽到

    這篇文章主要介紹了教你怎樣用python編寫(xiě)腳本實(shí)現(xiàn)自動(dòng)簽到,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • PyQt5主窗口動(dòng)態(tài)加載Widget實(shí)例代碼

    PyQt5主窗口動(dòng)態(tài)加載Widget實(shí)例代碼

    這篇文章主要介紹了PyQt5主窗口動(dòng)態(tài)加載Widget實(shí)例代碼,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • Python中模塊string.py詳解

    Python中模塊string.py詳解

    這篇文章主要介紹了Python中模塊之string.py的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-03-03

最新評(píng)論