Hyperledger Fabric的PBFT源码分析(一)

PBFT算法源码详解 真的好久没有写博客了,正好最近在研究PBFT,那就从PBFT开始写起吧! 先奉上大佬@byron1st写的PBFT代码:https://github.com/bigpicturelabs/simple_pbft 我会带着大家鹿一遍源代码!因为看到网上好多的博客都是互相抄袭,对大家一点帮助没有 1.服务的启动主函数 func main() { nodeID := os.Args[1] // 这边就是传进来的公司的名称 server := network.NewServer(nodeID) serv. 阅读详情

一、PBFT的原理概述

1.算法公式:

replicaCount  int 变量定义在pbftCore结构体中
N (N在代码中对应replicaCount整型变量)是所有replicas的集合,每一个replica用一个整数来表示,如{ 0, 1, 2, 3,...N - 1 }


N-1 = 3f -----> f = N- 1/3


f 是最大可容忍的出错节点,也就是说准许错为1/3

2.图解PBFT执行过程


客户端发过来的请求其实是发给主replica,这里假设所得还没有选出主replica






这里大家估计也可以看出来图3和图4是一样的,其实这是一个互相确认的过程




客户端


Client---->REQUEST--->replicas
1. REQUEST携带 operation, timestamp,给每一个REQUEST加上时间戳,这样后来的REQUEST会有高于前面的时间戳

2.replicas会接收请求,如果他们验证了条请求,就会将它写入到自己的log中。在共识算法保证下每个replica完成对该请求的执行后直接将回复返回给client:

3.REPLY携带当前的view序号和时间戳,还有replica节点的编号,会返回执行结果

4.共识算法中有一个weak certificate,在这里,client也会等待weak certificate:即有f+1个replicas回复,并且它们的回复拥有相同的 t 和 r,由于至多有f个faulty replicas,所以确保了回复是合法的。我们叫这个weak certificate为 reply certificate。

5.处于active状态每一个replica会与每一个的client共享一份秘钥。


pre-prepare阶段


1.主节点收到来自Client的一条请求并分配了一个编号给这个请求,
2.主节点会广播一条PRE-PREPARE信息给备份节点,
3.这个PRE-PREPARE信息包含该请求的编号、所在的view和自身的一个digest。
4.直到该信息送达到每一个备份节点,接下来就看收到信息的备份节点们同不同意
5.主节点分配给该请求的这个编号n,即是否accept这条PRE-PREPARE信息,

6.如果一个备份节点accept了这条PRE-PREPARE,它就会进入下面的prepare阶段。

prepare阶段


1.备份节点进入prepared阶段后,广播一条PREPARE信息给主节点和其它的备份节点,直到PREPARE信息都抵达那三个节点。同时,该备份节点也会分别收到来自其它备份节点的PREPARE信息。
2.该备份节点将综合这些PREPARE信息做出自己对编号n的最终裁决。当这个备份节点开始综合比较来自其它两个备份节点的PREPARE信息和自身的PREPARE信息时,如果该备份节点发现其它两个节点都同意主节点分配的编号,又看了一下自己,自己也同意主节点的分配,a quorum certificate with the PRE-PREPARE and 2 f matching PREPARE messages for sequence number n, view v, and request m,如果一个replica达到了英文所说的条件,比如就是上面的斜体字描述的一种情况,那么我们就说该请求在这个replica上的状态是prepared,该replica就拥有了一个证书叫prepared certificate。那我们是不是就可以说至此排序工作已经完成,全网节点都达成了一个一致的请求序列呢,每一个replica开始照着这个序列执行吧。这是有漏洞的,设想一下,在t1时刻只有replica 1把请求m(编号为n)带到了prepared状态,其他两个备份节点replica 2, replica 3还没有来得及收集完来自其它节点的PREPARE信息进行判断,那么这时发生了view change进入到了一个新的view中,replica 1还认为给m分配的编号n已经得到了一个quorum同意,可以继续納入序列中,或者可以执行了,但对于replica 2来说,它来到了新的view中,它失去了对请求m的判断,甚至在上个view中它还有收集全其他节点发出的PREPARE信息,所以对于replica 2来说,给请求m分配的编号n将不作数,同理replica 3也是。那么replica 1一个人认为作数不足以让全网都认同,所以再新的view中,请求m的编号n将作废,需要重新发起提案。所以就有了下面的commit阶段。
        需要注意的是,该备份节点会将自己收到的PRE-PREPARE和发送的PREPARE信息记录到自己的log中。
        该备份节点发出PREPARE信息表示该节点同意主节点在view v中将编号n分配给请求m,不发即表示不同意。
        如果一个replica对请求m发出了PRE-PREPARE和PREPARE信息,那么我们就说该请求m在这个replica节点上处于pre-prepared状态。


Commit阶段

