# Tendermint中的共识协议-给Paxos打上byzantine补丁 **Published by:** [CaseyLuo](https://paragraph.com/@luoyx/) **Published on:** 2022-03-29 **URL:** https://paragraph.com/@luoyx/tendermint-paxos-byzantine ## Content Tendermint是一个通用的byzantine共识协议层,把上层的应用抽象为一个复制状态机,只要共识协议对要执行的事件和事件顺序达成共识,状态机依照次序回放事件,最终各个节点存储的状态就能够达成一致。 和常见的分布式数据库、存储等系统中常用到的共识协议paxos,raft等不同,Tendermint能够允许byzantine节点存在的环境中运行,而paxos,raft等则不行,基于他们实现的系统无法解决byzantine节点带来的问题。 而又与比特币,以太坊中使用的POW共识协议不同的点,则在于POW是一种基于链式的应用模型。基于链式的应用模型状态可能会随时出现分叉,而且参与共识的节点数量不受限制,系统中不存在一个最终的状态确认点,只能是基于“合法最长链原则”。 由于tendermint的应用模型更加接近与paxos,raft,因此为了方便大家理解tendermint共识中的核心知识,我会采用和paxos对比的方式来讲解tendermint的共识。 在paxos的实现中,集群机器数为2f + 1,可接受的故障机器数为f,因此只要故障的节点不过半数,共识协议就能继续推进。paxos协议分为两个阶段:prepare/commit。prepare阶段中proposer会向多数派的accepter协商本轮的,如果value为空,则proposer可以自定义要提交的value,否则proposer只能选择acceptor返回的中最大proposal id对应的value。接着,在commit阶段中,proposer会将协商好的广播给多数派的accepter,acceptor收到消息后校验并提交value。在整个流程中可能会存在并行执行的多个proposer,因此他们发起的之间可能会存在冲突,acceptor解决冲突的原则是只提交proposal id更大的value,当多数派的acceptor都提交同一个value后,value最终被chosen。 paxos协议中之所以能够保证正确性,是因为当多数acceptor提交一个value后,proposer因为要通过prepare来选择,而prepare要发给多数派的acceptor,必定和某个提交了value的acceptor存在交集,因此proposer无论如何都无法发起一个除value之外的commit请求,从而保证了正确性。 在上述描述paxos节点的行为的时候,都假设了节点会按照协议要求的行为来执行,否则正确性则无法得到保证。例如proposer如果直接无视了prepare阶段中收集到的,而直接采用自己选定的value'来发起commit,则会出现已经被提交的value被value'替换的问题。 为了解决上述节点不按协议“办事”的问题,单纯依赖分布式协议是不够的,首先需要引入密码学的工具。为了防止byzantine节点恶意篡改其受到的内容,中还需要带上节点用私钥对其进行的签名,accetpor在校验受到的消息时,不能只因为proposalid大于本地值,就接受其value,还需要验证其proposalid来源的消息的签名是否合法,以及是否存在恶意节点对不同的执行多次签名投票的情况。 除了消息带上签名,其次还需要故障和byzantine节点的个数均为f,并且小于集群机器数的1/3。当然故障节点f和byzantine节点的f可能存在交集,但是假设一种极端情况,故障f与byzantine f无交集,为了能够使得还在工作的节点中正常节点仍然能够达成多数派,因此要求集群机器为3f+1。当集群机器为3f+1时,即使f的机器出现故障,剩下的2f+1节点中,byzantine节点依然小于半数,从而无法破坏协议。 最后,需要对paxos协议做一点修改,当acceptor在受到commit消息后,不能直接接受proposalid更大的value,而是检查最新受到的是否在prepare阶段被多数派签名过,acceptor只接受被多数派签名过的,并在后续锁定该value。后续接受到prepare请求时,也会将该签名并返回。因此,当多数派acceptor在commit某个后,byzantine节点将无法再有机会伪造出另外一个合法的,因为value'无法得到多数派的签名。这里提一句,在tendermint中prevote/precommit阶段分别对应paxos中的prepare/commit阶段,在tendermint里commit阶段是最终chosen阶段,但paxos的commit阶段并不是最终chosen阶段。 在给上述paxos协议打上3个补丁后,就可以升级为byzantine的tendermint共识协议了~ ## Publication Information - [CaseyLuo](https://paragraph.com/@luoyx/): Publication homepage - [All Posts](https://paragraph.com/@luoyx/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@luoyx): Subscribe to updates