日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python timestamp转string_Python仿真区块链【含源码】

發(fā)布時(shí)間:2025/3/19 python 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python timestamp转string_Python仿真区块链【含源码】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在區(qū)塊鏈或數(shù)字貨幣領(lǐng)域,Python并不是主流的開發(fā)語(yǔ)言。但是如果 你的目的是研究區(qū)塊鏈技術(shù)的原理,或者需要在自己的筆記本上仿真一個(gè) 區(qū)塊鏈網(wǎng)絡(luò)并進(jìn)行一些研究性的實(shí)驗(yàn),比如完成自己的畢業(yè)設(shè)計(jì)項(xiàng)目 或科研課題,那么Python就是合適的。在這個(gè)教程里,我們將學(xué)習(xí)如何 使用Python從零開發(fā)一個(gè)多節(jié)點(diǎn)的區(qū)塊鏈網(wǎng)絡(luò),并基于這個(gè)仿真區(qū)塊鏈網(wǎng)絡(luò), 開發(fā)一個(gè)去中心化的數(shù)據(jù)分享應(yīng)用。

相關(guān)教程鏈接: 區(qū)塊鏈畢業(yè)論文 | 以太坊 | 比特幣 | EOS | Tendermint | Hyperledger Fabric | Omni/USDT | Ripple

1、Python仿真區(qū)塊鏈:用區(qū)塊分批保存交易

我們首先要把數(shù)據(jù)以JSON格式存入?yún)^(qū)塊鏈。JSON是一種常用的跨語(yǔ)言的 數(shù)據(jù)交換格式,例如一篇博客的JSON表示看起來(lái)就像這樣:

{ "author": "some_author_name", "content": "Some thoughts that author wants to share", "timestamp": "The time at which the content was created"}

在區(qū)塊鏈領(lǐng)域,我們經(jīng)常使用 交易 來(lái)代替上面說(shuō)到的數(shù)據(jù)。因此,為了 避免引起混亂并保持一致,在這個(gè)教程里我們將使用 交易 這個(gè)術(shù)語(yǔ) 來(lái)表示要存入?yún)^(qū)塊鏈的數(shù)據(jù)。

交易被分批打包進(jìn)區(qū)塊,一個(gè)區(qū)塊可以包含一個(gè)或多個(gè)交易。包含交易的區(qū)塊會(huì) 定期生成并加入?yún)^(qū)塊鏈。因?yàn)闀?huì)有很多區(qū)塊,所以每個(gè)區(qū)塊都應(yīng)當(dāng)有一個(gè)唯一 的ID。下面是我們的Python仿真區(qū)塊鏈的Block類定義代碼:

class Block: def __init__(self, index, transactions, timestamp): """ Constructor for the `Block` class. :param index: Unique ID of the block. :param transactions: List of transactions. :param timestamp: Time of generation of the block. """ self.index = index self.transactions = transactions self.timestamp = timestamp

2、Python仿真區(qū)塊鏈:為區(qū)塊添加抗篡改的數(shù)字指紋

區(qū)塊鏈的一個(gè)特點(diǎn)就是存儲(chǔ)在區(qū)塊中的交易不可篡改,為了實(shí)現(xiàn)這個(gè)特性, 首先需要能夠檢測(cè)出區(qū)塊數(shù)據(jù)被篡改。為此目的,我們需要使用密碼學(xué)中 的哈希(Hash)函數(shù)。

哈希函數(shù)可以把任意大小的輸入數(shù)據(jù)轉(zhuǎn)換為固定大小的輸出數(shù)據(jù),也就是 數(shù)據(jù)的哈希,而且不同的輸入數(shù)據(jù)(基本上)會(huì)得到不同的輸出數(shù)據(jù),因此 可以使用輸出的哈希作為輸入數(shù)據(jù)的標(biāo)識(shí)。一個(gè)理想的哈希函數(shù)具有如下 特點(diǎn):

  • 應(yīng)當(dāng)易于計(jì)算
  • 應(yīng)當(dāng)是確定性的,對(duì)于相同的輸入數(shù)據(jù)總是生成相同的哈希
  • 應(yīng)當(dāng)具有均勻隨機(jī)性,輸入數(shù)據(jù)的一點(diǎn)變化也會(huì)導(dǎo)致輸出哈希的顯著改變

這樣我們就可以保證:

  • 從哈希猜測(cè)出輸入數(shù)據(jù)是什么基本是不可能的,唯一的辦法是嘗試所有可能的組合
  • 如果同時(shí)知道輸入和輸出,那么你可以通過簡(jiǎn)單地重算來(lái)驗(yàn)證哈希是否正確