紧接着prepare阶段,当一个replica节点发现有一个quorum同意编号分配时,它就会广播一条COMMIT信息给其它所有节点告诉他们它有一个prepared certificate了。与此同时它也会陆续收到来自其它节点的COMMIT信息,如果它收到了2f+1条COMMIT(包括自身的一条,这些来自不同节点的COMMIT携带相同的编号n和view v),我们就说该节点拥有了一个叫committed certificate的证书,请求在这个节点上达到了committed状态。此时只通过这一个节点,我们就能断定该请求已经在一个quorum中到达了prepared状态,寄一个quorum的节点们都同意了编号n的分配。当请求m到达commited状态后,该请求就会被该节点执行。


由此观之核心代码执行的过程如下



二、共识算法代码解析

1.代码目录结构


// GetEngine returns initialized peer.Engine
//============================================================================
//它初始化一个consenter和一个helper,并互相把一个句柄赋值给了对方。
//这样做的目的,就是为了可以让外部调用内部,内部可以调用外部
//============================================================================
func GetEngine(coord peer.MessageHandlerCoordinator) (peer.Engine, error) {
    var err error
    engineOnce.Do(func() {
        engine = new(EngineImpl)
        engine.helper = NewHelper(coord)
        engine.consenter = controller.NewConsenter(engine.helper)
        engine.helper.setConsenter(engine.consenter)
        engine.peerEndpoint, err = coord.GetPeerEndpoint()
        engine.consensusFan = util.NewMessageFan()

        go func() {
            logger.Debug("Starting up message thread for consenter")

            // The channel never closes, so this should never break
            for msg := range engine.consensusFan.GetOutChannel() {
                engine.consenter.RecvMsg(msg.Msg, msg.Sender)
            }
        }()
    })
    return engine, err
}


//==============================================================================
// NewConsenter constructs a Consenter object if not already present
//==============================================================================
//==============================================================================
//调用controller获取一个plugin,当选择是pbft算法时,它会调用pbft.go 里的
//GetPlugin(c consensus.Stack)方法,在pbft.go里面把所有的外部参数读进算法内部
//==============================================================================
func NewConsenter(stack consensus.Stack) consensus.Consenter {

    plugin := strings.ToLower(viper.GetString("peer.validator.consensus.plugin"))
    if plugin == "pbft" {
        logger.Infof("Creating consensus plugin %s", plugin)
        return pbft.GetPlugin(stack)
    }
    logger.Info("Creating default consensus plugin (noops)")
    return noops.GetNoops(stack)

}

controller目录下是共识插件选择模块的函数
---->HyperLedger提供了两种算法PBFT和noops
---->默认单节点情况下使用noops即相当于没有共识算法

func NewConsenter(stack consensus.Stack) consensus.Consenter {

    plugin := strings.ToLower(viper.GetString("peer.validator.consensus.plugin"))
    if plugin == "pbft" {
        logger.Infof("Creating consensus plugin %s", plugin)
        return pbft.GetPlugin(stack)
    }
    logger.Info("Creating default consensus plugin (noops)")
    return noops.GetNoops(stack)

}
函数中可以看出目前Hyperledger Fabric只支持PBFT和NOOPS


executor和helper是两个相互依赖的模块
---->主要提供了共识算法和外部衔接的一块代码。主要负责事件处理的转接

helper
--->这里面主要包含了对外部接口的一个调用,比如执行处理transaction,stateupdate,持久化一些对象等
noops 
--->noops相当于没有共识算法
pbft
---> HyperLedger的默认共识算法
util 
--->交互需要的工具包,最主要的一个实现的功能就是它的消息机制。


func GetPlugin(c consensus.Stack) consensus.Consenter {
    if pluginInstance == nil {
        pluginInstance = New(c)
    }
    return pluginInstance
}

func New(stack consensus.Stack) consensus.Consenter {
    handle, _, _ := stack.GetNetworkHandles()
    id, _ := getValidatorID(handle)

    switch strings.ToLower(config.GetString("general.mode")) {
    case "batch":
        return newObcBatch(id, config, stack)
    default:
        panic(fmt.Errorf("Invalid PBFT mode: %s", config.GetString("general.mode")))
    }
}

//==============================================================================//在newobcbatch时,会初始化得到一个pbftcore的一个实例,这个是算法的核心模块。//并此时会启动一个batchTimer(这个batchTimer是一个计时器,//当batchTimer timeout后会触发一个sendbatch操作,这个只有primary节点才会去做)。//当然此时会创建一个事件处理机制,这个事件处理机制是各个模块沟通的一个bridge。//==============================================================================

