区块链时代的拜占庭容错:Tendermint(三)

原文题目:《Tendermint: Byzantine Fault Tolerance in the Age of Blockchains》

原文作者:Ethan Buchman

翻译:杜满想

校对:饶云坤

本文为节选

Tendermint子协议

上一章中对Tendermint共识的介绍省略了有关用于广播区块(blocks),投票(votes),交易(transactions)和其他节点信息的gossip协议的一些细节。之所以这样做是为了聚焦在共识协议本身,而不让工程实践的细节分散注意力。本章讲述一种特定的用来填充这些细节的方法,通过把这些组件实现为相对独立的反应器(reactors),在这些反应器中每个对等连接(peer connection)是复用的。

P2P网络

在启动时,每个Tendermint节点都会收到一份需要拨号的对等节点的初始列表(initial list)。对于每个对等节点,节点会保持一个持久的TCP连接(persistent TCP connection),在该连接上以速率受限的方式复用了多个子协议(subprotocols)。消息被序列化为紧凑的二进制表示,并且通过认证的加密协议对连接进行加密。

本章的其余部分的每一小节分别描述了一个独立的反应器,该反应器在每一个对等链接进行了复用。有一个额外的对等节点交换反应器(peer exchange reactor),该反应器允许节点彼此请求其他对等节点地址,并跟踪它们先前连接到的对等节点,以便保持连接其他对等点的最小数量。

共识Gossip

共识反应器(consensus reactor)封装了共识状态机(consensus state machine),用来确保当每个节点的状态发生变化时都向其所有对等节点广播其当前状态。以这种方式,每个节点跟踪所有对等节点的共识状态,只发送对等节点此刻需要的信息,或者对等节点没有的信息,以此来优化消息的gossip过程。对于每个对等节点,本地节点维护来两个例程(routine)来不断检查发送给对其等节点的新信息,即提议(proposals)和投票(votes)。信息应该以“第一稀有”(ratest first)的原则来最大限度地提高gossip的效率,并尽量减少某些信息变得不可用的概率。

区块数据

在上一章节中,假设提议信息是包含区块的。然而由于区块是从一个验证节点发出的,并且可以相当大,对于块提议节点来说把数据上传到所有其他节点的方式压力过大;如果把区块分成若干块后再广播出去会快很多。

一个常用来保证数据被安全广播的方法,就是利用Merkle树,此方法也被各种P2P协议所采用,具体方法就是允许每一段数据伴随一个简短的证明(原数据的对数级大小),用来证明该片段是整体的一部分。为了使用这种方法,根据区块大小和验证者的数量,区块被序列化并分割成适当大小的块(chunks),块(chunks)被散列成Merkle树。被签名的提议(proposals)不再包含整个区块,而是只包含Merkle的根哈希(root hash),允许网络通过协作来广播被分割后的块(chunks)。节点每次收到块(chunks)时都会通知它的对等节点,来避免把同一个块对一个节点传输多次,以此来节省带宽。

一旦接收到所有块,就对块进行反序列化和验证,以确保它正确地指向前一个块,并且其各种校验和(用Merkle树实现)是正确的。虽然先前假定验证者在接收到提案(包括块)之前不预先投票,但是通过允许验证者在收到提案之后,在接收到完整的块数据之前进行投票,可以提升性能。这意味着预先投票到最后证明是无效的块也是可以的。不管怎么样,对一个无效区块进行预提交(pre-commit)被认为是拜占庭行为。

节点通过接受块(chunks)的方式同步到最新的高度,以一次一个区块的方式进行同步(progress one block at a time)。

投票

在共识状态机中,一个块被提议以后,节点就会开始等待投票(或者本地计时器过期)以往前推进。如果一个节点刚好进入了下一个区块高度的状态下收到一个对上一个块的pre-commits投票,而这个节点如果同时是这轮区块的提议者,它也许会把pre-commits投票当作下一个块的中的LastCommit值存入区块。如果一个对等节点(peer)已经预投票,但尚未预先提交,或者已经预先提交,但尚未进入下一轮,则其被分别发送预投票(pre-votes)或预提交(pre-commits)。如果一个节点是在同步区块的情况下,它将会收到在它当前的高度下预提交(pre-commits)。

内存池

交易独立地在内存缓存中被管理,这个缓存沿用比特币的叫法就是内存池。交易被业务逻辑验证合法后加入内存池,并用有序组播算法发送给相邻节点。一个节点会为每个相邻节点维持一个例程(routine),用来确保发送交易的顺序是和自己处理的顺序是一致的。

块提议者会把内存池的有序交易列表中的交易打包进新的区块。一旦一个区块被确认提交,区块中的所有交易都会被从内存池中删除,而留下来的交易会被业务逻辑重新验证,因为账户中的其他交易被确认提交,导致它们的有效性也许会改变。

区块同步

共识反应器(consensus reactor)提供一种相对较慢的区块同步方法,这是为了实时共识而设计的,也就是说节点在处理下一个块之前,会等待接受到所有的信息来确认当下的一个块。为了适应一个节点远落后与当前高度的情况,有一个区块链反应器(blockchain reactor),这个反应器允许节点同时并行地下载多个区块,使节点可以百倍于共识反应器的速度来同步区块数据。

当一个节点链接一个新的对等节点时,这个对等节点需要把它当前区块高度发送给对方。节点并行的从所有比自己高度高的对等节点中循序的请求区块,并下载区块加入到自己的区块池(block pool)。另一个例程不断尝试从池中删除块并通过验证和执行将它们添加到区块链中,一次两个块,相对于区块链的最新状态。必须每次同时处理两个区块,因为一个区块的提交确认被包含在下一个区块的LastCommit字段中。

节点持续的查询它所有对等节点的当前高度,同时不断的并行请求区块,直到同步到其所有对等节点的最高高度,一旦同步到最高高度就会停止请求区块,并开启共识反应器。

总结

实现Tendermint区块链涉及很多子协议。这些子协议包括包括gossip区块数据和交易的共识数据(投票和提议),和新节点快速同步区块链状态的方法。

相关阅读:

区块链时代的拜占庭容错:Tendermint(一)

区块链时代的拜占庭容错:Tendermint(二)

原创文章 29 获赞 2 访问量 8028

猜你喜欢

转载自blog.csdn.net/WXblockchain1/article/details/84588019
今日推荐