顯然,從輸入數(shù)據(jù)推導(dǎo)出哈希很簡(jiǎn)單,然而從哈希推導(dǎo)出輸入數(shù)據(jù)則是幾乎 不可能的,這一非對(duì)稱性值就是區(qū)塊鏈用來(lái)獲取期望的抗篡改能力的關(guān)鍵。

目前有很多流行的哈希函數(shù),下面是一個(gè)使用SHA-256哈希函數(shù)的Python示例:

>>> from hashlib import sha256>>> data = b"Some variable length data">>> sha256(data).hexdigest()'b919fbbcae38e2bdaebb6c04ed4098e5c70563d2dc51e085f784c058ff208516'>>> sha256(data).hexdigest() # no matter how many times you run it, the result is going to be the same 256 character string'b919fbbcae38e2bdaebb6c04ed4098e5c70563d2dc51e085f784c058ff208516'>>> data = b"Some variable length data2" # Added one character at the end.'9fcaab521baf8e83f07512a7de7a0f567f6eef2688e8b9490694ada0a3ddeec8'

注意在上面的示例中,輸入數(shù)據(jù)的一點(diǎn)變化就得到完全不同的哈希!

在教程的Python仿真區(qū)塊鏈項(xiàng)目中,我們將把區(qū)塊哈希保存為區(qū)塊的一個(gè)字段, 用它作為區(qū)塊數(shù)據(jù)的數(shù)字指紋(Digital Fingerprint),或者說(shuō)簽名(Signature)。

下面是計(jì)算區(qū)塊哈希的Python實(shí)現(xiàn)代碼:

from hashlib import sha256import jsondef compute_hash(block): """ Returns the hash of the block instance by first converting it into JSON string. """ block_string = json.dumps(self.__dict__, sort_keys=True) return sha256(block_string.encode()).hexdigest()

注意:在大多數(shù)數(shù)字加密貨幣實(shí)現(xiàn)中,區(qū)塊中的每個(gè)交易也需要計(jì)算哈希并 利用一個(gè)樹形結(jié)構(gòu)(merkle樹)來(lái)計(jì)算一組交易的根哈希。不過這對(duì)于區(qū)塊鏈 來(lái)說(shuō)并不是必需的,因此我們暫時(shí)忽略這一特性。

3、Python仿真區(qū)塊鏈:將區(qū)塊一個(gè)個(gè)鏈接起來(lái)

好了,現(xiàn)在我們已經(jīng)搞定區(qū)塊類Block的Python實(shí)現(xiàn)了,現(xiàn)在來(lái)看看如何 用Ptyhon實(shí)現(xiàn)區(qū)塊鏈結(jié)構(gòu)。

區(qū)塊鏈就是區(qū)塊的集合,我們可以使用Python列表來(lái)保存所有的區(qū)塊。 不過這還不夠,因?yàn)槿绻腥斯室庥靡粋€(gè)較早的區(qū)塊替換掉集合中的新區(qū)塊 還會(huì)導(dǎo)致數(shù)據(jù)被篡改。

我們需要一個(gè)辦法來(lái)保證對(duì)較早的區(qū)塊的修改會(huì)導(dǎo)致整條區(qū)塊鏈的無(wú)效。 比特幣使用的辦法是讓后面區(qū)塊的哈希依賴于前面較早的區(qū)塊。為將 區(qū)塊鏈接起來(lái),我們需要在區(qū)塊結(jié)構(gòu)中增加一個(gè)新的字段來(lái)保存前一個(gè) 區(qū)塊的哈希:previous_hash。

好了,如果每個(gè)區(qū)塊都通過previous_hash字段鏈接到前一個(gè)區(qū)塊,那么 第一個(gè)區(qū)塊怎么辦?在區(qū)塊鏈領(lǐng)域,第一個(gè)區(qū)塊被稱為創(chuàng)世區(qū)塊(Genesis Block), 可以手工生成創(chuàng)世區(qū)塊或者使用一些特定的邏輯。現(xiàn)在讓我們?yōu)锽lock類 添加previous_hash字段并實(shí)現(xiàn)區(qū)塊鏈結(jié)構(gòu)定義,下面是Blockchain類的 Python實(shí)現(xiàn)代碼:

from hashlib import sha256import jsonimport timeclass Block: def__init__(self, index, transactions, timestamp, previous_hash): """ Constructor for the `Block` class. :param index: Unique ID of the block. :param transactions: List of transactions. :param timestamp: Time of generation of the block. :param previous_hash: Hash of the previous block in the chain which this block is part of. """ self.index = index self.transactions = transactions self.timestamp = timestamp self.previous_hash = previous_hash # Adding the previous hash field def compute_hash(self): """ Returns the hash of the block instance by first converting it into JSON string. """ block_string = json.dumps(self.__dict__, sort_keys=True) # The string equivalent also considers the previous_hash field now return sha256(block_string.encode()).hexdigest()class Blockchain: def __init__(self): """ Constructor for the `Blockchain` class. """ self.chain = [] self.create_genesis_block() def create_genesis_block(self): """ A function to generate genesis block and appends it to the chain. The block has index 0, previous_hash as 0, and a valid hash. """ genesis_block = Block(0, [], time.time(), "0") genesis_block.hash = genesis_block.compute_hash() self.chain.append(genesis_block) @property def last_block(self): """ A quick pythonic way to retrieve the most recent block in the chain. Note that the chain will always consist of at least one block (i.e., genesis block) """ return self.chain[-1]