func newObcBatch(id uint64, config *viper.Viper, stack consensus.Stack) *obcBatch {
    var err error

    op := &obcBatch{
        obcGeneric: obcGeneric{stack: stack},
    }

    op.persistForward.persistor = stack

    logger.Debugf("Replica %d obtaining startup information", id)

    op.manager = events.NewManagerImpl() // TODO, this is hacky, eventually rip it out
    op.manager.SetReceiver(op)
    etf := events.NewTimerFactoryImpl(op.manager)
    op.pbft = newPbftCore(id, config, op, etf)
    op.manager.Start()
    blockchainInfoBlob := stack.GetBlockchainInfoBlob()
    op.externalEventReceiver.manager = op.manager
    op.broadcaster = newBroadcaster(id, op.pbft.N, op.pbft.f, op.pbft.broadcastTimeout, stack)
    op.manager.Queue() <- workEvent(func() {
        op.pbft.stateTransfer(&stateUpdateTarget{
            checkpointMessage: checkpointMessage{
                seqNo: op.pbft.lastExec,
                id:    blockchainInfoBlob,
            },
        })
    })

    op.batchSize = config.GetInt("general.batchsize")
    op.batchStore = nil
    op.batchTimeout, err = time.ParseDuration(config.GetString("general.timeout.batch"))
    if err != nil {
        panic(fmt.Errorf("Cannot parse batch timeout: %s", err))
    }
    logger.Infof("PBFT Batch size = %d", op.batchSize)
    logger.Infof("PBFT Batch timeout = %v", op.batchTimeout)

    if op.batchTimeout >= op.pbft.requestTimeout {
        op.pbft.requestTimeout = 3 * op.batchTimeout / 2
        logger.Warningf("Configured request timeout must be greater than batch timeout, setting to %v", op.pbft.requestTimeout)
    }

    if op.pbft.requestTimeout >= op.pbft.nullRequestTimeout && op.pbft.nullRequestTimeout != 0 {
        op.pbft.nullRequestTimeout = 3 * op.pbft.requestTimeout / 2
        logger.Warningf("Configured null request timeout must be greater than request timeout, setting to %v", op.pbft.nullRequestTimeout)
    }

    op.incomingChan = make(chan *batchMessage)

    op.batchTimer = etf.CreateTimer()

    op.reqStore = newRequestStore()

    op.deduplicator = newDeduplicator()

    op.idleChan = make(chan struct{})
    close(op.idleChan) // TODO remove eventually

    return op
}


