虚拟币用到的非常哇塞的技术(实用拜占庭容错(PBFT))解读

python编程示例系列
python编程示例系列二
python的Web神器Streamlit
如何应聘高薪职位
C#视觉应用开发问题系列
c#串口应用开发问题系列
microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
在这里插入图片描述# 实用拜占庭容错(PBFT)技术详解

用途

实用拜占庭容错(Practical Byzantine Fault Tolerance, PBFT)是一种共识算法,主要用于解决分布式系统中的拜占庭将军问题。在虚拟货币和区块链领域,PBFT具有以下用途:

  1. 提供高效的共识机制,确保系统在部分节点出现故障或恶意行为时仍能正常运行
  2. 相比工作量证明(PoW),PBFT能够更快地达成共识,提高交易处理速度
  3. 不需要大量计算资源,能耗更低
  4. 能够提供确定性的交易终结性,而不是像比特币那样的概率性终结

原理

PBFT的核心原理是通过多轮投票来达成共识,即使在存在恶意节点的情况下也能正常工作。基本流程如下:

  1. 预准备阶段(Pre-prepare): 主节点选择一个客户端请求,分配一个序列号,并广播给所有备份节点
  2. 准备阶段(Prepare): 所有节点验证请求,并向其他所有节点广播准备消息
  3. 确认阶段(Commit): 当节点收到至少2f个准备消息(包括自己的),它进入确认阶段并广播确认消息
  4. 执行阶段: 当节点收到至少2f+1个确认消息,它执行请求并向客户端返回结果

其中f表示系统能容忍的最大恶意节点数量,系统总节点数为3f+1。

实现代码示例

下面是一个简化的PBFT算法实现,使用Python语言:

import hashlib
import json
import time
import random
from typing import Dict, List, Set, Tuple, Optional

# 消息类型枚举
class MessageType:
    REQUEST = "REQUEST"         # 客户端请求
    PRE_PREPARE = "PRE-PREPARE" # 预准备消息
    PREPARE = "PREPARE"         # 准备消息
    COMMIT = "COMMIT"           # 确认消息
    REPLY = "REPLY"             # 回复消息

class Message:
    """消息基类,所有PBFT消息都继承自此类"""
    def __init__(self, msg_type: str, content: dict):
        self.type = msg_type
        self.content = content
        # 计算消息的哈希值,用于唯一标识
        self.digest = self.calculate_digest()
        
    def calculate_digest(self) -> str:
        """计算消息内容的哈希值"""
        serialized = json.dumps(self.content, sort_keys=True).encode('utf-8')
        return hashlib.sha256(serialized).hexdigest()
    
    def to_dict(self) -> dict:
        """将消息转换为字典格式"""
        return {
            "type": self.type,
            "content": self.content,
            "digest": self.digest
        }

class Request(Message):
    """客户端请求消息"""
    def __init__(self, client_id: str, timestamp: float, operation: str):
        content = {
            "client_id": client_id,
            "timestamp": timestamp,
            "operation": operation
        }
        super().__init__(MessageType.REQUEST, content)

class PrePrepare(Message):
    """预准备消息,由主节点发送"""
    def __init__(self, view_num: int, seq_num: int, request_digest: str, node_id: str):
        content = {
            "view_num": view_num,
            "seq_num": seq_num,
            "request_digest": request_digest,
            "node_id": node_id
        }
        super().__init__(MessageType.PRE_PREPARE, content)

class Prepare(Message):
    """准备消息,由所有节点发送"""
    def __init__(self, view_num: int, seq_num: int, request_digest: str, node_id: str):
        content = {
            "view_num": view_num,
            "seq_num": seq_num,
            "request_digest": request_digest,
            "node_id": node_id
        }
        super().__init__(MessageType.PREPARE, content)

class Commit(Message):
    """确认消息,由所有节点发送"""
    def __init__(self, view_num: int, seq_num: int, request_digest: str, node_id: str):
        content = {
            "view_num": view_num,
            "seq_num": seq_num,
            "request_digest": request_digest,
            "node_id": node_id
        }
        super().__init__(MessageType.COMMIT, content)

