用Python创建简单区块链

用Python创建简单区块链,第1张

用Python创建简单区块链

环境:
Flask 0.12.2
request2.18.4
原文链接:https://xiaozhuanlan.com/blockchaincore?rel=5100037573
Github:https://github.com/xilibi2003/blockchain

可能出现的问题:
AttributeError: ‘Request’ object has no attribute ‘is_xhr’
解决方法:
降低Werkzeug版本为0.16版本如下:
pip uninstall Werkzeug
pip install Werkzeug==0.16.1
链接: Flask AttributeError ‘Request’ object has no attribute ‘is_xhr’ 报错的解决办法
源代码:

import hashlib
import json
import requests
from time import time
from textwrap import dedent
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
from uuid import uuid4
from flask import Flask, jsonify, request


# flask服务器 扮演区块链网络中的一个节点


class Blockchain(object):
    # Used for 管理链条,它能存储交易,加入新块
    def __init__(self):
        self.current_transactions = []
        self.chain = []
        self.nodes = set()

        # Create the genesis block
        self.new_block(previous_hash=1, proof=100)

    # 提供一个注册节点的方法:
    def register_node(self, address):
        """
        Add a new node to the list of nodes
        :param address:  Address of node. Eg. 'http://192.168.0.5:5000'
        :return: None
        """

        parsed_url = urlparse(address)
        self.nodes.add(parsed_url.netloc)

    def valid_chain(self, chain):
        # 检查是否是有效链。