func newPbftCore(id uint64, config *viper.Viper, consumer innerStack, etf events.TimerFactory) *pbftCore {
    var err error
    instance := &pbftCore{}
    instance.id = id
    instance.consumer = consumer
    //==============================================================================
    // 4. 在初始化pbftcore时,在把所用配置读进的同时,创建了三个timer
    //==============================================================================
    
    //==========================================================================
    //newViewTimer对应于viewChangeTimerEvent{},当这个timer在一定时间没有close时,
    //就会触发一个viewchange事件
    //==========================================================================
    
    instance.newViewTimer = etf.CreateTimer()
    //==========================================================================
    //vcResendTimer对应viewChangeResendTimerEvent,发出viewchange过时时会
    //触发一个将viewchange从新发送
    //==========================================================================
    
    instance.vcResendTimer = etf.CreateTimer()
    //==========================================================================
    //nullRequestTimer对应nullRequestEvent,如果主节点长期没有发送preprepare消息,
    //也就是分配了seq的reqBatch。它timeout就认为主节点挂掉了然后发送viewchange消息
    //==========================================================================
    instance.nullRequestTimer = etf.CreateTimer()

    instance.N = config.GetInt("general.N") //网络中验证器的最大数量赋值
    //==================================================================================//
    /*N是所有replicas的集合,每一个replica用一个整数来表示,依次为
    { 0, …, |N - 1 }
    简单起见,我们定义
    |N = 3f + 1
    f 是最大可容忍的faulty节点
    另外我们将一个view中的primary节点定义为replica p,
    p = v mod |N
    v 是view的编号,从0开始一直连续下去,这样可以理解为从replica 0 到 replica |N-1 依次当primary节点,当每一次view change发生时。
    */
    //==================================================================================//
    instance.f = config.GetInt("general.f") //默认的最大容错数量赋值
    if instance.f*3+1 > instance.N {        //默认的最大容错数量大于网络中验证器的最大数量
        panic(fmt.Sprintf("need at least %d enough replicas to tolerate %d byzantine faults, but only %d replicas configured", instance.f*3+1, instance.f, instance.N))
    }

    instance.K = uint64(config.GetInt("general.K")) //检查点时间段赋值

    //计算日志的大小值赋值,日志倍增器
    instance.logMultiplier = uint64(config.GetInt("general.logmultiplier"))
    if instance.logMultiplier < 2 {
        panic("Log multiplier must be greater than or equal to 2")
    }

    //日志大小计算
    instance.L = instance.logMultiplier * instance.K // 日志大小

    //自动视图改变的时间段
    instance.viewChangePeriod = uint64(config.GetInt("general.viewchangeperiod"))

    //这个节点是否故意充当拜占庭;testnet用于调试
    instance.byzantine = config.GetBool("general.byzantine")

    //请求过程超时
    instance.requestTimeout, err = time.ParseDuration(config.GetString("general.timeout.request"))
    if err != nil {
        panic(fmt.Errorf("Cannot parse request timeout: %s", err))
    }

    //重发视图改变之前超时
    instance.vcResendTimeout, err = time.ParseDuration(config.GetString("general.timeout.resendviewchange"))
    if err != nil {
        panic(fmt.Errorf("Cannot parse request timeout: %s", err))
    }

    //新的视图超时
    instance.newViewTimeout, err = time.ParseDuration(config.GetString("general.timeout.viewchange"))
    if err != nil {
        panic(fmt.Errorf("Cannot parse new view timeout: %s", err))
    }

    //超时持续
    instance.nullRequestTimeout, err = time.ParseDuration(config.GetString("general.timeout.nullrequest"))
    if err != nil {
        instance.nullRequestTimeout = 0
    }

    //广播过程超时
    instance.broadcastTimeout, err = time.ParseDuration(config.GetString("general.timeout.broadcast"))
    if err != nil {
        panic(fmt.Errorf("Cannot parse new broadcast timeout: %s", err))
    }

    //查看view发生
    instance.activeView = true

    //replicas的数量; PBFT `|R|`
    instance.replicaCount = instance.N

    logger.Infof("PBFT type = %T", instance.consumer)
    logger.Infof("PBFT Max number of validating peers (N) = %v", instance.N)
    logger.Infof("PBFT Max number of failing peers (f) = %v", instance.f)
    logger.Infof("PBFT byzantine flag = %v", instance.byzantine)
    logger.Infof("PBFT request timeout = %v", instance.requestTimeout)
    logger.Infof("PBFT view change timeout = %v", instance.newViewTimeout)
    logger.Infof("PBFT Checkpoint period (K) = %v", instance.K)
    logger.Infof("PBFT broadcast timeout = %v", instance.broadcastTimeout)
    logger.Infof("PBFT Log multiplier = %v", instance.logMultiplier)
    logger.Infof("PBFT log size (L) = %v", instance.L)

    //超时持续
    if instance.nullRequestTimeout > 0 {
        logger.Infof("PBFT null requests timeout = %v", instance.nullRequestTimeout)
    } else {
        logger.Infof("PBFT null requests disabled")
    }

    //在自动视图改变的时间段
    if instance.viewChangePeriod > 0 {
        logger.Infof("PBFT view change period = %v", instance.viewChangePeriod)
    } else {
        logger.Infof("PBFT automatic view change disabled")
    }

    // init the logs
    //跟踪法定证书请求
    instance.certStore = make(map[msgID]*msgCert)

    //跟踪请求批次
    instance.reqBatchStore = make(map[string]*RequestBatch)

    //跟踪检查点设置
    instance.checkpointStore = make(map[Checkpoint]bool)

    //检查点状态; 映射lastExec到全局hash
    instance.chkpts = make(map[uint64]string)

    //跟踪视view change消息
    instance.viewChangeStore = make(map[vcidx]*ViewChange)
    instance.pset = make(map[uint64]*ViewChange_PQ)
    instance.qset = make(map[qidx]*ViewChange_PQ)
    //跟踪我们接收后者发送的最后一个新视图
    instance.newViewStore = make(map[uint64]*NewView)

    // initialize state transfer
    //观察每一个replica最高薄弱点序列数
    instance.hChkpts = make(map[uint64]uint64)

    //检查点状态; 映射lastExec到全局hash
    instance.chkpts[0] = "XXX GENESIS"

    // 在我们使用视图改变期间最后超时
    instance.lastNewViewTimeout = instance.newViewTimeout

    //跟踪我们是否正在等待请求批处理执行
    instance.outstandingReqBatches = make(map[string]*RequestBatch)

    //对于所有已经分配我们可能错过的在视图改变期间的非检查点的请求批次
    instance.missingReqBatches = make(map[string]bool)

    //将变量的值恢复到初始状态
    instance.restoreState()

    // 执行视图改变的下一个序号
    instance.viewChangeSeqNo = ^uint64(0) // infinity

    //更新视图改变序列号
    instance.updateViewChangeSeqNo()

    return instance
}


代码走到newPbftCore的过程,等待下周更新...........




PBFT(实用拜占庭容错算法)原理及代码分析(go语言) @[TOC]PBFT原理及go语言代码实现 PBFT 前提 客户端 正常情况下的操作 预准备阶段 准备阶段 确认阶段 垃圾回收 视图切换 算法的安全性与活性 前提 在pbft算法中,用R表示副本节点集合,每个副本用{0,...,|R|-1}来表示。假设|R|=3f+1,f为出错节点的数量。 副本节点通过一系列称为“视图”(view)的配置来移动。在每一个视图中,包含一个primary(主节点),其他做为backups(备份节点)。算法的步骤如下: (1)客户端向主节点发送请求以调用服务器操作。 (2)主节点 阅读详情

相关推荐

30. 精简版PBFT使用(附代码)

