正好这些天要有一个需求要帮客户魔改Fabric-v0.6,把一些hyperchain的高级特性移植过去,借此机会把之前看过的源码在梳理一下。
下面就是对Fabric共识模块的源码分析和梳理,代码都是以Fabric-v0.6-preview为例,在1.0及后续版本中都移除了PBFT部分,用了更好的SBFT,目前这一部分还在开发中。

目录结构

可以看到共识模块目录如下。

consensus
├── controller
├── executor
├── helper
│   └── persist
├── noops
├── pbft
└── util└── events

目录含义如下

  • controller 用来控制Fabric选择什么样的共识算法,默认是noops
  • executor 封装了消息队列中对交易的处理。
  • helper 对外提供接口调用和数据持久化接口。
  • noops 提供了如何编写Fabric共识算法的Demo。
  • pbft PBFT算法的具体实现。
  • util 实现了一个peer节点到共识算法的一个消息通道,和一个消息队列。

流程概览

Fabric网络通过一个EventLoop和共识算法进行交互,所有的操作都通过对事件循环中的事件监听进行推进。

整体流程如下图所示。

Consensus模块接口

fabric/consensus/consensus.go对外提供共识模块的方法调用。

其中最核心也是每个算法必须实现的接口是Consenter

type ExecutionConsumer interface {Executed(tag interface{})                                Committed(tag interface{}, target *pb.BlockchainInfo)    RolledBack(tag interface{})                              StateUpdated(tag interface{}, target *pb.BlockchainInfo)
}type Consenter interface {RecvMsg(msg *pb.Message, senderHandle *pb.PeerID) errorExecutionConsumer
}

接口的具体实现在fabric/consensus/pbft/external.go

因为对交易的操作都是异步的,所以必须手动实现ExecutedCommittedRolledBackStateUpdated方法来监听对应动作的完成。

RecvMsg方法用来从不用的peer节点接收消息。

初始化共识模块

共识算法引擎在peer启动的时候初始化,初始化的具体函数如下所示。

// consensus/helper/engine.go
func GetEngine(coord peer.MessageHandlerCoordinator) (peer.Engine, error) {var err errorengineOnce.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")for msg := range engine.consensusFan.GetOutChannel() {engine.consenter.RecvMsg(msg.Msg, msg.Sender)}}()})return engine, err
}

GetEngine的作用是进行共识模块的初始化,同时启动一个goroutine等待消息进入。

具体的engine.consenter是在consensus/controller/controller.go里选择。

// consensus/controller/controller.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)}

默认选择的是noops,如果需要添加自己编写的共识模块需要在这里自行添加判断。

noops 只是演示如何编写Fabric共识模块,不要用在生产环境。

如果选择了PBFT则会调用consensus/pbft/pbft.go进行初始化。

使用PBFTbatch模式启动时会调用newObcBatch进行PBFT算法初始化。

PBFT只有batch一种模式。

// consensus/pbft/batch.go
func newObcBatch(id uint64, config *viper.Viper, stack consensus.Stack) *obcBatch {var err error...op.manager = events.NewManagerImpl()    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...return op
}

newObcBatch主要做了这几项工作

  • 初始化了eventLoop的消息队列。
  • 设置了消息的接收者,用来处理对应的消息。
  • 创建监听消息超时的定时器。
  • 初始化pbft算法。
  • 启动消息队列,不断监听事件的到来并且分发给接收者处理。

消息处理

Fabric的共识消息是通过eventLoop注射给对应处理函数的。

// consensus/util/events/events.go
func SendEvent(receiver Receiver, event Event) {next := eventfor {next = receiver.ProcessEvent(next)if next == nil {break}}
}func (em *managerImpl) Inject(event Event) {if em.receiver != nil {SendEvent(em.receiver, event)}
}func (em *managerImpl) eventLoop() {for {select {case next := <-em.events:em.Inject(next)case <-em.exit:logger.Debug("eventLoop told to exit")return}}
}

eventLoop函数不断的从em.events里取出事件,通过Inject注射给对应的接收者,注意,通过SendEvent注射给接收者的ProcessEvent方法。

SendEvent函数实现非常有意思,如果receiver.ProcessEvent的返回不为nil则不断的调用receiver.ProcessEvent直到找到对应的消息处理函数,在ProcessEvent函数中,其余case均为事件处理函数,唯独pbftMessage依赖SendEvent发送消息给其余函数处理。

// consensus/pbft/pbft-core.go
func (instance *pbftCore) ProcessEvent(e events.Event) events.Event {...case *pbftMessage:return pbftMessageEvent(*et)case pbftMessageEvent:msg := etlogger.Debugf("Replica %d received incoming message from %v", instance.id, msg.sender)next, err := instance.recvMsg(msg.msg, msg.sender)if err != nil {break}return nextcase *RequestBatch:err = instance.recvRequestBatch(et)case *PrePrepare:err = instance.recvPrePrepare(et)...
}

