Tendermint 导读|乌托邦周报 #20

无环图
2023-06-02 12:18
发布于 Mirror

如果说 Cosmos SDK 是 Layer 1 的黄埔军校,那么 Tendermint 就是黄埔军校的奠基石。

自 2017 年问世以来,Cosmos SDK 是当今使用最为广泛的 L1 框架。从自家的 Cosmos Hub,到新晋金融协议 Injective,无不是出自 Cosmos SDK 之手。而 Tendermint,作为 Cosmos SDK 背后的核心模块,更是驱动了所有这些 L1 项目。

今天我们就来解构一下 Tendermint 的底层逻辑。

本文要点:

  • 什么是 Tendermint

  • 从头到尾走一遍 Tendermint


什么是 Tendermint

来源:https://v1.cosmos.network/intro

Tendermint 由 3 部分组成:

  1. 网络层:负责节点间的 P2P 通信。

  2. 共识层:拜占庭容错(BFT)的 PoS 共识机制。

  3. 应用层接口:暴露给上层应用的接口,所谓 ABCI(Application BlockChain Interface)。

其中,网络层和共识层整体上又被称为 Tendermint Core。

Cosmos SDK 做的,其实是在 Tendermint 的基础上,进一步为大家提供了应用层的逻辑模板,包括如何治理、如何质押、干坏事怎么 slash,以及如何跨链通信。

来源:https://blog.cosmos.network/tendermint-explained-bringing-bft-based-pos-to-the-public-blockchain-domain-f22e274a0fdb

总而言之,Tendermint 把 L1 最共性的部分抽了出来,做成公共组件,让大家专心写应用逻辑就好。这就是 Tendermint 的价值所在。


从头到尾走一遍 Tendermint

理解 Tendermint,目前最好的资料便是官方文档里的这张流程图了。它从用户提交交易开始,到打包入块,到节点间达成共识,到执行交易,改变状态,完整地呈现了 Tendermint 的主线逻辑。

不过除此以外,似乎也没有其他补充性资料展开说明其中的逻辑细节。怎么办?我们不妨从头到尾扒代码看看。

用户提交 Tx

这一步骤对应流程图的左上区域。

Tendermint 在 Mempool Cache 介入,检查 Cache 中的 Tx 是否合法,合法的话才会将其加入 Mempool。

对应的逻辑在 Mempool 的 Reactor 中。Reactor 结构体用于响应 P2P 网络层的事件,最关键的是 Receive(),即收到其他节点发过来的消息后如何处理。

看看 Mempool Reactor 的实现。收到消息后首先反序列化,然后检查每一条 Tx 是否合法。

合法性主要看 Tx 的大小是否在配置的范围内,此处也可以加入自定义的检查逻辑。最终如果 Tx 合法,就加入到 Mempool 中。

Proposer 将 Tx 打包入块

Mempool 中的 Tx 打包由 CreateProposalBlock() 完成,后者会在 Mempool 中按 Tx 优先级从高到低,获取一组 Tx,放入区块中,并填充区块头。

节点间 3 阶段通信,达成共识

在区块链的语境下,共识机制讲的是所有节点按相同的顺序,执行同样的一组 Tx(状态转移),最终达到相同状态(State)的方法。

Tendermint 的共识机制和 PBFT 很相似,都有 3 个阶段,只不过命名不同。

来源:https://pmg.csail.mit.edu/papers/osdi99.pdf

PBFT 的三阶段为 Pre-prepare、Prepare、Commit。

其中,Pre-prepare 和 Prepare 阶段需要至少 2f+1f为拜占庭节点数)的节点投票,才能进入下一阶段,原因是最坏情况下,所有拜占庭节点(f个)同时广播假消息,那么合法节点数至少要超过它们(≥f+1),收到投票的节点才能判断哪边消息是真,哪边是假。拜占庭节点和合法节点数相加便得到2f+1

而在 Commit 后的 Reply 环节,客户端则只需要f+1 个确认来判断是否 OK,因为最坏情况下,所有拜占庭节点(f个)同时作恶,只要有 1 个合法节点与其反馈不一,就可以判断有问题。

最后,考虑所有拜占庭节点(f个)还可以选择不广播、不回应,因此要让这个机制能运行下去,总的节点数至少得是2f+1+f=3f+1

在 Tendermint 里,三阶段对应 Pre-vote、Pre-commit、Commit。

其中,Pre-vote 和 Pre-commit 阶段都需要至少 2f+1的节点投票,Commit 后需要至少f+1 个确认来开启下一轮。由于 Tendermint 基于 PoS,这里的节点看的不再是节点数量,而是节点的投票权(如按照质押额分配)。此外,由于节点多,公网环境复杂,且谁都可以加入,Tendermint 加入了超时机制,每个阶段只要超过 Δ 时间,就会跳过当前阶段。

来源:https://blog.cosmos.network/consensus-compare-casper-vs-tendermint-6df154ad56ae

来源:https://arxiv.org/pdf/1807.04938.pdf

实现层面上,可以分步来看。

首先,Proposer 签名并广播 Proposal。

其他节点在收到 Proposer 广播的区块后,验证区块的合法性,包括区块的高度、时间戳、关联的上一个区块的 ID 等。

若区块没问题,则签名并广播 Pre-vote,其中包含区块的 ID,否则不包含(nil)。

投票结构体的定义也可以简单看一眼。

接下来,等待一段时间,接收其他节点的 Pre-vote,直到收到三分之二节点的 Pre-vote(这种情形又称作 Polka)或超时。

Pre-vote 阶段过后,进入到 Pre-commit 阶段。检查之前有没有收到三分之二的 Pre-vote,有且自己也见着 Pre-vote 对应的区块的话,就签名并广播 Pre-commit,其中包含该区块的 ID,否则不包含(nil)。

接下来,如前一样,进入 Pre-commit 阶段的等待期。这里不再赘述。

最后,终于走到 Commit 阶段,看大家有没有达成一致(Pre-commit 阶段达成 Polka),有的话就 Commit,没有的话从头再来。

执行 Tx

执行 Commit 的区块,包括其中的所有 Tx,并更新状态。

选举下一区块的新 Proposer

Tendermint 的 Leader Election 是基于 Weighted Round-Robin 算法进行的。

来源:https://medium.com/@ppio/tendermint-introduction-and-analysis-95bc15749921

一轮走完后,先给所有节点增加优先级。然后,选择优先级最高的作为 Proposer,循环往复。

注意,被选为 Proposer 的节点在下一轮的 Priority 会排到队尾(被减去 VotingPower 之和)。

值得一提的是,上一轮的 Proposer 节点在下一轮的优先级会排到末尾。狡猾一点的话,他可以选择退出,再重新加入,这样又会按照他的质押额来赋予投票权,从而插到队伍中间。为了尽可能避免这种情况,新加入的节点的优先级会有一个惩罚系数。


以上便是 Tendermint 的全流程玩法了。后面我们将看看,构建在 Tendermint 之上的 Cosmos SDK 是如何对其进行扩展的。

0
粉丝
0
获赞
27
精选
数据来源区块链,不构成投资建议!
网站只展示作者的精选文章
2022 Tagge. With ❤️ from Lambda