环境:
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
# }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)