現(xiàn)在,如果任何較早的區(qū)塊被修改,那么:

  • 該較早區(qū)塊的哈希會(huì)變化
  • 這會(huì)導(dǎo)致與后面區(qū)塊的previous_hash字段記錄的內(nèi)容不一致
  • 由于計(jì)算區(qū)塊哈希的輸入數(shù)據(jù)包含了previous_hash字段的內(nèi)容,因此下一個(gè)區(qū)塊的哈希也會(huì)變化

最終,從被替換掉的區(qū)塊開始的整條鏈都失效了,修復(fù)這一問題的唯一 辦法是重算整條鏈。

4、Python仿真區(qū)塊鏈:實(shí)現(xiàn)工作量證明算法

不過還有一個(gè)問題。如果我們修改了之前的區(qū)塊,如果重算后面的其他 區(qū)塊非常簡(jiǎn)單的話,那么篡改區(qū)塊鏈也不是什么難事了。為了避免這一問題, 我們可以利用前面提到的哈希函數(shù)的非對(duì)稱性來(lái)加大區(qū)塊哈希計(jì)算工作的 難度和隨機(jī)性。我們要做的是:只接受符合特定約束條件的區(qū)塊哈希。 現(xiàn)在讓我們?cè)黾右粋€(gè)約束條件,要求區(qū)塊哈希的開始部分至少有n個(gè)0, 其中n是一個(gè)正整數(shù)。

我們知道,除非改變區(qū)塊數(shù)據(jù)的內(nèi)容,否則區(qū)塊哈希不會(huì)變化,當(dāng)然 我們也不希望修改已有的數(shù)據(jù)。那么我們?cè)撛趺醋?#xff1f;很簡(jiǎn)單!我們?cè)僭黾?一些我們可以隨便修改的數(shù)據(jù)就是了。因此我們需要為Block類增加一個(gè) 新的字段nonce,我們可以通過改變這個(gè)字段的值來(lái)得到不同的區(qū)塊哈希, 直到滿足指定的約束條件,而這時(shí)的nonce值就是我們工作量的證明。

上面的這一過程就是比特幣使用的hashcash算法的簡(jiǎn)化版本。約束條件 中指定的前導(dǎo)0的數(shù)量決定了我們的工作量證明算法的難度:前導(dǎo)0的數(shù)量 越多,就越難找到合適的nonce。

同時(shí),由于哈希函數(shù)的非對(duì)稱性,工作量證明不容易計(jì)算,但是容易進(jìn)行驗(yàn)證。

下面是工作量證明算法(PoW:Proof of Work)的Python實(shí)現(xiàn)代碼:

class Blockchain: # difficulty of PoW algorithm difficulty = 2 """ Previous code contd.. """ def proof_of_work(self, block): """ Function that tries different values of the nonce to get a hash that satisfies our difficulty criteria. """ block.nonce = 0 computed_hash = block.compute_hash() while not computed_hash.startswith('0' * Blockchain.difficulty): block.nonce += 1 computed_hash = block.compute_hash() return computed_hash

需要指出的是,沒有簡(jiǎn)單的邏輯可以快速找到滿足約束條件的nonce值,因此 只能進(jìn)行暴力計(jì)算。

5、Python仿真區(qū)塊鏈:將區(qū)塊加入?yún)^(qū)塊鏈

要將區(qū)塊加入?yún)^(qū)塊鏈,我們首先需要驗(yàn)證:

  • 區(qū)塊中的數(shù)據(jù)沒有被篡改,所提供的工作量證明是正確的
  • 交易的順序是正確的,previous_hash字段指向我們鏈上最新區(qū)塊的哈希

現(xiàn)在讓我們看一下將區(qū)塊上鏈的Python實(shí)現(xiàn)代碼:

class Blockchain: """ Previous code contd.. """ def add_block(self, block, proof): """ A function that adds the block to the chain after verification. Verification includes: * Checking if the proof is valid. * The previous_hash referred in the block and the hash of a latest block in the chain match. """ previous_hash = self.last_block.hash if previous_hash != block.previous_hash: return False if not Blockchain.is_valid_proof(block, proof): return False block.hash = proof self.chain.append(block) return True def is_valid_proof(self, block, block_hash): """ Check if block_hash is valid hash of block and satisfies the difficulty criteria. """ return (block_hash.startswith('0' * Blockchain.difficulty) and block_hash == block.compute_hash())

