python區(qū)塊鏈基本原型簡版實現(xiàn)示例
說明
本文根據(jù)https://github.com/liuchengxu/blockchain-tutorial的內(nèi)容,用python實現(xiàn)的,但根據(jù)個人的理解進行了一些修改,大量引用了原文的內(nèi)容。文章末尾有"本節(jié)完整源碼實現(xiàn)地址"。
引言
區(qū)塊鏈是 21 世紀最具革命性的技術(shù)之一,它仍然處于不斷成長的階段,而且還有很多潛力尚未顯現(xiàn)。 本質(zhì)上,區(qū)塊鏈只是一個分布式數(shù)據(jù)庫而已。 不過,使它獨一無二的是,區(qū)塊鏈是一個公開的數(shù)據(jù)庫,而不是一個私人數(shù)據(jù)庫,也就是說,每個使用它的人都有一個完整或部分的副本。 只有經(jīng)過其他“數(shù)據(jù)庫管理員”的同意,才能向數(shù)據(jù)庫中添加新的記錄。 此外,也正是由于區(qū)塊鏈,才使得加密貨幣和智能合約成為現(xiàn)實。
在本系列文章中,我們將實現(xiàn)一個簡化版的區(qū)塊鏈,并基于它來構(gòu)建一個簡化版的加密貨幣。
區(qū)塊
首先從 “區(qū)塊” 談起。在區(qū)塊鏈中,真正存儲有效信息的是區(qū)塊(block)。而在比特幣中,真正有價值的信息就是交易(transaction)。實際上,交易信息是所有加密貨幣的價值所在。除此以外,區(qū)塊還包含了一些技術(shù)實現(xiàn)的相關(guān)信息,比如版本,當前時間戳和前一個區(qū)塊的哈希。
不過,我們要實現(xiàn)的是一個簡化版的區(qū)塊鏈,而不是一個像比特幣技術(shù)規(guī)范所描述那樣成熟完備的區(qū)塊鏈。所以在我們目前的實現(xiàn)中,區(qū)塊僅包含了部分關(guān)鍵信息,它的數(shù)據(jù)結(jié)構(gòu)如下:
class Block(object):
"""A Block
Attributes:
_magic_no (int): Magic number
_block_header (Block): Header of the previous Block.
_transactions (Transaction): transactions of the current Block.
"""
MAGIC_NO = 0xBCBCBCBC
def __init__(self, block_header, transactions):
self._magic_no = self.MAGIC_NO
self._block_header = block_header
self._transactions = transactions
| 字段 | 解釋 |
|---|---|
| _magic_no | 魔數(shù) |
| _block_header | 區(qū)塊頭 |
| _transactions | 交易 |
這里的_magic_no, _block_header, _transactions, 也是比特幣區(qū)塊的構(gòu)成部分,這里我們簡化了一部分信息。在真正的比特幣中,區(qū)塊 的數(shù)據(jù)結(jié)構(gòu)如下:
| Field | Description | Size |
|---|---|---|
| Magic no | value always 0xD9B4BEF9 | 4 bytes |
| Blocksize | number of bytes following up to end of block | 4 bytes |
| Blockheader | consists of 6 items | 80 bytes |
| Transaction counter | positive integer VI = VarInt | 1 - 9 bytes |
| transactions | the (non empty) list of transactions | -many transactions |
區(qū)塊頭
class BlockHeader(object):
""" A BlockHeader
Attributes:
timestamp (str): Creation timestamp of Block
prev_block_hash (str): Hash of the previous Block.
hash (str): Hash of the current Block.
hash_merkle_root(str): Hash of the merkle_root.
height (int): Height of Block
nonce (int): A 32 bit arbitrary random number that is typically used once.
"""
def __init__(self, hash_merkle_root, height, pre_block_hash=''):
self.timestamp = str(time.time())
self.prev_block_hash = pre_block_hash
self.hash = None
self.hash_merkle_root = hash_merkle_root
self.height = height
self.nonce = None
| 字段 | 解釋 |
|---|---|
| timestamp | 當前時間戳,也就是區(qū)塊創(chuàng)建的時間 |
| prev_block_hash | 前一個塊的哈希,即父哈希 |
| hash | 當前塊頭的哈希 |
| hash_merkle_root | 區(qū)塊存儲的交易的merkle樹的根哈希 |
我們這里的 timestamp,prev_block_hash, Hash,hash_merkle_root, 在比特幣技術(shù)規(guī)范中屬于區(qū)塊頭(block header),區(qū)塊頭是一個單獨的數(shù)據(jù)結(jié)構(gòu)。
完整的 比特幣的區(qū)塊頭(block header)結(jié)構(gòu) 如下:
| Field | Purpose | Updated when… | Size (Bytes) |
|---|---|---|---|
| Version | Block version number | You upgrade the software and it specifies a new version | 4 |
| hashPrevBlock | 256-bit hash of the previous block header | A new block comes in | 32 |
| hashMerkleRoot | 256-bit hash based on all of the transactions in the block | A transaction is accepted | 32 |
| Time | Current timestamp as seconds since 1970-01-01T00:00 UTC | Every few seconds | 4 |
| Bits | Current target in compact format | The difficulty is adjusted | 4 |
| Nonce | 32-bit number (starts at 0) | A hash is tried (increments) | 4 |
我們的簡化版的區(qū)塊頭里,hash和hash_merkle_root是需要計算的。hash_merkle_root暫且不管留空,它是由區(qū)塊中的交易信息生成的merkle樹的根哈希。
而hash的計算如下:
def set_hash(self):
"""
Set hash of the header
"""
data_list = [str(self.timestamp),
str(self.prev_block_hash),
str(self.hash_merkle_root),
str(self.height),
str(self.nonce)]
data = ''.join(data_list)
self.hash = sum256_hex(data)
區(qū)塊鏈
有了區(qū)塊,下面讓我們來實現(xiàn)區(qū)塊鏈。本質(zhì)上,區(qū)塊鏈就是一個有著特定結(jié)構(gòu)的數(shù)據(jù)庫,是一個有序,每一個塊都連接到前一個塊的鏈表。也就是說,區(qū)塊按照插入的順序進行存儲,每個塊都與前一個塊相連。這樣的結(jié)構(gòu),能夠讓我們快速地獲取鏈上的最新塊,并且高效地通過哈希來檢索一個塊。
class BlockChain(object):
def __init__(self):
self.blocks = []
這就是我們的第一個區(qū)塊鏈!就是一個list。
我們還需要一個添加區(qū)塊的函數(shù):
def add_block(self, transactions):
"""
add a block to block_chain
"""
last_block = self.blocks[-1]
prev_hash = last_block.get_header_hash()
height = len(self.blocks)
block_header = BlockHeader('', height, prev_hash)
block = Block(block_header, transactions)
block.set_header_hash()
self.blocks.append(block)
為了加入一個新的塊,我們必須要有一個已有的塊,但是,初始狀態(tài)下,我們的鏈是空的,一個塊都沒有!所以,在任何一個區(qū)塊鏈中,都必須至少有一個塊。這個塊,也就是鏈中的第一個塊,通常叫做創(chuàng)世塊(genesis block). 讓我們實現(xiàn)一個方法來創(chuàng)建創(chuàng)世塊:
# class BlockChain
def new_genesis_block(self):
if not self.blocks:
genesis_block = Block.new_genesis_block('genesis_block')
genesis_block.set_header_hash()
self.blocks.append(genesis_block)
# class Block
@classmethod
def new_genesis_block(cls, coin_base_tx):
block_header = BlockHeader.new_genesis_block_header()
return cls(block_header, coin_base_tx)
# class BlockHeader
@classmethod
def new_genesis_block_header(cls):
"""
NewGenesisBlock creates and returns genesis Block
"""
return cls('', 0, '')
上面分別對應(yīng)三個函數(shù)分別對應(yīng)鏈中創(chuàng)世塊生成,創(chuàng)世塊生成,和創(chuàng)世塊頭的生成。
創(chuàng)世塊高度為0。這里我們暫時還沒有交易類,交易暫時用字符串代替。prev_block_hash和hash_merkle_root都暫時留空。
讓BlockChain支持迭代
# class BlockChain
def __getitem__(self, index):
if index < len(self.blocks):
return self.blocks[index]
else:
raise IndexError('Index is out of range')
最后再進行簡單的測試:
def main():
bc = BlockChain()
bc.new_genesis_block()
bc.add_block('Send 1 BTC to B')
bc.add_block('Send 2 BTC to B')
for block in bc:
print(block)
if __name__ == "__main__":
main()
輸出:
Block(_block_header=BlockHeader(timestamp='1548150457.22', hash_merkle_root='', prev_block_hash='', hash='f91f638a9a2b4caf241112d3bc92c9168cc9d52207a5580b3a549ed5343e2ed3', nonce=None, height=0)) Block(_block_header=BlockHeader(timestamp='1548150457.22', hash_merkle_root='', prev_block_hash='f91f638a9a2b4caf241112d3bc92c9168cc9d52207a5580b3a549ed5343e2ed3', hash='d21570e36f0c6f75c112d98416ca4ffae14e5cf02492bea5a7f8c398c1d458ca', nonce=None, height=1)) Block(_block_header=BlockHeader(timestamp='1548150457.22', hash_merkle_root='', prev_block_hash='d21570e36f0c6f75c112d98416ca4ffae14e5cf02492bea5a7f8c398c1d458ca', hash='9c78f38ec78a0d492a27e69ab04a3e0ba07d70d31a1ef96d581e8198d9781bc0', nonce=None, height=2))
總結(jié)
我們創(chuàng)建了一個非常簡單的區(qū)塊鏈原型:它僅僅是一個數(shù)組構(gòu)成的一系列區(qū)塊,每個塊都與前一個塊相關(guān)聯(lián)。真實的區(qū)塊鏈要比這復(fù)雜得多。在我們的區(qū)塊鏈中,加入新的塊非常簡單,也很快,但是在真實的區(qū)塊鏈中,加入新的塊需要很多工作:你必須要經(jīng)過十分繁重的計算(這個機制叫做工作量證明),來獲得添加一個新塊的權(quán)力。并且,區(qū)塊鏈是一個分布式數(shù)據(jù)庫,并且沒有單一決策者。因此,要加入一個新塊,必須要被網(wǎng)絡(luò)的其他參與者確認和同意(這個機制叫做共識(consensus))。還有一點,我們的區(qū)塊鏈還沒有任何的交易!
參考:
[1] basic-prototype
[2] 完整實現(xiàn)源碼
以上就是python區(qū)塊鏈基本原型簡版實現(xiàn)示例的詳細內(nèi)容,更多關(guān)于python區(qū)塊鏈基本原型的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python自動化測試中裝飾器@ddt與@data源碼深入解析
最近工作中接觸了python自動化測試,所以下面這篇文章主要給大家介紹了關(guān)于python自動化測試中裝飾器@ddt與@data源碼解析的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-12-12
typing.Dict和Dict的區(qū)別及它們在Python中的用途小結(jié)
當在 Python 函數(shù)中聲明一個 dictionary 作為參數(shù)時,我們一般會把 key 和 value 的數(shù)據(jù)類型聲明為全局變量,而不是局部變量。,這篇文章主要介紹了typing.Dict和Dict的區(qū)別及它們在Python中的用途小結(jié),需要的朋友可以參考下2023-06-06
Python用requests-html爬取網(wǎng)頁的實現(xiàn)
本文主要介紹了Python用requests-html爬取網(wǎng)頁的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07
Python?OpenCV超詳細講解調(diào)整大小與圖像操作的實現(xiàn)
OpenCV用C++語言編寫,它具有C?++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac?OS,OpenCV主要傾向于實時視覺應(yīng)用,并在可用時利用MMX和SSE指令,本篇文章帶你通過OpenCV實現(xiàn)重調(diào)大小與圖像裁剪2022-04-04
用python生成(動態(tài)彩色)二維碼的方法(使用myqr庫實現(xiàn))
今天小編就為大家分享一篇用python生成(動態(tài)彩色)二維碼的方法(使用myqr庫實現(xiàn)),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06

