如何从零开始搭建一个完整的区块链系统?关键步骤与技术难点有哪些?
摘要:
我们将使用 Python 来构建一个简化版的区块链,这个版本将包含以下核心功能:区块结构:定义每个区块应该包含什么信息(索引、时间戳、数据、前一个区块的哈希、自己的哈希),区块链:... 我们将使用 Python 来构建一个简化版的区块链,这个版本将包含以下核心功能:
- 区块结构:定义每个区块应该包含什么信息(索引、时间戳、数据、前一个区块的哈希、自己的哈希)。
- 区块链:一个由区块按顺序链接而成的列表。
- 工作量证明:通过“挖矿”来找到符合特定难度的哈希值,确保新区块的创建是困难的。
- 一致性检查:验证一个区块链是否有效。
- 简单的HTTP API:使用
Flask框架暴露几个API端点,让外界可以与我们的区块链进行交互(查看整个链、添加新交易、挖矿)。
项目结构
我们先来规划一下项目的文件结构:
blockchain/
├── app.py # 主应用程序,包含Flask API和区块链核心逻辑
└── requirements.txt # 项目依赖
第一步:环境准备
- 安装Python: 确保你的系统上安装了Python 3.6+。
- 安装依赖: 我们需要
Flask来构建Web API,requests来模拟节点间的通信,hashlib用于哈希计算(Python内置)。
创建 requirements.txt 文件:
Flask==2.0.1
requests==2.26.0
安装依赖:
pip install -r requirements.txt
第二步:实现核心区块链逻辑
这是整个项目的核心,我们将所有的区块链逻辑都放在 app.py 文件中。
创建 app.py 文件,然后我们一步步填充它。
导入必要的库
import hashlib import json from time import time from flask import Flask, jsonify, request
定义 Block 类
每个区块都是一个对象,我们用一个字典来表示区块的结构,然后用一个类来方便地创建和管理它。
class Block:
def __init__(self, index, previous_hash, timestamp, data, hash):
self.index = index
self.previous_hash = previous_hash
self.timestamp = timestamp
self.data = data
self.hash = hash
实现 Blockchain 类
这是我们的主角,它将包含创建区块、验证链条和挖矿的逻辑。
class Blockchain:
def __init__(self):
self.chain = []
self.current_transactions = []
# 创建创世区块
self.new_block(previous_hash='1', proof=100, data="Genesis Block")
def new_block(self, proof, previous_hash, data):
"""
创建一个新区块并添加到链中
:param proof: <int> 由工作量证明算法给出的证明
:param previous_hash: <str> 前一个区块的哈希
:param data: <str> 区块存储的数据
:return: <dict> 新区块
"""
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'data': data,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
# 重置当前交易列表
self.current_transactions = []
self.chain.append(block)
return block
@property
def last_block(self):
return self.chain[-1]
def new_transaction(self, sender, recipient, amount):
"""
创建一个新的交易信息,将添加到下一个待挖的区块中
:param sender: <str> 发送方地址
:param recipient: <str> 接收方地址
:param amount: <int> 金额
:return: <int> 保存这个交易的区块的索引
"""
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
@staticmethod
def hash(block):
"""
生成一个区块的 SHA-256 哈希值
:param block: <dict> Block
:return: <str>
"""
# 我们必须确保字典是有序的,否则哈希值会不一致
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: <int>
:return: <int>
"""
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: <int> 上一个区块的证明
:param proof: <int> 当前证明
:return: <bool> 正确返回True,错误返回False
"""
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
代码解释:
__init__: 初始化一个空的链,并创建一个创世区块,创世区块是链的起点,它没有前一个区块,所以我们给它一个固定的哈希值'1'。new_block: 这是我们添加新区块的方法,它接收工作量证明proof、前一个区块的哈希previous_hash和要存储的数据data,然后创建一个新区块对象。new_transaction: 这个方法用于添加新的交易,交易会先被暂存,直到下一个区块被“挖”出并添加到链上。hash: 一个静态方法,接收一个区块的字典,计算并返回其SHA-256哈希值。json.dumps的sort_keys=True确保了无论输入顺序如何,生成的JSON字符串都是一致的,从而保证了哈希值的稳定。proof_of_work: 这是“挖矿”的核心,它会不断尝试不同的proof值,直到找到一个值,使得hash(last_proof, proof)的结果满足我们的难度要求(这里是以4个0开头)。valid_proof: 一个辅助方法,用于验证一个给定的proof是否满足难度要求。
第三步:构建API接口
现在我们有了核心的区块链逻辑,接下来用 Flask 搭建一个简单的Web服务器,提供几个API端点来与我们的区块链交互。
在 app.py 中,Blockchain 类之后,添加以下代码:
# Instantiate the Node
app = Flask(__name__)
# Instantiate the Blockchain
blockchain = Blockchain()
@app.route('/mine', methods=['GET'])
def mine():
# 我们运行工作量证明算法来获得下一个证明...
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_address", # 这里可以替换为你的节点地址
amount=1,
)
# 通过添加以下区块来锻造新区块
previous_hash = blockchain.hash(last_block)
block = blockchain.new_block(proof, previous_hash, data=f"Mined block {len(blockchain.chain)}")
response = {
'message': "New Block Forged",
'index': block['index'],
'transactions': 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()
# 检查POST请求的体中是否包含了必要的字段
required = ['sender', 'recipient', 'amount']
if not all(k in values for k in required):
return 'Missing values', 400
# 创建一个新的交易
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 been 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 authoritative',
'chain': blockchain.chain
}
return jsonify(response), 200
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port
app.run(host='0.0.0.0', port=port)
新增代码解释:
app = Flask(__name__): 创建一个Flask应用实例。blockchain = Blockchain(): 创建我们的区块链实例。@app.route('/mine', methods=['GET']):GET /mine端点,当访问它时,它会执行挖矿操作:计算工作量证明,添加一笔“挖矿奖励”交易,然后创建并添加一个新区块。@app.route('/transactions/new', methods=['POST']):POST /transactions/new端点,用于向当前交易列表中添加一笔新的交易,它接收一个JSON格式的请求体,包含sender,recipient, 和amount。@app.route('/chain', methods=['GET']):GET /chain端点,返回整个区块链和它的长度。if __name__ == '__main__':: 启动Flask服务器,我们添加了命令行参数,方便指定端口号。
第四步:运行和测试
我们的 app.py 文件已经完成了,让我们来运行它并进行测试。
- 运行区块链节点
打开终端,进入 blockchain 目录,运行:
python app.py -p 5000
你应该会看到类似下面的输出,表示服务器正在运行:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
- 与节点交互
我们需要另一个工具来发送HTTP请求,curl 或者 Postman,这里我们使用 curl。
a. 查看整个区块链
在另一个终端窗口中,运行:
curl http://localhost:5000/chain
你会看到创世区块:
Flask==2.0.1
requests==2.26.00
b. 添加一笔新交易
Flask==2.0.1
requests==2.26.01
你会得到响应:
Flask==2.0.1
requests==2.26.02
c. 挖矿
这是最激动人心的一步!运行以下命令来“挖”出包含刚才那笔交易的新区块。
Flask==2.0.1
requests==2.26.03
你会看到类似下面的输出(proof 和 timestamp 会不同):
Flask==2.0.1
requests==2.26.04
d. 再次查看区块链
现在再次运行 GET /chain 命令,你会看到链上现在有两个区块了!
curl http://localhost:5000/chain
输出会显示一个长度为2的链,第二个区块包含了你添加的交易和挖矿奖励。
总结与展望
恭喜!你已经从零开始成功搭建了一个功能完备的简化版区块链。
你刚刚实现了什么?
- 区块和链式结构:数据被组织成区块,并通过哈希指针安全地链接在一起。
- 工作量证明:通过计算哈希来“挖矿”,增加了创建新区块的难度,防止篡改。
- 交易系统:可以添加和记录交易。
- 简单的API:可以通过HTTP请求与你的区块链进行交互。
接下来可以做什么?
- 实现节点发现和共识:我们预留了
register_nodes和resolve_conflicts的接口,但还没有实现,你可以实现一个P2P网络,让不同的节点可以互相发现,并通过“最长有效链”原则来解决链的冲突。 - 实现其他共识机制:尝试实现权益证明,它比PoW更节能。
- 创建一个简单的钱包:实现公钥/私钥对,用于签名交易,确保交易的真实性。
- 添加数据持久化:目前链数据只存在于内存中,你可以将它保存到数据库(如LevelDB)或文件中。
- 前端界面:用Vue或React创建一个前端,让你可以更直观地查看交易、挖矿和链的状态。
这个项目是通往更复杂区块链(如比特币、以太坊)世界的绝佳第一步,祝你学习愉快!
作者:咔咔本文地址:https://www.jits.cn/content/27238.html发布于 02-21
文章转载或复制请以超链接形式并注明出处杰思科技・AI 股讯



还没有评论,来说两句吧...