6、Python仿真區(qū)塊鏈:挖礦

交易一開始是保存在未確認(rèn)交易池中的。將未確認(rèn)交易放入?yún)^(qū)塊并計(jì)算工作量 證明的過程,就是廣為人知的挖礦。一旦找出了滿足指定約束條件的nonce,我們 就可以說(shuō)挖出了一個(gè)可以上鏈的區(qū)塊。

在大多數(shù)數(shù)字加密貨幣中,包括比特幣,礦工都會(huì)得到加密貨幣獎(jiǎng)勵(lì),以回報(bào) 其為計(jì)算工作量證明所投入的算力。下面是我們的挖礦函數(shù)的Python實(shí)現(xiàn)代碼:

class Blockchain: def __init__(self): self.unconfirmed_transactions = [] # data yet to get into blockchain self.chain = [] self.create_genesis_block() """ Previous code contd... """ def add_new_transaction(self, transaction): self.unconfirmed_transactions.append(transaction) def mine(self): """ This function serves as an interface to add the pending transactions to the blockchain by adding them to the block and figuring out proof of work. """ if not self.unconfirmed_transactions: return False last_block = self.last_block new_block = Block(index=last_block.index + 1, transactions=self.unconfirmed_transactions, timestamp=time.time(), previous_hash=last_block.hash) proof = self.proof_of_work(new_block) self.add_block(new_block, proof) self.unconfirmed_transactions = [] return new_block.index

好了,我們就快要完成這個(gè)Python仿真區(qū)塊鏈項(xiàng)目了!

7、Python仿真區(qū)塊鏈:為節(jié)點(diǎn)添加API接口

現(xiàn)在該為我們的仿真區(qū)塊鏈節(jié)點(diǎn)添加API接口了,這樣應(yīng)用程序就可以利用 這些API開發(fā)具體的應(yīng)用。我們將使用流行的Python微框架Flask來(lái)創(chuàng)建 REST API。如果你以前使用過其他web框架,那么下面的代碼應(yīng)當(dāng)不難理解, 如果沒有接觸過web框架的話也別擔(dān)心,這里有一個(gè)非常棒的Flask教程:

from flask import Flask, requestimport requests# Initialize flask applicationapp = Flask(__name__)# Initialize a blockchain object.blockchain = Blockchain()

我們需要一個(gè)可以提交新交易的訪問端節(jié)點(diǎn),這樣我們的應(yīng)用就可以 利用這個(gè)API來(lái)將新數(shù)據(jù)添加到區(qū)塊鏈中。下面是節(jié)點(diǎn)的/new_transaction 訪問端節(jié)點(diǎn)的Python實(shí)現(xiàn)代碼:

# Flask's way of declaring end-points@app.route('/new_transaction', methods=['POST'])def new_transaction(): tx_data = request.get_json() required_fields = ["author", "content"] for field in required_fields: if not tx_data.get(field): return "Invalid transaction data", 404 tx_data["timestamp"] = time.time() blockchain.add_new_transaction(tx_data) return "Success", 201

另一個(gè)端節(jié)點(diǎn)/chain可以返回區(qū)塊鏈的數(shù)據(jù)。我們的應(yīng)用將利用這個(gè)API 來(lái)查詢要顯示的數(shù)據(jù)。下面是這個(gè)端節(jié)點(diǎn)的Python實(shí)現(xiàn)代碼:

@app.route('/chain', methods=['GET'])def get_chain(): chain_data = [] for block in blockchain.chain: chain_data.append(block.__dict__) return json.dumps({"length": len(chain_data), "chain": chain_data})

挖礦很費(fèi)CPU,因此我們不希望讓節(jié)點(diǎn)一直挖礦,而是提供一個(gè) 訪問端節(jié)點(diǎn)/mine來(lái)提供按需挖礦服務(wù)。 下面是Python實(shí)現(xiàn)代碼:

@app.route('/mine', methods=['GET'])def mine_unconfirmed_transactions(): result = blockchain.mine() if not result: return "No transactions to mine" return "Block #{} is mined.".format(result)@app.route('/pending_tx')def get_pending_tx(): return json.dumps(blockchain.unconfirmed_transactions)

這些REST訪問端節(jié)點(diǎn)可以用來(lái)操作我們的區(qū)塊鏈,比如提交一些交易,然后 通過挖礦確認(rèn)這些交易等等。

8、Python仿真區(qū)塊鏈:實(shí)現(xiàn)最長(zhǎng)鏈共識(shí)與去中心化計(jì)算