class Reply(Message):
    """回复消息,发送给客户端"""
    def __init__(self, view_num: int, timestamp: float, client_id: str, node_id: str, result: str):
        content = {
            "view_num": view_num,
            "timestamp": timestamp,
            "client_id": client_id,
            "node_id": node_id,
            "result": result
        }
        super().__init__(MessageType.REPLY, content)

class PBFTNode:
    """PBFT节点实现"""
    def __init__(self, node_id: str, total_nodes: int, f: int, is_primary: bool = False):
        self.node_id = node_id          # 节点ID
        self.total_nodes = total_nodes  # 总节点数
        self.f = f                      # 容错数量
        self.is_primary = is_primary    # 是否为主节点
        self.view_num = 0               # 当前视图编号
        self.seq_num = 0                # 当前序列号
        
        # 存储各类消息的集合
        self.request_pool: Dict[str, Request] = {}  # 请求池
        self.pre_prepares: Dict[Tuple[int, int], PrePrepare] = {}  # 预准备消息池
        self.prepares: Dict[Tuple[int, int, str], Set[str]] = {}   # 准备消息池
        self.commits: Dict[Tuple[int, int, str], Set[str]] = {}    # 确认消息池
        
        # 已执行的请求记录
        self.executed_requests: Set[str] = set()
        
        # 日志
        self.log: List[str] = []
    
    def add_log(self, message: str):
        """添加日志"""
        self.log.append(f"[{self.node_id}] {message}")
        print(f"[{self.node_id}] {message}")
    
    def receive_request(self, request: Request) -> None:
        """接收客户端请求"""
        self.add_log(f"收到客户端 {request.content['client_id']} 的请求: {request.content['operation']}")
        
        # 存储请求
        self.request_pool[request.digest] = request
        
        # 如果是主节点,则开始共识过程
        if self.is_primary:
            self.seq_num += 1
            # 创建并广播预准备消息
            pre_prepare = PrePrepare(
                view_num=self.view_num,
                seq_num=self.seq_num,
                request_digest=request.digest,
                node_id=self.node_id
            )
            self.add_log(f"广播预准备消息: seq={self.seq_num}, digest={request.digest[:8]}...")
            
            # 在实际系统中,这里会将消息发送给所有其他节点
            # 在模拟中,我们直接处理预准备消息
            self.receive_pre_prepare(pre_prepare)
            return pre_prepare  # 返回供其他节点处理
    
    def receive_pre_prepare(self, pre_prepare: PrePrepare) -> Optional[Prepare]:
        """接收预准备消息"""
        view_num = pre_prepare.content["view_num"]
        seq_num = pre_prepare.content["seq_num"]
        request_digest = pre_prepare.content["request_digest"]
        
        # 验证视图编号是否正确
        if view_num != self.view_num:
            self.add_log(f"拒绝预准备消息: 视图编号不匹配 {view_num} != {self.view_num}")
            return None
        
        # 检查是否已经存在相同序列号的预准备消息
        if (view_num, seq_num) in self.pre_prepares:
            existing_digest = self.pre_prepares[(view_num, seq_num)].content["request_digest"]
            if existing_digest != request_digest:
                self.add_log(f"拒绝预准备消息: 序列号 {seq_num} 已存在不同的请求")
                return None
        
        # 检查请求是否存在
        if request_digest not in self.request_pool and not self.is_primary:
            self.add_log(f"拒绝预准备消息: 请求 {request_digest[:8]}... 不在请求池中")
            return None
        
        # 存储预准备消息
        self.pre_prepares[(view_num, seq_num)] = pre_prepare
        
        # 创建并广播准备消息
        prepare = Prepare(
            view_num=view_num,
            seq_num=seq_num,
            request_digest=request_digest,
            node_id=self.node_id
        )
        
        self.add_log(f"广播准备消息: seq={seq_num}, digest={request_digest[:8]}...")
        
        # 处理自己的准备消息
        self.receive_prepare(prepare)
        return prepare  # 返回供其他节点处理
    
    def receive_prepare(self, prepare: Prepare) -> Optional[Commit]:
        """接收准备消息"""
        view_num = prepare.content["view_num"]
        seq_num = prepare.content["seq_num"]
        request_digest = prepare.content["request_digest"]
        node_id = prepare.content["node_id"]
        
        # 验证视图编号是否正确
        if view_num != self.view_num:
            self.add_log(f"拒绝准备消息: 视图编号不匹配 {view_num} != {self.view_num}")
            return None
        
        # 检查是否收到对应的预准备消息
        if (view_num, seq_num) not in self.pre_prepares:
            self.add_log(f"暂存准备消息: 尚未收到对应的预准备消息 seq={seq_num}")
            return None
        
        # 检查请求摘要是否匹配
        pre_prepare_digest = self.pre_prepares[(view_num, seq_num)].content["request_digest"]
        if pre_prepare_digest != request_digest:
            self.add_log(f"拒绝准备消息: 请求摘要不匹配 {request_digest[:8]}... != {pre_prepare_digest[:8]}...")
            return None
        
        # 存储准备消息
        key = (view_num, seq_num, request_digest)
        if key not in self.prepares:
            self.prepares[key] = set()
        self.prepares[key].add(node_id)
        
        self.add_log(f"收到准备消息: 来自节点 {node_id}, seq={seq_num}, 当前准备消息数量: {len(self.prepares[key])}")
        
        # 检查是否收到足够的准备消息(2f个)
        if len(self.prepares[key]) >= 2 * self.f:
            # 如果尚未发送确认消息,则发送
            if key not in self.commits or self.node_id not in self.commits[key]:
                commit = Commit(
                    view_num=view_num,
                    seq_num=seq_num,
                    request_digest=request_digest,
                    node_id=self.node_id
                )
                
                self.add_log(f"广播确认消息: seq={seq_num}, digest={request_digest[:8]}...")
                
                # 处理自己的确认消息
                self.receive_commit(commit)
                return commit  # 返回供其他节点处理
        
        return None
    
    def receive_commit(self, commit: Commit) -> Optional[Reply]:
        """接收确认消息"""
        view_num = commit.content["view_num"]
        seq_num = commit.content["seq_num"]
        request_digest = commit.content["request_digest"]
        node_id = commit.content["node_id"]
        
        # 验证视图编号是否正确
        if view_num != self.view_num:
            self.add_log(f"拒绝确认消息: 视图编号不匹配 {view_num} != {self.view_num}")
            return None
        
        # 存储确认消息
        key = (view_num, seq_num, request_digest)
        if key not in self.commits:
            self.commits[key] = set()
        self.commits[key].add(node_id)
        
        self.add_log(f"收到确认消息: 来自节点 {node_id}, seq={seq_num}, 当前确认消息数量: {len(self.commits[key])}")
        
        # 检查是否收到足够的确认消息(2f+1个)
        if len(self.commits[key]) >= 2 * self.f + 1 and request_digest not in self.executed_requests:
            # 执行请求
            request = self.request_pool.get(request_digest)
            if request:
                result = self.execute_request(request)
                self.executed_requests.add(request_digest)
                
                # 创建回复消息
                reply = Reply(
                    view_num=view_num,
                    timestamp=time.time(),
                    client_id=request.content["client_id"],
                    node_id=self.node_id,
                    result=result
                )
                
                self.add_log(f"执行请求并回复客户端: seq={seq_num}, result={result}")
                return reply
        
        return None
    
    def execute_request(self, request: Request) -> str:
        """执行客户端请求,返回结果"""
        # 在实际系统中,这里会执行具体的操作
        # 在模拟中,我们简单地返回操作的结果
        operation = request.content["operation"]
        self.add_log(f"执行操作: {operation}")
        return f"已执行: {operation}"

