本文作者:咔咔

如何从零开始搭建一个完整的区块链系统?关键步骤与技术难点有哪些?

如何从零开始搭建一个完整的区块链系统?关键步骤与技术难点有哪些?摘要: 我们将使用 Python 来构建一个简化版的区块链,这个版本将包含以下核心功能:区块结构:定义每个区块应该包含什么信息(索引、时间戳、数据、前一个区块的哈希、自己的哈希),区块链:...

我们将使用 Python 来构建一个简化版的区块链,这个版本将包含以下核心功能:

  1. 区块结构:定义每个区块应该包含什么信息(索引、时间戳、数据、前一个区块的哈希、自己的哈希)。
  2. 区块链:一个由区块按顺序链接而成的列表。
  3. 工作量证明:通过“挖矿”来找到符合特定难度的哈希值,确保新区块的创建是困难的。
  4. 一致性检查:验证一个区块链是否有效。
  5. 简单的HTTP API:使用 Flask 框架暴露几个API端点,让外界可以与我们的区块链进行交互(查看整个链、添加新交易、挖矿)。

项目结构

我们先来规划一下项目的文件结构:

如何从零开始搭建一个完整的区块链系统?关键步骤与技术难点有哪些?
(图片来源网络,侵删)
blockchain/
├── app.py          # 主应用程序,包含Flask API和区块链核心逻辑
└── requirements.txt # 项目依赖

第一步:环境准备

  1. 安装Python: 确保你的系统上安装了Python 3.6+。
  2. 安装依赖: 我们需要 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.dumpssort_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 文件已经完成了,让我们来运行它并进行测试。

  1. 运行区块链节点

打开终端,进入 blockchain 目录,运行:

python app.py -p 5000

你应该会看到类似下面的输出,表示服务器正在运行:

 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
  1. 与节点交互

我们需要另一个工具来发送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

你会看到类似下面的输出(prooftimestamp 会不同):

Flask==2.0.1
requests==2.26.04

d. 再次查看区块链

现在再次运行 GET /chain 命令,你会看到链上现在有两个区块了!

curl http://localhost:5000/chain

输出会显示一个长度为2的链,第二个区块包含了你添加的交易和挖矿奖励。


总结与展望

恭喜!你已经从零开始成功搭建了一个功能完备的简化版区块链。

你刚刚实现了什么?

  • 区块和链式结构:数据被组织成区块,并通过哈希指针安全地链接在一起。
  • 工作量证明:通过计算哈希来“挖矿”,增加了创建新区块的难度,防止篡改。
  • 交易系统:可以添加和记录交易。
  • 简单的API:可以通过HTTP请求与你的区块链进行交互。

接下来可以做什么?

  1. 实现节点发现和共识:我们预留了 register_nodesresolve_conflicts 的接口,但还没有实现,你可以实现一个P2P网络,让不同的节点可以互相发现,并通过“最长有效链”原则来解决链的冲突。
  2. 实现其他共识机制:尝试实现权益证明,它比PoW更节能。
  3. 创建一个简单的钱包:实现公钥/私钥对,用于签名交易,确保交易的真实性。
  4. 添加数据持久化:目前链数据只存在于内存中,你可以将它保存到数据库(如LevelDB)或文件中。
  5. 前端界面:用Vue或React创建一个前端,让你可以更直观地查看交易、挖矿和链的状态。

这个项目是通往更复杂区块链(如比特币、以太坊)世界的绝佳第一步,祝你学习愉快!

文章版权及转载声明

作者:咔咔本文地址:https://www.jits.cn/content/27238.html发布于 02-21
文章转载或复制请以超链接形式并注明出处杰思科技・AI 股讯

阅读
分享

发表评论

快捷回复:

评论列表 (暂无评论,1人围观)参与讨论

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