之前写过一篇文章,大家尽量不要去改造共识算法,这个难度很高,尤其共识算法再与区块链底层平台结合,那真是压力山大。一个完整的PBFT拥有完善的状态机流转,除多轮次投票,还要考虑投票超时处理、View Change等,Primary节点更换等,节点异常退出及重连,网络包乱序、丢包处理等,复杂度很高。本节简单实现PBFT,根据开源SIMPLE_PBFT改造,无View Change逻辑,只实现多轮次投票逻辑,帮助大家理解学习PBFT原理,有技术实例的同学可根据本节附带的代码,进一步二次开发,例如增加PoS流程等。

菜鸟的博客 1900

区块链核心:共识算法

​什么是共识算法背景分布式系统集群设计中面临着一个不可回避的问题,一致性问题对于系统中的多个服务节点,给定一系列操作,如何试图使全局对局部处理结果达成某种程度的一致?这个一致性问题大致有如下的场景:节点之间通讯不可靠的,延迟和阻塞节点的处理可能是错误的,甚至节点自身随时可能宕机节点作恶举例说明,就比如有两家电影院同时售卖总量一定的电影票,在这样的场景下,要如何设计方式来保证两家电影院协调同步不出现超卖或者错卖的问题呢?共识算法,就是解决对某一提案(目标,投票等各种协作工作),大家达成一致意见的过程比如上述的买票问题,就可以有如下的设计:1.每次卖票打电话给其他电影院,确认当前票数2.协商售卖时间,比如一三五A卖,二四六B卖3.成立个第三方存票机构,它统一发票通过以上的设计,可以看出一个很重要的解决一致性算法的解决思路,即:将可能引发不一致的并行操作进行串行化,就是现在计算机系统里处理分布式一致性问题基础思路和唯一秘诀 著名的共识设计理论FLP 不可能性原理  共识算法的理论下限提出该定理的论文是由 Fischer, Lynch 和 Patterson 三位作者于 1985 年发表,该论文后来获得了 Dijkstra(就是发明最短路径算法的那位)奖。FLP 原理认为对于允许节点失效情况下,纯粹异步系统无法确保一致性在有限时间内完成。三人三房间投票例子三个人在不同房间,进行投票(投票结果是 0 或者 1)。三个人彼此可以通过电话进行沟通,但经常会有人时不时地睡着。比如某个时候,A 投票 0,B 投票 1,C 收到了两人的投票,然后 C 睡着了。A 和 B 则永远无法在有限时间内获知最终的结果。如果可以重新投票,则类似情形每次在取得结果前发生带入到计算机领域就是说,即便在网络通信可靠情况下,一个可扩展的分布式系统的共识问题的下限是无解。即可靠性的下限是0%CAP  分布式系统领域的重要原理CAP 原理最早由 Eric Brewer 在 2000 年,ACM 组织的一个研讨会上提出猜想,后来 Lynch 等人进行了证明• C(一致性):所有的节点上的数据时刻保持同步,即数据一致• A(可用性):每个请求都能在一定时间内接受到一个响应,即低延迟• P(分区容错):当系统发生分区时仍然可以运行的定理:任何分布式系统只可同时满足二点,没法三者兼顾。即数据一致,响应及时,可分区执行不可能同时满足。举个例子:一个分布式网路上,某一个节点有一组依赖数据A,当网络无延迟,无阻塞时,依赖于X的操作可正常进行。但网络无延迟阻塞在现实世界中是没法100%保证的,那么当网络异常时,必然会产生分布式系统的分区和孤岛,那当一个执行操作在A分区之外时,如果要保证P,即当系统发生分区时仍可运行,就需要在分布式系统中多个节点有X的备份数据,以应对分区情况。则这时候就需要在C,A之间做出选择。假如选择C,即要保证数据在分布式网络中的一致性,那么就需要在X每次改动时,需要将全网节点的X数据同步刷新成最新的状态,那么在等待数据刷新完成之前,分布式系统是不可响应X的依赖操作的,即A的功能缺失假如选择A,即要突出低延迟的实时响应。那么在响应的时候,可能全节点的X数据并没有同步到最新的状态,则会导致C的缺失。上面看上去有些绕,那么你只要记住这句话,CAP原理在分布式网络系统的应用讨论,其实就是讨论在允许网络发生故障的系统中,该选择一致性还是可靠性?如果系统重视一致性,那么可以基于ACID原则做系统设计即 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)。ACID 原则描述了对分布式数据库的一致性需求,同时付出了可用性的代价。• Atomicity:每次操作是原子的,要么成功,要么不执行;• Consistency:数据库的状态是一致的,无中间状态;• Isolation:各种操作彼此互相不影响;• Durability:状态的改变是持久的,不会失效相应的有一个BASE原则,(Basic Availiability,Soft state,Eventually Consistency)则强调了可用性。 经典的共识算法设计业内,针对节点异常的情况,会有两种分类1.故障的,不响应的节点,成为非拜占庭错误2.恶意响应的节点,称为非拜占庭错误Paxos 最早的共识算法  非拜占庭算法的代表Paxos有三种角色:• proposer:提出一个提案,等待大家批准为结案。客户端担任该角色;• acceptor:负责对提案进行投票。往往是服务端担任该角色;• learner:被告知结案结果,并与之统一,不参与投票过程。即普通节点系统运行由proposer驱动,当合法提案在一定时间内收到1/2以上投票后达成共识。因此,可得出无法达成共识的条件:1.proposer故障2.二分之一以上acceptor故障拜占庭问题与BFT(Byzantine Fault Tolerant) 算法Leslie Lamport 1982 年提出用来解释一致性问题的一个虚构模型。拜占庭是古代东罗马帝国的首都,由于地域宽广,守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致的决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将努力向不同的将军发送不同的消息,试图会干扰一致性的达成。拜占庭问题即为在此情况下,如何让忠诚的将军们能达成行动的一致。对于拜占庭问题来说,假如将军总数为 N,叛变将军数为 F,则当N>=3F+1 时,问题才有解,即叛变的将军不超过1/3时,存在有效的算法,如BFT,不论叛变者如何折腾,忠诚的将军们总能达成一致的结果。这是一个数学论证的结论,有兴趣的同学可以自行推导。PBFT  一种高效拜占庭容错共识算法PBFT是Practical Byzantine Fault Tolerance的缩写,意为实用拜占庭容错算法。该算法是Miguel Castro 和Barbara Liskov(2008年图灵奖得主)在1999年提出来的,解决了原始拜占庭容错算法效率不高的问题。他的核心思想是:对于每一个收到命令的将军,都要去询问其他人,他们收到的命令是什么。如上图,假设命令由A将军分发,假如A是作恶异常,分发给B,C,D的操作分别是1,2,3.意图扰乱共识。拜占庭容错算法上设计实现是,当B,C,D收到命令后,相互之间也会沟通从A收到的命令是否一致,从而达到识破干扰的目的。其容错的极限值就是N>=3F+1。PBFT 在区块链上的实现区块链的节点分为记账节点和普通节点两个角色记账节点负责向全网提供记账服务,并维护全局账本,每过一段时间从记账节点中选一个议长,进行命令的分发,其他记账节点则作为议员进行验证将军就是记账节点,拥有全局账本,并验证交易的有效性,过互相传达验证结果,在f共识的一般流程如下:1.任一节点接收到发送者签名的交易数据请求后,向全网广播2.所有记账节点均独立监听全网的交易数据,并记录在内存3.议长在经过t后发送共识请求提案request4.议员在收到提案后,进行相关验证,发送响应response5.任意节点在限定时间内收到至少F+1个response后,共识达成,把交易记录入区块并发布给全网,如果超时,则更换视图和议长6.任意节点在收到完整区块后,把包含的交易从内存中删除开始下一个共识循环区块产生间隔t,    记账节点n,  可容错节点数f, 视图编号v,  区块高度h, 议长编号p,  议员编号i p=(h-v)%n  未来的发展POW算法建立了比特币帝国,具有划时代的意义。但其能耗和速度问题却是制约区块链普及的两大难以解决的问题。目前POS算法是一大趋势,以太坊的Casper,EOS的DPos等都是借鉴了上述前人的设计理念做的基于应用场景的优化改造,但万变不离其宗,我和大家一样,需要不断的学习和思考,没准,能有发明出自己的共识算法的一天呢。 