# 演示PBFT算法的运行过程
def simulate_pbft():
    # 创建4个节点,容错数量f=1,总节点数需要>=3f+1
    nodes = [
        PBFTNode(node_id=f"node-{i}", total_nodes=4, f=1, is_primary=(i==0))
        for i in range(4)
    ]
    
    # 创建客户端请求
    client_request = Request(
        client_id="client-1",
        timestamp=time.time(),
        operation="转账 10 个代币从 A 到 B"
    )
    
    print("\n===== 开始PBFT共识过程 =====\n")
    
    # 主节点接收请求并广播预准备消息
    primary_node = nodes[0]
    pre_prepare = primary_node.receive_request(client_request)
    
    # 所有非主节点接收预准备消息并广播准备消息
    prepares = []
    for node in nodes[1:]:
        # 将请求添加到请求池
        node.request_pool[client_request.digest] = client_request
        prepare = node.receive_pre_prepare(pre_prepare)
        if prepare:
            prepares.append(prepare)
    
    # 所有节点接收所有准备消息
    commits = []
    for node in nodes:
        for prepare in prepares:
            commit = node.receive_prepare(prepare)
            if commit:
                commits.append(commit)
    
    # 所有节点接收所有确认消息
    replies = []
    for node in nodes:
        for commit in commits:
            reply = node.receive_commit(commit)
            if reply:
                replies.append(reply)
    
    print("\n===== PBFT共识过程完成 =====\n")
    
    # 输出回复消息
    if replies:
        print(f"客户端收到回复: {replies[0].content['result']}")
    
    # 验证所有节点是否达成共识
    executed_count = sum(1 for node in nodes if client_request.digest in node.executed_requests)
    print(f"\n共有 {executed_count}/{len(nodes)} 个节点执行了请求")