可以看到*pbftMessagepbftMessageEvent这两个case通过recvMsg的返回值又把消息分发给其余case,非常巧妙。

PBFT算法的不同阶段都会按着上面的流程映射到不同的处理函数往前推进,本质上是一个状态机。

至此Fabric的Consensus模块主要流程已经梳理清楚,熟悉了这个流程以后再结合PBFT算法的过程就可以很容易在此基础上添加新的功能了。

https://zhuanlan.zhihu.com/p/35255567

Fabric源码分析-共识模块相关推荐

  1. koa源码分析-co模块以及thunk

    Thunk以及CO模块 co4.0之前都是返回的thunk函数 之后的都是返回promise thunk thunk:在 JavaScript 语言中,Thunk 函数替换的是将多参数函数,替换成单参 ...

  2. Python3.5源码分析-sys模块及site模块导入

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的sys模块初始化 根据分析完成builtins ...

  3. nginx源码分析之模块初始化

    在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...

  4. [Abp vNext 源码分析] - 2. 模块系统的变化

    一.简要说明 本篇文章主要分析 Abp vNext 当中的模块系统,从类型构造层面上来看,Abp vNext 当中不再只是单纯的通过 AbpModuleManager 来管理其他的模块,它现在则是 I ...

  5. Canal源码分析deployer模块

    canal有两种使用方式:1.独立部署 2.内嵌到应用中. deployer模块主要用于独立部署canal server.关于这两种方式的区别,请参见server模块源码分析.deployer模块源码 ...

  6. 5章 性能平台GodEye源码分析-第三方模块

    5. 第三方模块 5.1 Crash(XCrash) Crash监控崩溃后的堆栈上传,作者采用接入爱奇艺的XCrash框架 源码分析 1.启动Crash的监控 Crash的监控通过反射启动XCrash ...

  7. WebRTC源码分析——Call模块

    目录 1. 引言 2. Call对象的创建 2.1 创建CallFactory对象 2.2 创建Call对象 2.2.1 PeerConnection.CreateCall_w 2.2.2 CallF ...

  8. 超级账本(Hyperledger Fabric)源码分析之一:总览

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 一.编译 1.环境准备 需要提前在linux或者mac机器上安装如下软件 1)Go,注意设置好gopath(笔者安装的是 ...

  9. Zepto源码分析-event模块

    源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT l ...

最新文章

  1. 测试晶面间距软件_超逼真动图解析常用15大分析测试仪器,必收藏!SEM, 红外,紫外,核磁,质谱,TEM,ICP等...
  2. 客户端稳定性优化实战,Crash率最高下降40%
  3. SAP Cloud for Customer最新版本2002 RUI如何启用adaptation模式
  4. webpack2 项目
  5. 由几个月前写的(验证码利用ashx一般处理程序来做),修改为不用以一般处理程序...
  6. 看我如何绕过Cloudflare 的 SQL 注入过滤
  7. 【C++leetcode】寻找给定字符串的最大回文子串
  8. 那些你不可错过的Java博客
  9. 简单java游戏代码_Java经典小游戏——贪吃蛇简单实现(附源码)
  10. nfc修改饭卡软件下载_NFC卡模拟,从此打卡刷电梯,饭卡工卡各种IC卡都用手机搞定!...
  11. 1024 科学计数法(C语言详解)
  12. ROS2前置基础教程 | 小鱼教你用g++编译ROS2节点
  13. 公司禁用QQ,破解方法(洋葱tor 安装配置)
  14. Windows漏洞修复报告
  15. 送给天天对着电脑或者已经脖子痛的朋友,超实用颈椎保养法
  16. 08.GPIO基础知识和工作原理
  17. 如何把PPT幻灯片压缩到最小
  18. 中国最火最流行的40个博客网站
  19. Java调用TSC打印机进行打印
  20. 华为畅享10s值得买吗_华为畅享10s多少钱?值得入手么?

热门文章

  1. System 和 Runtime 类
  2. For与Function进阶实战、Lazy的使用笔记总结
  3. vue3-network 无效
  4. linux图形界面编程基本知识
  5. 反向传播(Back propagation)算法推导具体过程
  6. [云炬创业基础笔记]第二章创业者测试24
  7. Coursera吴恩达《序列模型》课程笔记(1)-- 循环神经网络(RNN)
  8. 山西职称计算机考试报名时间 2014,2014山西省6月份职称计算机考试报名入口
  9. c++ c6386 缓冲区 溢出_Office 远程溢出漏洞测试与分析
  10. VTK修炼之道42:频域处理_高通滤波(理想+巴特沃兹)