到目前為止,我們用Python從零實(shí)現(xiàn)的仿真區(qū)塊鏈?zhǔn)沁\(yùn)行在一臺(tái)計(jì)算機(jī)上的。即使 我們已經(jīng)利用哈希將區(qū)塊前后鏈接起來(lái),并應(yīng)用了工作量證明約束,我們 還是不能只信任單一的節(jié)點(diǎn)。我們需要實(shí)現(xiàn)分布式數(shù)據(jù)存儲(chǔ),我們需要 多個(gè)節(jié)點(diǎn)來(lái)維護(hù)區(qū)塊鏈。因此,為了從單一節(jié)點(diǎn)轉(zhuǎn)向P2P網(wǎng)絡(luò),讓我們先 創(chuàng)建一個(gè)機(jī)制來(lái)讓網(wǎng)絡(luò)上的節(jié)點(diǎn)彼此了解。

首先定義一個(gè)新的訪問端節(jié)點(diǎn)/register_node用來(lái)在網(wǎng)絡(luò)中注冊(cè)新節(jié)點(diǎn)。 下面是Python實(shí)現(xiàn)代碼:

# Contains the host addresses of other participating members of the networkpeers = set()# Endpoint to add new peers to the network@app.route('/register_node', methods=['POST'])def register_new_peers(): # The host address to the peer node node_address = request.get_json()["node_address"] if not node_address: return "Invalid data", 400 # Add the node to the peer list peers.add(node_address) # Return the blockchain to the newly registered node so that it can sync return get_chain()@app.route('/register_with', methods=['POST'])def register_with_existing_node(): """ Internally calls the `register_node` endpoint to register current node with the remote node specified in the request, and sync the blockchain as well with the remote node. """ node_address = request.get_json()["node_address"] if not node_address: return "Invalid data", 400 data = {"node_address": request.host_url} headers = {'Content-Type': "application/json"} # Make a request to register with remote node and obtain information response = requests.post(node_address + "/register_node", data=json.dumps(data), headers=headers) if response.status_code == 200: global blockchain global peers # update chain and the peers chain_dump = response.json()['chain'] blockchain = create_chain_from_dump(chain_dump) peers.update(response.json()['peers']) return "Registration successful", 200 else: # if something goes wrong, pass it on to the API response return response.content, response.status_codedef create_chain_from_dump(chain_dump): blockchain = Blockchain() for idx, block_data in enumerate(chain_dump): block = Block(block_data["index"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"]) proof = block_data['hash'] if idx > 0: added = blockchain.add_block(block, proof) if not added: raise Exception("The chain dump is tampered!!") else: # the block is a genesis block, no verification needed blockchain.chain.append(block) return blockchain

新加入網(wǎng)絡(luò)的節(jié)點(diǎn)可以利用/register_with endpoint端節(jié)點(diǎn)調(diào)用 register_with_existing_node方法進(jìn)行注冊(cè)。這有助于解決以下問題:

  • 要求遠(yuǎn)端節(jié)點(diǎn)在其已知鄰節(jié)點(diǎn)中添加一個(gè)新的條目
  • 使用遠(yuǎn)端節(jié)點(diǎn)的數(shù)據(jù)初始化新節(jié)點(diǎn)上的區(qū)塊鏈
  • 如果節(jié)點(diǎn)中途有下線,而可以重新從網(wǎng)絡(luò)同步區(qū)塊鏈

然而,當(dāng)存在多個(gè)區(qū)塊鏈節(jié)點(diǎn)時(shí)有一個(gè)問題需要解決:不管有意或無(wú)意(例如網(wǎng)絡(luò)延遲), 不同節(jié)點(diǎn)上的區(qū)塊鏈可能彼此不同。在這種情況下,節(jié)點(diǎn)之間需要就區(qū)塊鏈的版本 達(dá)成一致,以便維護(hù)整個(gè)系統(tǒng)的一致性。換句話說(shuō),我們需要達(dá)成共識(shí)。

當(dāng)不同節(jié)點(diǎn)上的區(qū)塊鏈出現(xiàn)分化時(shí),一個(gè)簡(jiǎn)單的共識(shí)算法是選擇最長(zhǎng)有效鏈。 這一方法背后的合理性在于,最長(zhǎng)的鏈包含了最多的已經(jīng)投入的工作量證明計(jì)算。 下面是最長(zhǎng)鏈共識(shí)算法的Python實(shí)現(xiàn)代碼:

class Blockchain """ previous code continued... """ def check_chain_validity(cls, chain): """ A helper method to check if the entire blockchain is valid. """ result = True previous_hash = "0" # Iterate through every block for block in chain: block_hash = block.hash # remove the hash field to recompute the hash again # using `compute_hash` method. delattr(block, "hash") if not cls.is_valid_proof(block, block.hash) or previous_hash != block.previous_hash: result = False break block.hash, previous_hash = block_hash, block_hash return resultdef consensus(): """ Our simple consensus algorithm. If a longer valid chain is found, our chain is replaced with it. """ global blockchain longest_chain = None current_len = len(blockchain.chain) for node in peers: response = requests.get('{}/chain'.format(node)) length = response.json()['length'] chain = response.json()['chain'] if length > current_len and blockchain.check_chain_validity(chain): # Longer valid chain found! current_len = length longest_chain = chain if longest_chain: blockchain = longest_chain return True return False