if __name__ == "__main__":
    simulate_pbft()

PBFT算法逻辑流程图

执行阶段
确认阶段
准备阶段
预准备阶段
节点执行请求
节点回复客户端
节点广播确认消息
节点收集确认消息
确认消息数 >= 2f+1?
所有节点广播准备消息
节点收集准备消息
准备消息数 >= 2f?
主节点接收请求
主节点广播预准备消息
所有节点接收预准备消息
客户端发送请求

PBFT的其他应用场景

除了虚拟货币和区块链外,PBFT还可以应用于以下场景:

  1. 分布式数据库系统:确保数据一致性和可用性,即使在部分节点出现故障的情况下
  2. 云服务和边缘计算:在分布式云环境中提供高可用性服务
  3. 物联网(IoT)网络:在设备之间建立可信任的通信和数据共享机制
  4. 金融交易系统:确保交易的一致性和安全性
  5. 关键基础设施控制系统:如电网、水处理系统等需要高度可靠性的系统
  6. 分布式身份验证系统:确保身份信息的一致性和安全性
  7. 供应链管理:在多方参与的供应链中建立信任和追踪机制
  8. 去中心化治理系统:如DAO(去中心化自治组织)中的投票和决策机制

总结

实用拜占庭容错(PBFT)是一种高效的共识算法,能够在存在恶意节点的情况下保证系统的正常运行。其主要特点包括:

  1. 高效性:相比PoW等算法,PBFT能够更快地达成共识,提高交易处理速度
  2. 确定性终结:一旦达成共识,交易就是最终确定的,不会被回滚
  3. 低能耗:不需要解决复杂的数学难题,能耗较低
  4. 可扩展性限制:节点数量增加会导致通信复杂度急剧上升,适合节点数量有限的场景

PBFT在虚拟货币领域的应用主要集中在联盟链和许可链中,如超级账本(Hyperledger Fabric)等项目。虽然PBFT在节点规模上存在限制,但其高效、低能耗的特性使其在许多需要高可靠性的分布式系统中具有广泛的应用前景。

随着研究的深入,PBFT的变种算法不断涌现,如SBFT、HotStuff等,这些算法在保持PBFT基本优势的同时,进一步改进了其可扩展性和性能,为分布式系统提供了更多选择。

