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

本贴最后更新于 2821 天前,其中的信息可能已经渤澥桑田

阅读 fabric 源码的共识机制部分,感觉源码难度还是有的,所以先从最简单的 requeststore 开始吧。

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

但是对于那些不是很好调试的代码来说,还有一个简单的方法,就是看代码的单元测试的程序,体会它是怎么使用的,这其实也是一个比较好的方法,下面分析 pbft 的实现源码,就是使用这种方法来分析的。

pbft 实现起来不容易,这里从它最简单的部分入手,话不多说,看代码吧:

// consensus/pbft/requeststore_test.go func TestOrderedRequests(t *testing.T) { or := &orderedRequests{} or.empty() r1 := createPbftReq(2, 1) r2 := createPbftReq(2, 2) r3 := createPbftReq(19, 1) if or.has(or.wrapRequest(r1).key) { t.Errorf("should not have req") } or.add(r1) if !or.has(or.wrapRequest(r1).key) { t.Errorf("should have req") } if or.has(or.wrapRequest(r2).key) { t.Errorf("should not have req") } if or.remove(r2) { t.Errorf("should not have removed req") } if !or.remove(r1) { t.Errorf("should have removed req") } if or.remove(r1) { t.Errorf("should not have removed req") } if or.order.Len() != 0 || len(or.presence) != 0 { t.Errorf("should have 0 len") } or.adds([]*Request{r1, r2, r3}) if or.order.Back().Value.(requestContainer).req != r3 { t.Errorf("incorrect order") } } func BenchmarkOrderedRequests(b *testing.B) { or := &orderedRequests{} or.empty() Nreq := 100000 reqs := make(map[string]*Request) for i := 0; i < Nreq; i++ { rc := or.wrapRequest(createPbftReq(int64(i), 0)) reqs[rc.key] = rc.req } b.ResetTimer() b.N = 100 fmt.Printf("N is %d\n", b.N) for i := 0; i < b.N; i++ { for _, r := range reqs { or.add(r) } for k := range reqs { _ = or.has(k) } for _, r := range reqs { or.remove(r) } } }

requeststore_test.go 开始看,它测试了两个函数:

  • TestOrderedRequests(t *testing.T)
  • BenchmarkOrderedRequests(b *testing.B)

这里的第一个测试函数是普通的测试函数,第二个是 benchmark 测试函数(注意*testing.B)

先看 createPbftReq 这个函数:

// consensus/pbft/mock_utilities_test.go func createPbftReq(tag int64, replica uint64) (req *Request) { tx := createTx(tag) txPacked := marshalTx(tx) req = &Request{ Timestamp: tx.GetTimestamp(), ReplicaId: replica, Payload: txPacked, } return }

这里就是使用传过来的 tag 与 replica 构造了 Request 对象,其中 tx 的时间属性(Seconds)与 tag 有关,在 createTx 还给定了 tx 的 type,这些不是很重要,我们只要知道是通过 tag 和 replica 构造了一个请求就行了。

继续看 orderedRequests:

type orderedRequests struct { order list.List presence map[string]*list.Element }

它保存着一个列表,还有一个 map,这里的 map 键是 list 元素的 hash,值对应于 list 的元素。

继续看:wrapRequest 函数

func (a *orderedRequests) wrapRequest(req *Request) requestContainer { return requestContainer{ key: hash(req), req: req, } }

就是把 req 变成 (hash(req), req)对,是不是很简单。。
后面的测试逻辑就很简单了,所以总的逻辑是:

创建空的 orderedRequests 并初始化
创建 3 个 req
判断 or 有没有 req1(此时为空,当然没有)
添加 req1
判断 or 有没有 req1(刚添加上,当然有)
判断 or 有没有 req2(当然没有)
删掉 r2(所以这个时候就可以得到源码里 remove 的作用,删除成功返回 true,否则返回 false)
删除 r1(删除成功)
再删除 r1(已为空,删除不成功)
检查 or 是否为空(为空)
添加 r1,r2,r3 到 or
看最后一个是不是 r3(这也体现出 requeststore 是顺序表)

第一个测试逻辑非常简单,但是可以让我们快速对源代码文件有了一定了解。

下一个测试函数是一个 benchmark 函数,本身非常的简单,我接触 golang 不久,要提的主要是 b.N 是函数执行的次数,golang 会使用不同的 N 来调用函数,多次测试取平均嘛,这个挺方便的。

另外测试结束后会提示:

100 1031034650 ns/op

它表示函数执行了 100 次,平次一次执行时间是 1031034650 纳秒。

测试到此就结束了,再看源码文件,测试没覆盖到的主要是:

type requestStore struct { outstandingRequests *orderedRequests pendingRequests *orderedRequests }

其他的函数基本上都是非常简单的,除了:

// getNextNonPending returns up to the next n outstanding, but not pending requests func (rs *requestStore) getNextNonPending(n int) (result []*Request) { for oreqc := rs.outstandingRequests.order.Front(); oreqc != nil; oreqc = oreqc.Next() { oreq := oreqc.Value.(requestContainer) if rs.pendingRequests.has(oreq.key) { continue } result = append(result, oreq.req) if len(result) == n { break } } return result }

这个函数主要是从 outstandingRequests 拿出不在 pendingRequests 的 n 个 request。

上面就是这部分的内容,非常简单的代码,关键是看代码的一个思路,后面会对 pbft 其他部分进行分析。

  • hyperledger
    3 引用
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    500 引用 • 1396 回帖 • 255 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 643 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    268 引用 • 666 回帖
  • Telegram

    Telegram 是一个非盈利性、基于云端的即时消息服务。它提供了支持各大操作系统平台的开源的客户端,也提供了很多强大的 APIs 给开发者创建自己的客户端和机器人。

    5 引用 • 35 回帖
  • OneNote
    1 引用 • 3 回帖 • 1 关注
  • Office

    Office 现已更名为 Microsoft 365. Microsoft 365 将高级 Office 应用(如 Word、Excel 和 PowerPoint)与 1 TB 的 OneDrive 云存储空间、高级安全性等结合在一起,可帮助你在任何设备上完成操作。

    5 引用 • 34 回帖
  • 禅道

    禅道是一款国产的开源项目管理软件,她的核心管理思想基于敏捷方法 scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。

    10 引用 • 15 回帖 • 3 关注
  • 职场

    找到自己的位置,萌新烦恼少。

    127 引用 • 1708 回帖
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    53 引用 • 190 回帖 • 1 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 13 关注
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    554 引用 • 675 回帖 • 1 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    498 引用 • 934 回帖
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 186 关注
  • Outlook
    1 引用 • 5 回帖 • 1 关注
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 831 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 33 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 267 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    172 引用 • 541 回帖
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    70 引用 • 193 回帖 • 414 关注
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 506 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    38 引用 • 158 回帖
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 554 关注
  • 浅吟主题

    Jeffrey Chen 制作的思源笔记主题,项目仓库:https://github.com/TCOTC/Whisper

    2 引用 • 32 回帖
  • RemNote
    2 引用 • 16 回帖 • 26 关注
  • danl
    186 关注
  • 创业

    你比 99% 的人都优秀么?

    81 引用 • 1395 回帖 • 2 关注