遍历每个块验证hash 和 proof """ Determine if a given blockchain is valid :param chain: A blockchain :return: True if valid, False if not """ last_block = chain[0] current_index = 1 while current_index < len(chain): block = chain[current_index] print(f'{last_block}') print(f'{block}') print("\n--------\n") # Check that the hash of the block is correct if block['previous_hash'] != self.hash(last_block): return False # Check that the Proof of Work is correct if not self.valid_proof(last_block['proof', block['proof']]): return False last_block = block current_index += 1 return True def resolve_conflicts(self): # 用来解决冲突,遍历所有的邻居节点,并用上一个放啊检查链的 # 有效性,如果发现有效更长链,就替换掉自己的链 """ 共识算法解决冲突 使用网络中最长的链, :return: True 如果链被取代,否则为False """ neighbours = self.nodes new_chain = None # We're only looking for chains longer than ours max_length = len(self.chain) # Grab and verify the chains from all the nodes in our network for node in neighbours: response = requests.get(f'http://{node}/chain') if response.status_code == 200: length = response.json()['length'] chain = response.json()['chain'] # Check if the length is longer and the chain is valid if length > max_length and self.valid_chain(chain): max_length = length new_chain = chain # Replace our chain if we discovered a new, valid chain longer than ours if new_chain: self.chain = new_chain return True return False def new_block(self, proof, previous_hash=None): """ 生成新块 :param proof: The proof given by the Proof of Work algorithm :param previous_hash: (Optional) Hash of previous Block :return: New Block """ block = { 'index': len(self.chain) + 1, 'timestamp': time(), 'transactions': self.current_transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.chain[-1]), } # Reset the current list of transactions self.current_transactions = [] self.chain.append(block) return block def new_transaction(self, sender, recipient, amount): # Adds a new transaction to the list of transactions """ 生成新交易信息,信息将加入到下一个待挖的区块中 :param sender: Address of the Sender :param recipient: Address of the Recipient :param amount: Amount :return: The index of the Block that will hold this transaction """ self.current_transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1 @property def last_block(self): # Return the last Block in the chain return self.chain[-1] # 区块结构 # block = { # 'index': 1, #索引 # 'timestamp': 1506057125.900785, #Unix时间戳 # 'transactions': [ # 交易列表 # { # 'sender': "8527147fe1f5426f9dd545de4b27ee00", #发送者 # 'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f", #接收者 # 'amount': 5, #数量 # } # ], # 'proof': 324984774000, # 'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" #前一个区块的Hash值 # } @staticmethod def hash(block): # Hashes a Block """ 生成块的 SHA-256 hash值 :param block: Block :return: """ # We must make sure that the Dictionary is Ordered, or we'll have # inconsistent hashes 确保当前的字典被Ordered,否则会导致hash 冲突 block_string = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_string).hexdigest() def proof_of_work(self, last_proof): # 方法向列表中添加一个交易记录,并返回该记录将被添加到的区块 # (下一个待挖掘的区块)的索引,等下在用户提交交易时会有用 """ 简单的工作量证明: - 查找一个 p' 是的 hash(pp') 以4个0开头 - p 是上一个块的证明, p' 是当前的证明 :param last_proof: :return: """ proof = 0 while self.valid_proof(last_proof, proof) is False: proof += 1 return proof @staticmethod def valid_proof(last_proof, proof): """ 验证证明: 是否hash(last_proof, proof)以4个0开头? :param last_proof: Previous Proof :param proof: Current Proof :return: True if correct,False if not """ guess = f'{last_proof}{proof}'.encode() guess_hash = hashlib.sha256(guess).hexdigest() return guess_hash[:4] == "0000" # Instantiate our Node 初始化节点 app = Flask(__name__) # Generate a globally unique address for this node 生成一个全局唯一的地址给这个节点 node_identifier = str(uuid4()).replace('_', '') # Instantiate the Blockchain blockchain = Blockchain() # 挖矿一共做了三件事 # 1. 计算工作量证明PoW # 2. 通过新增一个交易授予矿工(自己) 一个币 # 3. 构造新区块并将其添加到链中 @app.route('/mine', methods=['GET']) def mine(): # We run the proof of wok algorithm to get the next proof... last_block = blockchain.last_block last_proof = last_block['proof'] proof = blockchain.proof_of_work(last_proof) # 给工作量证明的节点提供奖励 # 发送者为 “0” 表明是新挖出的币 blockchain.new_transaction( sender="0", recipient=node_identifier, amount=1, ) # Forge the new Block by adding it to the chain # 锻造新的区块,并添加到链中 block = blockchain.new_block(proof) response = { 'message': "New Block Forged", 'index': block['index'], 'transaction': block['transactions'], 'proof': block['proof'], 'previous_hash': block['previous_hash'], } return jsonify(response), 200 @app.route('/transactions/new', methods=['POST']) def new_transaction(): values = request.get_json() # Check that the required fields are in the POST'ed data required = ['sender', 'recipient', 'amount'] if not all(k in values for k in required): return 'Missing values', 400 # Create a new Transaction index = blockchain.new_transaction(values['sender'], values['recipient', values['amount']]) response = {'message': f'Transaction will be added to Block {index}'} return jsonify(response), 201 @app.route('/chain', methods={'GET'}) def full_chain(): response = { 'chain': blockchain.chain, 'length': len(blockchain.chain), } return jsonify(response), 200 @app.route('/nodes/register', methods=['POST']) def register_nodes(): values = request.get_json() nodes = values.get('nodes') if nodes is None: return "Error: Please supply a valid list of nodes", 400 for node in nodes: blockchain.register_node(node) response = { 'message': 'New nodes have benn added', 'total_nodes': list(blockchain.nodes), } return jsonify(response), 201 @app.route('/nodes/resolve', methods=['GET']) def consensus(): replaced = blockchain.resolve_conflicts() if replaced: response = { 'message': 'Our chain was replaced', 'new_chain': blockchain.chain } else: response = { 'message': 'Our chain is authoritaat' } if __name__ == '__main__': app.run(host='127.0.0.1', port=5000) # app.run(host='0.0.0.0', port=5000) # 发送交易 # { # "sender": "my address", # "recipient": "someone else's address", # "amount": 5 # }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/563557.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存