現(xiàn)在,我們需要提供一個(gè)Python方法讓節(jié)點(diǎn)在挖出區(qū)塊時(shí)可以將這一 消息廣播給其他節(jié)點(diǎn),這樣我們的仿真區(qū)塊鏈網(wǎng)絡(luò)中的每個(gè)參與者都可以 更新其本地區(qū)塊鏈,然后接著挖下一個(gè)區(qū)塊。收到區(qū)塊廣播的節(jié)點(diǎn)很簡(jiǎn)單 就可以驗(yàn)證工作量證明,然后將收到區(qū)塊加入到自己的本地鏈上。

下面是節(jié)點(diǎn)的/add_block訪問端節(jié)點(diǎn)的Python實(shí)現(xiàn)代碼:

# endpoint to add a block mined by someone else to# the node's chain. The node first verifies the block# and then adds it to the chain.@app.route('/add_block', methods=['POST'])def verify_and_add_block(): block_data = request.get_json() block = Block(block_data["index"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"]) proof = block_data['hash'] added = blockchain.add_block(block, proof) if not added: return "The block was discarded by the node", 400 return "Block added to the chain", 201def announce_new_block(block): """ A function to announce to the network once a block has been mined. Other blocks can simply verify the proof of work and add it to their respective chains. """ for peer in peers: url = "{}add_block".format(peer) requests.post(url, data=json.dumps(block.__dict__, sort_keys=True))

announce_new_block方法應(yīng)當(dāng)在區(qū)塊被挖出的時(shí)候調(diào)用,這樣其他節(jié)點(diǎn) 就可以更新自己本地保存的區(qū)塊鏈副本:

@app.route('/mine', methods=['GET'])def mine_unconfirmed_transactions(): result = blockchain.mine() if not result: return "No transactions to mine" else: # Making sure we have the longest chain before announcing to the network chain_length = len(blockchain.chain) consensus() if chain_length == len(blockchain.chain): # announce the recently mined block to the network announce_new_block(blockchain.last_block) return "Block #{} is mined.".format(blockchain.last_block.index

9、Python仿真區(qū)塊鏈:開發(fā)去中心化應(yīng)用程序

好了,現(xiàn)在我們的仿真區(qū)塊鏈的節(jié)點(diǎn)軟件已經(jīng)開發(fā)完了?,F(xiàn)在需要開發(fā) 應(yīng)用程序的用戶界面了。我們使用Jinja2模板來(lái)渲染網(wǎng)頁(yè),并使用一些CSS來(lái) 讓網(wǎng)頁(yè)看起來(lái)美觀一些。

我們的應(yīng)用需要連接到這個(gè)仿真區(qū)塊鏈網(wǎng)絡(luò)中的某個(gè)節(jié)點(diǎn)以便獲取數(shù)據(jù)或者 提交新數(shù)據(jù)。下面是應(yīng)用的初始化部分的Python代碼:

import datetimeimport jsonimport requestsfrom flask import render_template, redirect, requestfrom app import app# Node in the blockchain network that our application will communicate with# to fetch and add data.CONNECTED_NODE_ADDRESS = "http://127.0.0.1:8000"posts = []

fetch_posts方法利用節(jié)點(diǎn)的/chain端節(jié)點(diǎn)獲取數(shù)據(jù)、解析數(shù)據(jù)并保存在本地:

def fetch_posts(): """ Function to fetch the chain from a blockchain node, parse the data, and store it locally. """ get_chain_address = "{}/chain".format(CONNECTED_NODE_ADDRESS) response = requests.get(get_chain_address) if response.status_code == 200: content = [] chain = json.loads(response.content) for block in chain["chain"]: for tx in block["transactions"]: tx["index"] = block["index"] tx["hash"] = block["previous_hash"] content.append(tx) global posts posts = sorted(content, key=lambda k: k['timestamp'], reverse=True)

應(yīng)用程序使用一個(gè)HTML表單來(lái)接收用戶輸入然后利用一個(gè)POST請(qǐng)求 將交易添加到所連接節(jié)點(diǎn)的未確認(rèn)交易池中。然后交易會(huì)被我們的 仿真區(qū)塊鏈網(wǎng)絡(luò)確認(rèn)并最終當(dāng)刷新網(wǎng)頁(yè)時(shí)被再次讀取:

