目录
本篇文章将从一个实践者的角度出发,通过构建一个简单的区块链系统,揭开区块链技术的神秘面纱。我们将使用Python语言,结合Flask框架,创建一个可以处理交易、挖矿新区块、验证区块链有效性,并能在网络节点间同步的区块链网络。。
一、代码展示
- # Module 1 -Create a Cryptocurrency
- #To be installed:
- #Flask==0.12.2:pip install Flask==0.12.2
- #Postman HTrp Client:https://www.getpostman.com
- #requests==2.18.4:pip install requests=-2.18.4
- #时间戳
- import datetime
- import hashlib
- import json
- #Flask可以定义Web应用的路由(URL到Python函数的映射),并处理HTTP请求和响应。jsonify是一个函数,用于将Python对象转换为JSON格式的响应。当你在Flask路由函数中返回一个jsonify对象时,Flask会自动将该对象对应的数据转换为JSON格式,并设置合适的HTTP响应头,以便客户端可以正确解析响应内容。
- from flask import Flask, jsonify,request
- import requests
- from uuid import uuid4
- from urllib.parse import urlparse
-
- # 1******Building a Blockchain
- class Blockchain:
- def __init__(self):
- self.transactions=[]
- self.chain=[]
- self.create_block(proof=1,previous_hash='0')
- self.nodes=set()
-
- def create_block(self,proof,previous_hash):
- block={'index':len(self.chain)+1,
- 'timestamp':str(datetime.datetime.now()),
- 'proof':proof,
- 'previous_hash':previous_hash,
- 'transactions':self.transactions}
- self.transactions=[]
- self.chain.append(block)
- return block
- def get_previous_block(self):
- return self.chain[-1]
-
- def proof_of_work(self,previous_proof):
- new_proof=1
- check_proof=False
- while check_proof is False:
- hash_oparation=hashlib.sha256(str(new_proof**2-previous_proof**2).encode()).hexdigest()
- if hash_oparation[:4]=='0000':
- check_proof=True
- else:
- new_proof+=1
- return new_proof
-
- def hash(self, block):
- encode_block = json.dumps(block, sort_keys=True).encode()
- return hashlib.sha256(encode_block).hexdigest()
-
- def is_chain_valid(self,chain):
- previous_block=chain[0]
- block_index=1
- while block_index<len(chain):
- block=chain[block_index]
- if block['previous_hash'] !=self.hash(previous_block):
- return False
- previous_proof=previous_block['proof']
- proof=block['proof']
- hash_oparation=hashlib.sha256(str(proof**2-previous_proof**2).encode()).hexdigest()
- if hash_oparation[:4] !='0000':
- return False
- previous_block=block
- block_index+=1
- return True
-
- def add_transaction(self,sender,receiver,amount):
- self.transactions.append({'sender':sender,
- 'receiver':receiver,
- 'amount':amount})
- previous_block=self.get_previous_block()
- return previous_block['index']+1
-
- def add_node(self,address):
- parsed_url=urlparse(address)
- self.nodes.add(parsed_url.netloc)
-
- def replace_chain(self):
- network = self.nodes
- longest_chain = None
- max_length = len(self.chain)
-
- for node in network:
- try:
- response = requests.get(f'http://{node}/get_chain')
- response.raise_for_status() # 这将抛出异常,如果请求失败
- except requests.exceptions.RequestException as e:
- print(f"Failed to get the chain from {node}. Exception: {e}")
- continue
-
- if response.status_code == 200:
- length = response.json()['length']
- chain = response.json()['chain']
- if length > max_length and self.is_chain_valid(chain):
- max_length = length
- longest_chain = chain
-
- if longest_chain:
- self.chain = longest_chain
- return True
- return False
- #Part 2 -Mining our Blockchain
-
- #Creating a Web App
- app = Flask(__name__)
-
- #Creating an address for the node on Port 5000
- node_address=str(uuid4()).replace('-', '')
-
- #Creating a Blockchain
- blockchain=Blockchain()
- #Mining a new block
- @app.route('/mine_block',methods=['GET'])
- def mine_block():
- previous_block=blockchain.get_previous_block()
- previous_proof=previous_block['proof']
- proof=blockchain.proof_of_work(previous_proof)
- previous_hash=blockchain.hash(previous_block)
- blockchain.add_transaction(sender=node_address,receiver='Lanzhile',amount=1)
- block=blockchain.create_block(proof, previous_hash)
- response={'message':'Congratulation,you just mined a block',
- 'index':block['index'],
- 'timestamp':block['timestamp'],
- 'proof':block['proof'],
- 'previous_hash':block['previous_hash'],
- 'transactions':block['transactions']}
- return jsonify(response),200
-
- #Getting the full Blockchain
- @app.route('/get_chain',methods=['GET'])
- def get_chain():
- response={'chain':blockchain.chain,
- 'length':len(blockchain.chain)}
- return jsonify(response),200
-
- #Checking if the Blockchain is valid
- @app.route('/is_valid',methods=['GET'])
- def get_valid():
- is_valid=blockchain.is_chain_valid(blockchain.chain)
- if is_valid:
- response={'message':'All good. The Blockchain is valid.'}
- else:
- response={'message':'Houston,we have a problem.The Blockchain is not valid.'}
- return jsonify(response),200
-
- #Addling a new transaction to the Blockchain
- @app.route('/add_transaction',methods=['POST'])
- def add_transaction():
- json =request.get_json()
- transaction_keys=['sender','receiver','amount']
- if not all(key in json for key in transaction_keys):
- return 'Some elements of the transaction are missing',400
- index=blockchain.add_transaction(json['sender'], json['receiver'],json['amount'])
- response={'message':f'This transaction will be added to Block {index}'}
- return jsonify(response),201
-
- #Connecting new nodes
- @@app.route('/connect_node', methods=['POST'])
- def connect_node():
- json = request.get_json()
- nodes = json.get('nodes')
- if nodes is None:
- return "No nodes provided", 400
- for node in nodes:
- blockchain.add_node(node)
- # 将响应构建移到循环外,并在所有节点添加后才返回
- response = {
- 'message': 'All the nodes are now connected. The Lancoin Blockchain now contains the following nodes:',
- 'total_nodes': list(blockchain.nodes)
- }
- return jsonify(response), 201
-
- #Replacing the chain by the longest chain if needed
- @app.route('/replace_chain', methods=['GET'])
- def replace_chain():
- is_chain_replaced = blockchain.replace_chain()
- if is_chain_replaced:
- response = {
- 'message': 'The nodes had different chains so the chain was replaced by the longest one.',
- 'new_chain': blockchain.chain
- }
- else:
- response = {
- 'message': 'All good. the chain is the largest one.',
- 'actual_chain': blockchain.chain
- }
- return jsonify(response), 200
-
-
- app.run(host='0.0.0.0',port=5000)
注:下面对
/add_transaction、/connect_node、/replace_chain路由和对应的视图函数进行讲解,其他函数的详解在我的另外两篇我的文章里“
创建一个简单的区块链,并使用 Flask 框架提供一个简单的 Web 接口来与区块链交互。-CSDN博客”“
使用了Python语言和Flask框架。创建一个区块链网络,允许用户通过HTTP请求进行交互,如包括创建区块链、挖矿、验证区块链等功能。-CSDN博客”
- @app.route('/add_transaction', methods=['POST'])
- def add_transaction():
- # 获取请求的JSON数据
- json = request.get_json()
- # 定义交易必须包含的键
- transaction_keys = ['sender', 'receiver', 'amount']
- # 检查JSON数据中是否包含所有必要的交易键
- if not all(key in json for key in transaction_keys):
- # 如果缺少任何一个键,返回错误信息和400状态码
- return 'Some elements of the transaction are missing', 400
- # 添加交易到区块链,并获取返回的区块索引
- index = blockchain.add_transaction(json['sender'], json['receiver'], json['amount'])
- # 构建响应消息,告知交易将被添加到的区块索引
- response = {'message': f'This transaction will be added to Block {index}'}
- # 返回JSON格式的响应和201状态码,表示交易已成功创建
- return jsonify(response), 201
- @app.route('/connect_node', methods=['POST'])
- def connect_node():
- # 获取请求的JSON数据
- json = request.get_json()
- # 尝试从JSON数据中获取节点列表
- nodes = json.get('nodes')
- # 如果节点列表不存在,返回错误信息和400状态码
- if nodes is None:
- return "No nodes provided", 400
- # 遍历节点列表,并将每个节点添加到区块链网络中
- for node in nodes:
- blockchain.add_node(node)
- # 构建响应消息,列出所有已连接的节点
- response = {
- 'message': 'All the nodes are now connected. The Lancoin Blockchain now contains the following nodes:',
- 'total_nodes': list(blockchain.nodes)
- }
- # 返回JSON格式的响应和201状态码,表示节点已成功连接
- return jsonify(response), 201
- @app.route('/replace_chain', methods=['GET'])
- def replace_chain():
- # 调用 Blockchain 类的 replace_chain 方法
- # 这个方法会遍历所有节点,并决定是否需要用更长的链替换当前链
- is_chain_replaced = blockchain.replace_chain()
-
- # 如果链被替换了
- if is_chain_replaced:
- # 构建一个包含替换信息的响应字典
- response = {
- 'message': 'The nodes had different chains so the chain was replaced by the longest one.',
- # 提供替换后区块链的完整信息
- 'new_chain': blockchain.chain
- }
- else:
- # 如果当前区块链已经是最长的,没有被替换
- # 构建一个包含当前区块链信息的响应字典
- response = {
- 'message': 'All good. the chain is the largest one.',
- # 提供当前区块链的完整信息
- 'actual_chain': blockchain.chain
- }
-
- # 使用 jsonify 将 Python 字典转换成 JSON 格式的响应体
- # 返回 200 OK HTTP 状态码
- return jsonify(response), 200
这纸片文章主要介绍三个路由:/add_transaction
、/connect_node
和 /replace_chain
,分别用于添加交易、连接新节点和替换链。在处理请求时,代码首先获取请求中的JSON数据,然后根据不同的路由执行相应的操作,最后返回响应消息和状态码。