microPython的源码解析之 objset.c
隐写术,将信息隐藏起来
智能农业设备软件工程师如何实现智能温室环境控制
C#进行串口应用开发如何避免串口通信因缓冲区溢出丢失数据
python的logging库如何使用
python web应用开发神器 入门十九
车载系统软件工程师如何处理车载系统的系统日志和故障报告
microPython的源码解析之 objgetitemiter.c
python的xmlrpc库如何使用
chatGPT如何与工业软件领域结合
microPython的源码解析之 nlrx64.c
为什么Python对VR社区很重要
python的非常灵活和方便的缓存库cachetools
C#进行串口应用开发如何区分串口接收到的数据帧
streamlit如何布局
python字符串进行格式化
保护Python运行环境
智能农业设备软件工程师如何实现农业设备的精准农业应用
智能农业设备软件工程师如何实现农业设备的电池管理
linux下模拟鼠标键盘的工具xdotool
microPython的源码解析之 objobject.c
如何执行python setup.py
c#视觉应用开发中如何在C#中进行图像色调调整?
python web应用开发神器 入门二十四
量化交易系统如何获取历史市场数据?
量化交易系统中如何处理大数据中的数据清洗和预处理?
python web应用开发神器 入门十四
c#视觉应用开发中如何在C#中进行图像去除色差?
C#进行串口应用开发如何实现串口通信的调试跟踪与日志记录
量化交易系统中+如何处理风险限额和风险敞口?
C#进行串口应用开发如何修复因串口配置错误导致的通信故障
c#视觉应用开发中如何使用C#进行人脸检测?
c#视觉应用开发中如何在C#中进行图像直方图均衡化?
Python如何实现一个XML转换引擎过程
量子计算Shor算法
Python的faker库,测试工作者的福音
python如何简单实现重试逻辑
Python开源自动化工具,用于配置管理、应用部署、智能自动化ansible
量化交易策略 标准差突破
量化交易系统中+如何处理交易所的延迟和网络延迟?
python用来进行代码语法高亮的库Pygments
python可以执行字符串形式的 Python 代码的库exec
python web应用开发神器 入门九
运动控制卡
python编写一段会跳动的文字
python的一个打包工具cx_Freeze
NI-Motion如何实现一个旋转刀片(Rotating Knife)的应用的C语言示例代码
车载系统软件工程师如何实现车载系统的远程锁定和解锁
c#如何使用 USB(Universal Serial Bus)进行通信
microPython的源码解析之 parse.c
C#进行串口应用开发如何改变串口的默认端口号
NI-Motion运动控制应用中实现缓冲位置断点的C语言示例代码
车载系统软件工程师如何处理车载系统的多语言支持
microPython的源码解析之 objclosure.c
C#进行串口应用开发如何从串口读取数据
python如何实现更精确的定时任务
智能农业设备软件工程师如何实现农场管理软件平台
python如何计算隐含波动率
C#进行串口应用开发如何实现基于串口的终端工具与远程控制
microPython的源码解析之 repl.c
c#视觉应用开发中如何在C#中使用K-means算法进行图像聚类?
开源htmx库简介
智能农业设备软件工程师如何实现精准播种系统
C#进行串口应用开发如何将串口数据保存到文件
c#视觉应用开发中如何在C#中进行图像平滑处理?
智能农业设备软件工程师如何处理设备的非易失性存储管理
介绍一下labview
Python 用于协作机器人
C#进行串口应用开发如何实现串口通信的自动重连与重传功能
车载系统软件工程师如何处理车载系统的传感器校准和同步
3D建模完成以后,如何用编程语言控制这些模型的展示和动画
Python实现本地语音转文字,并且带有唤醒词功能.
详细解读一下c++模版编程,并举例
智能农业设备软件工程师如何实现农业设备的智能助理和AI应用
microPython的源码解析之 objstringio.c
车载系统软件工程师如何确保车载系统的高可靠性和可用性
Python如何使用pickle库来复制、保存和加载一个空间
C#进行串口应用开发如何避免串口通信因缓冲区阻塞问题导致的发送失败
量化交易策略 均值回归
python的aria2p库介绍
Python如何从新浪财经爬去分价表数据
数据降维技术和算法
c#视觉应用开发中如何在C#中进行图像融合?
excel 中如何使用python操作
microPython的源码解析之 emitinlinethumb.c
C#进行串口应用开发如何实现串口通信的安全访问与权限控制
python web应用开发神器 入门四
NI-Motion实现控制器的球面弧线运动控制功能C语言代码
开源的全文搜索引擎Elasticsearch
车载系统软件工程师如何处理车载系统的多任务处理能力
量化交易系统中+如何设计和实现量化交易策略?
智能农业设备软件工程师如何实现农业设备的能量回收系统
python如何开发一个远程桌面的工具
python的paramiko 库如何使用
C#进行串口应用开发如何实现基于串口的远程监控与报警系统
microPython的源码解析之 objstrunicode.c
腾讯有哪些人工智能相关的开源代码
3D动画,头发随风摆动是如何做到的
c#视觉应用开发中如何在C#中进行图像特征点匹配?
c#视觉应用开发中如何在C#中进行图像批处理?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值