@app.route('/submit', methods=['POST'])def submit_textarea(): """ Endpoint to create a new transaction via our application """ post_content = request.form["content"] author = request.form["author"] post_object = { 'author': author, 'content': post_content, } # Submit a transaction new_tx_address = "{}/new_transaction".format(CONNECTED_NODE_ADDRESS)

10、Python仿真區(qū)塊鏈:如何運(yùn)行應(yīng)用

終于完成了!你可以在github上查看這個(gè)Python仿真區(qū)塊鏈的 完整源代碼。

首先克隆項(xiàng)目倉(cāng)庫(kù):

$ git clone https://github.com/ezpod/python-blockchain-sim.git

安裝必要的Python項(xiàng)目依賴:

$ cd python_blockchain_app$ pip install -r requirements.txt

啟動(dòng)我們的仿真區(qū)塊鏈節(jié)點(diǎn):

$ export FLASK_APP=node_server.py$ flask run --port 8000

現(xiàn)在我們的一個(gè)仿真區(qū)塊鏈節(jié)點(diǎn)實(shí)例已經(jīng)啟動(dòng)并在8000端口監(jiān)聽。

開啟另一個(gè)終端運(yùn)行我們的去中心化應(yīng)用:

$ python run_app.py

現(xiàn)在應(yīng)用已經(jīng)啟動(dòng),可以通過這個(gè)網(wǎng)址訪問: http://localhost:5000.

下圖展示了如何利用web界面向我們的仿真區(qū)塊鏈提交內(nèi)容:

下圖展示了如何利用web界面啟動(dòng)節(jié)點(diǎn)挖礦:

下圖展示了如何利用web界面重新同步區(qū)塊鏈數(shù)據(jù):

11、Python仿真區(qū)塊鏈:運(yùn)行多個(gè)節(jié)點(diǎn)

要運(yùn)行包含多個(gè)節(jié)點(diǎn)的仿真區(qū)塊鏈網(wǎng)絡(luò),可以使用register_with/端節(jié)點(diǎn) 在網(wǎng)絡(luò)中注冊(cè)新節(jié)點(diǎn)。

下面是一個(gè)多節(jié)點(diǎn)的示例場(chǎng)景,我們啟動(dòng)了3個(gè)仿真節(jié)點(diǎn),分別在8000、8001和 8002端口監(jiān)聽:

# already running$ flask run --port 8000 spinning up new nodes$ flask run --port 8001 &$ flask run --port 8002 &

可以使用下面的cURL請(qǐng)求注冊(cè)在8001和8002端口監(jiān)聽的兩個(gè)新節(jié)點(diǎn):

$ curl -X POST http://127.0.0.1:8001/register_with -H 'Content-Type: application/json' -d '{"node_address": "http://127.0.0.1:8000"}'$ curl -X POST http://127.0.0.1:8002/register_with -H 'Content-Type: application/json' -d '{"node_address": "http://127.0.0.1:8000"}'

這樣在端口8000監(jiān)聽的節(jié)點(diǎn)就可以知道還有8001和8002監(jiān)聽的節(jié)點(diǎn), 反之亦然。新加入的節(jié)點(diǎn)也會(huì)從原來(lái)的在網(wǎng)節(jié)點(diǎn)同步區(qū)塊鏈數(shù)據(jù), 這樣新節(jié)點(diǎn)就可以參與后續(xù)的挖礦過程了。

要修改前端應(yīng)用同步的區(qū)塊鏈節(jié)點(diǎn),可以修改views.py文件中的 CONNECTED_NODE_ADDRESS字段。

一旦完成上面的操作,你就可以運(yùn)行應(yīng)用(python run_app.py)并 通過web界面創(chuàng)建交易了。當(dāng)你挖礦后,網(wǎng)絡(luò)中的所有節(jié)點(diǎn)都會(huì)更新 自己的本地區(qū)塊鏈。也可以使用cURL或Postman利用/chain端節(jié)點(diǎn)查看 區(qū)塊鏈。例如:

$ curl -X GET http://localhost:8001/chain$ curl -X GET http://localhost:8002/chain

12、Python仿真區(qū)塊鏈:如何驗(yàn)證交易

你可能注意到我們的基于仿真區(qū)塊鏈的去中心化應(yīng)用還有一點(diǎn)瑕疵:任何人在任何時(shí)間都 可以提交任何內(nèi)容。解決這一問題的一個(gè)辦法,就是使用非對(duì)稱密鑰技術(shù)創(chuàng)建用戶賬戶。 每一個(gè)新用戶都需要一個(gè)公鑰(對(duì)應(yīng)賬戶名)和一個(gè)私鑰才能在我們的應(yīng)用 中提交數(shù)據(jù)。私鑰用來(lái)創(chuàng)建數(shù)據(jù)的簽名,而公鑰用來(lái)驗(yàn)證數(shù)據(jù)的簽名,下面是 其工作機(jī)制:

  • 每一個(gè)提交的新交易都使用用戶的私鑰進(jìn)行簽名。這個(gè)簽名與用戶信息一起 添加到交易數(shù)據(jù)中
  • 在驗(yàn)證階段,當(dāng)挖礦時(shí),我們可以使用公鑰和簽名驗(yàn)證數(shù)據(jù)中生成的發(fā)送方 和簽名是否相符,以及驗(yàn)證消息是否被修改。

