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

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

阅读 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 发布的第二款编程语言。

    492 引用 • 1383 回帖 • 370 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    140 引用 • 441 回帖 • 1 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    129 引用 • 793 回帖
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    40 引用 • 40 回帖 • 1 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    5 引用 • 26 回帖 • 495 关注
  • OnlyOffice
    4 引用 • 19 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    82 引用 • 122 回帖 • 619 关注
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    5 引用 • 13 回帖
  • Wide

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

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

    30 引用 • 218 回帖 • 604 关注
  • WebSocket

    WebSocket 是 HTML5 中定义的一种新协议,它实现了浏览器与服务器之间的全双工通信(full-duplex)。

    48 引用 • 206 回帖 • 395 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 440 关注
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    76 引用 • 390 回帖
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 611 关注
  • 笔记

    好记性不如烂笔头。

    305 引用 • 780 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6581 引用 • 29550 回帖 • 249 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    314 引用 • 1667 回帖 • 3 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 4 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 697 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 521 关注
  • 倾城之链
    23 引用 • 66 回帖 • 102 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 1 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 35 关注
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖 • 1 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    35 引用 • 35 回帖
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 8 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 1 关注
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    122 引用 • 73 回帖