PBFT算法介绍

PBFT算法详细介绍,实用拜占庭容错系统(Practical Byzantine Fault Tolerance,PBFT),是一类状态机拜占庭系统。PBFT算法由MiguelCastro和Barbara Liskov 1999年提出,初衷是为解决分布式系统中达成一致性的问题,与区块链共识机制的目标重合,其主要特点是网络具有高度容错性,在一个有3f+1个节点的网络中,失效节点数为f,网络依然能够正常运行,容错率接近33%。

hyperledger fabric v0.6pbft源码分析(一)requeststore.go

阅读fabric源码的共识机制部分,感觉源码难度还是有的,所以先从最简单的requeststore开始吧。 在阅读了部分超级账本的源码后,有一个经验就是,在阅读源码特别是大项目的源码时,可能会感到无所适从,其实这也是很正常的,我的经验是可以先从一条线开始理清代码的执行流。比如像 hyperledger 这样的平台,可以从链码的执行这条线来看源码,跟着调试一步步走,相信会简单不少。 但是对于那些不是...

weixin_30376163的博客 424

PBFT算法流程补充(二):算法正确性证明及优化

本文为万向区块链技术中心研究组撰写,文章尝试对PBFT算法的正确性证明以及算法优化等内容作一个介绍。 1. PBFT算法正确性证明 本部分介绍PBFT算法的正确性证明。 1.1 安全性(Safety)证明 PBFT算法提供的安全性(safety)的具体含义是,对于所有本地确认(commit locally)的客户端请求来说,系统中所有正常副本节点都会就这些请求的消息序号达成一致。 上述的“达成一致”,其含义又分为两种: 同一视图中的消息序号一致:对于所有在同一视图中本地确认的客户端请求来说,各正常副本节点就其消息序号会达成一致。 新旧视图中的消息序号一致:对于在新旧视图中本地确认的客户端