13、Python仿真區(qū)塊鏈:教程總結(jié)

在這個(gè)教程中,我們學(xué)習(xí)了一個(gè)公鏈的基本概念,并利用Python實(shí)現(xiàn)了一個(gè)仿真區(qū)塊鏈 以及基于這個(gè)仿真區(qū)塊鏈的Flask應(yīng)用。如果你走完了整個(gè)教程,相信應(yīng)該可以使用Python 從零實(shí)現(xiàn)一個(gè)區(qū)塊鏈,并基于這個(gè)仿真的區(qū)塊鏈開發(fā)自己的去中心化應(yīng)用,或者利用 這個(gè)仿真區(qū)塊鏈網(wǎng)絡(luò)進(jìn)行一些研究性的實(shí)驗(yàn)。教程中的區(qū)塊鏈實(shí)現(xiàn)沒有比特幣或以太坊那么復(fù)雜, 但相信會(huì)有助于理解區(qū)塊鏈技術(shù)的核心問題和解決思路。


原文鏈接:http://blog.hubwiz.com/2020/04/01/python-sim-blockchain/

總結(jié)

以上是生活随笔為你收集整理的python timestamp转string_Python仿真区块链【含源码】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日本美女视频 | 欧美日韩成人一区二区三区 | 中文字幕久久一区 | 美女色呦呦| 国产粉嫩一区二区三区 | 激情超碰在线 | 五月开心激情 | 亚洲天堂五月天 | 桃色视频网站 | 999精品| 高跟鞋肉丝交足91 | 在线观看网址你懂的 | 国产一级片网站 | 美女视频久久 | 欧美日韩国产一区二区三区在线观看 | 日韩乱论 | 中文字幕乱码一区 | 久久国产精品久久久久久电车 | 草草影院在线播放 | 国产香蕉尹人视频在线 | 九草视频在线观看 | 亚洲视频在线网 | www.白浆 | 双性高h1v1| 黄色在线免费视频 | 一个人看的视频www 色就是色网站 | 国产自产21区 | 免费黄色网址观看 | 国产大学生视频 | 91精品国产成人www | 精品国产18久久久久久二百 | 国产尤物在线视频 | 久操视频在线 | 国产精品无码中文字幕 | 午夜精品一区二区三区免费视频 | 8090av| 国产一区二区不卡视频 | 91成人免费观看 | 欧美色999 | 麻豆影视 | 伊人热久久 | 有码一区二区三区 | 午夜视频一区 | 国产成人无遮挡在线视频 | 日韩精品在线观看一区二区三区 | 91色交视频| 人妻丰满熟妇av无码区免 | 欧美一区免费看 | 黄色片在哪看 | 丝袜美腿av在线 | 午夜xxx | 国产女人在线 | 26uuu精品一区二区 | 久久久婷婷| 中文字幕毛片 | 丝袜诱惑av | 91九色网 | 午夜精品剧场 | 国产精品51麻豆cm传媒 | 日本 奴役 捆绑 受虐狂xxxx | 亚洲依依 | 欧美一区二区福利视频 | 国产美女特级嫩嫩嫩bbb | 在线高清免费观看 | 久久精品国产一区二区三区 | 一级黄色伦理片 | 中文字幕欧美在线观看 | 日韩在线播放视频 | 国产成人a人亚洲精品无码 在线aa | 极品尤物魔鬼身材啪啪仙踪林 | 中文字幕第一页久久 | 男女涩涩 | 少妇在军营h文高辣 | 久久频 | 国产精品中文字幕在线 | 天堂√8在线中文 | 色婷婷影院| 国产福利一区二区三区在线观看 | 三年中文在线观看免费观看 | 久久九九精品视频 | 嫩草影院一区二区三区 | 日韩欧美视频在线免费观看 | 欧美第一页在线 | 羞羞漫画在线播放 | 美女被草视频在线观看 | 荫蒂被男人添免费视频 | 无人在线观看高清视频 | 亚洲成av| 国产精品美女久久久久 | 国产色秀| 成人极品视频 | 国产网站黄 | 中国美女一级片 | 国产午夜在线视频 | 亚洲涩涩视频 | 久草免费在线视频观看 | 精品免费看 | 男人的天堂在线 | 国产成人精品免费在线观看 |