STM32 RTC_WaitForSynchro()死循环问题分析与LSI时钟优化实践

本文深入分析了STM32使用LSI时钟源时,调用RTC_WaitForSynchro()函数陷入死循环的根本原因。问题核心在于RTC时钟域未正确使能,导致硬件同步标志RSF无法置位。文章提供了通过显式调用RCC_RTCCLKCmd(ENABLE)函数启用RTC时钟总开关的解决方案,并分享了编写健壮RTC/BKP初始化代码、增加超时机制等最佳实践,确保系统稳定运行。

weixin_29185493的博客 510

Fabric中PBFT源码解读 (1)

1. 写在前面 笔者一直以来想学习一下PBFT的完整工程实践。但在网上搜了很多源码和博客,都没能找到一份比较独立且完整的PBFT实现。无奈之下,只能从Hyperledger Fabric的代码中学习其PBFT共识部分的代码。 因此,接下来的系列博客中,笔者将介绍在Fabric中是如何实现PBFT共识算法的。 1.1 源码版本及获取 Fabric在0.6版本中采用了PBFT,因此在从github中clone了源代码后,需要首先切换到v0.6.0-preview分支。PBFT共识相关的代码主要包含在fabric

seafooler的专栏 2229

嵌入式开发必备:手把手教你用DB-9连接器搞定RS-232串口通信(附万用表测试技巧)

本文详细解析了嵌入式开发中RS-232串口通信的硬件连接核心。从DB-9连接器的引脚定义入手,深入讲解DTE与DCE设备角色,明确直连线与交叉线的选择法则,并重点分享了使用万用表进行线缆连通性测试、电压测量及故障诊断的实战技巧,帮助开发者彻底掌握串口通信的硬件连接与排查方法。

tgb345678的博客 1166

区块链工程师路线图:从零开始的技能树与学习资源全解析

区块链技术作为分布式账本的核心,正在重塑金融、供应链和数字身份等多个领域。本文将通过gh_mirrors/aw/awesome-cs-cloudnative-blockchain项目提供的资源,为你构建一条系统的区块链工程师成长路径,从基础知识到实战开发,助你快速掌握关键技能。 ## 一、区块链工程师核心技能体系 区块链工程师需要兼具计算机科学基础与区块链特有技术。以下是必须掌握的核心能力:

gitblog_00237的博客 1217

基于ESP32-S3与模块化设计的立创桌面充电站:从硬件架构到Web控制实战

本文详细介绍了基于ESP32-S3与模块化设计的立创桌面充电站项目,涵盖从硬件架构到Web控制的全流程实战。项目采用模块化设计,支持自由组合快充模块,并通过ESP32-S3实现智能监控,用户可通过本地网页实时查看各接口电压、电流与功率数据。文章重点解析了基板、连接板与充电模块三大核心部件的设计,特别是大电流PCB的“开窗贴铜”处理技巧,并提供了固件刷写与Web控制面板的配置指南。

weixin_36122351的博客 293

单细胞数据分析(三):单细胞聚类分析

本文介绍了单细胞聚类分析的基本概念及其在单细胞RNA测序(scRNA-seq)数据中的应用。单细胞聚类分析通过将具有相似基因表达模式的细胞分组到不同的簇中,帮助识别细胞类型、状态和功能。文章详细展示了使用R语言中的Seurat包进行单细胞数据聚类分析的步骤,包括数据加载、降维、聚类和结果可视化。通过FindNeighbors和FindClusters函数,文章展示了如何基于降维数据进行细胞聚类,并选择合适的分辨率值。

专注生信领域 1906

Hyperleger源码分析--共识算法

共识算法(consensus) peer节点启动的时候根据配置文件core.yaml文件配置项peer.validator.consensus.plugin选择采用哪种共识算法。目前Fabric实现了两种共识算法NOOPS和PBFT,默认是NOOPS: NOOPS:是一个供开发和测试使用的插件,会处理所有收到的消息。PBFT:PBFT算法实现。 0x01 插件接口 Cons

李赫的专栏 9577

【企业智能体开发】优化模型成本、延迟与失败降级

小林的培训快开始时,服务台花很久“思考最优回答”,体验并不会更好。反过来,为了省钱而始终选最轻的模型,若连房间、连接方式和任务状态都识别不稳,后续错误检索和重复建单会造成更大代价。企业 Agent 的优化对象不是单次模型调用价格,而是任务在可接受时间内、安全地推进到正确结果的总成本。

Mr数据杨 893

超级账本源码分析(十二) - 共识机制(排序服务)

1

yzpbright的博客 1345

解锁 Bootloader 不再难!HyperOS澎湃系统小米与红米手机通用

必要时,可以在工具右上角安装驱动模块,手动安装驱动。解决方法:确保手机升级到最新稳定版,登录同一个小米账号,并在。新机型解锁时需要等待一段时间,通常为 7 天。如果账号安全评分较低,解锁等待时间会更长。如果解锁失败提示权限不足,说明账号存在安全问题。出现这个错误时,通常是因为网络不稳定。如果解锁次数已满,需要等到下个月。解锁后,手机会重启,首次开机会稍微慢一些,等耐心等待即可。按钮,开始解锁过程,注意:解锁会清除手机内所有数据。7次,开启开发者选项。,右键解压到指定文件夹。,使用小米账号登录。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 7221

光伏微电网蓄电池储能控制系统设计及动态性能分析

本文构建了光伏微电网蓄电池储能控制系统的完整理论体系。在系统架构方面,提出了基于直流母线电压平衡的多时间尺度能量管理理论,建立了光伏发电单元的二阶物理模型和MPPT动态跟踪算法。针对蓄电池系统,设计了融合二阶RC等效电路与扩展卡尔曼滤波的SOC估计方法,误差控制在3%以内。双向DC-DC变换器采用状态空间平均建模方法,推导了小信号传递函数,为闭环控制提供理论基础。该体系实现了从瞬时功率平衡到长期能量调度的多层级协同控制,为微电网稳定运行提供了系统的解决方案。

AI的内部世界的博客 191

区块链汽车租赁系统设计

基于Fabric的共享汽车系统设计实现一、项目描述1. 项目意义2. 项目实施阶段第一阶段第二阶段二、项目设计1.系统功能模块设计2.证书颁发设计3.智能合约设计4.第二阶段设计三、具体代码细节1.区块链网络的搭建2.智能合约编写3.源码分析 基于fabric的共享汽车租赁系统项目复盘 一、项目描述 将区块链和共享汽车结合的数据结算和共享系统框架, 在当前流行的区块链实现平台上进行部署, 利用区块链的分布式存储、 加密算法和时间戳服务器等技术来保证数据安全存储的同时设计系统关键业务流程的智能合约, 并为了提

热爱生活的博客 3798

D19: OpenClaw 安全性配置指南

在 OpenClaw 的 30 天探索旅程中,我们已经探讨了邮件自动化(D18)。今天进入安全专题,我将分享一个至关重要的话题:OpenClaw 安全性配置指南。 随着 OpenClaw 深入工作流核心,它掌握了越来越多的敏感信息: API Keys(GitHub、飞书、Notion、Jira...) 企业数据(代码库、文档、聊天记录) 个人数据(日历、邮件、任务) 系统权限(文件读写、命令执行、网络访问) 安全不是可选项,而是必选项。一次配置失误可能导致: API Key 泄露 → 账号被盗用权限

刘一说的IT专栏 203

区块链学习路线

一、编程基础 1、linux/unix 安装与命名 2、C++ 面向对象、泛型、STL,BOOST,OPENSSL 3、算法 3.1 常用算法:排序 3.2 基础算法思想:贪心算法、分治算法,递归、递推、 4、数据结构 链表、队列、栈、二叉树 5、GO语言 5.1并发编程 5.2网络编程 6、JS ...

weixin_33906657的博客 550

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Golang-区块链

此外,区块链的底层实现,比如如何用Golang构建简单的区块链,包括区块结构、工作量证明、网络通信等,这些实践项目能巩固知识。理解去中心化、分布式账本、共识机制(PoW/PoS/PBFT)、智能合约、默克尔树、UTXO模型等基础概念。工具链:Hardhat/Truffle(测试框架)、MetaMask集成、The Graph(链下索引)。Hyperledger Fabric:用Go编写链码(Chaincode),理解背书策略、通道机制。优化网络层:消息序列化(Protobuf)、连接池管理、流量控制。

python_reader的博客 577

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

区块链基础:共识算法

在区块链网络中,谁获得记账权是通过全网节点间所达成的共识来决定的;共识算法即这种“共识”的算法/代码体现;共识算法解决了拜占庭将军问题,即让一群人在彼此不信任的情况下还能在一起自动协调工作;本套课程带你认识常用的共识算法及其代码实现;

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

共识算法—拜占庭容错系统(PBFT)

课程目标:理解拜占庭容错系统(PBFT);适用人群:大数据/Java基础人群课程收益:理解拜占庭容错系统(PBFT); 课程配套学习资料,建议学员学习过程中跟着视频教程实操,可理解更加深入。技术问题可在下方留言,每晚8点我会准时答疑。感谢观看,祝您学习愉快!

PBFT代码实现

客户端 var clientCmd = &cobra.Command{ Use: "client", Short: "client manage", Run: func(cmd *cobra.Command, args []string) { // 获取客户端的端口 port, err := cmd.Flags().GetInt("port") if err != nil { log.Println("get param error: ", err) } // 客户端

qq_31639829的博客 4333
上一篇: JIRA项目管理
下一篇: Java文件上与下载代码-完整代码案例
The_Web3_社区
博客等级 码龄10年 388粉丝 154原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The_Web3_社区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值