好好学习,天天向上

  • 后端开发
    • Rust
  • 区块链
    • BTC
    • Layer2
  • 经济投资
  • 文学创作
    • 哲学思考
    • 随笔
HhxxTtxs
人生到处知何似,应似飞鸿踏雪泥。
  1. 首页
  2. 区块链
  3. 正文

理解共识算法----Tendermint

2 8 月, 2025 84点热度 0人点赞 0条评论
内容 隐藏
1 什么是Tendermint共识算法
2 Tendermint共识算法流程
2.1 常规共识流程
2.2 视图切换(view-change)
2.3 超时的处理
2.4 锁的概念
3 Tendermint共识算法的关键点
4 与PBFT的主要区别
5 简单代码实现

什么是Tendermint共识算法

Tendermint 是一种基于拜占庭容错 (Byzantine Fault Tolerant, BFT) 的区块链共识算法,旨在实现高性能、高安全性的分布式状态机复制。它由 Tendermint 团队设计,因 Cosmos 模块化区块链项目的使用而被人熟知。

Tendermint可以理解为PBFT算法的一个变种与优化,优化的主要目的是降低PBFT算法的复杂度,包括逻辑实现的复杂度以及算法复杂度。

Tendermint共识算法流程

下图是来自tendermint官方的一张状态流转图,很清晰的展示了整个共识的流程。

Height:理解为出块的高度,出一个块,Height+1。

Round:在每一个Height中,也就是共识出块当中,可能会出现共识失败的情况,一个round就代表该高度下的一轮共识,可能会出现在一个Height下多轮才成功出块的情况。

常规共识流程

如上图所示,Tendermint共识算法主要流程如下:

  1. Propose:区块提议者(proposer)也就是其中一个validator提议一个区块,并发送给其他验证者。
  2. Prevote:其他validator接收到后校验区块的合法性,如果合法就广播prevote消息。
  3. Precommit:validator接收到超过2/3节点的prevote消息,如果合法就广播Precommit消息。
  4. Commit:validator接收到超过2/3节点的Precommit消息,就本地执行区块,并写入存储。

视图切换(view-change)

Tendermint共识算法的一大创新就在将view-change与普通共识过程统一了起来,如果常规共识流程的某一个阶段未达成共识,按照图中所示,验证者会广播 Nil ,该 Nil 消息会流转下去,进入下一个 round。这里有一个关键点是每一个round,tendermint都会更换proposer。那么其实本次round结束,不管本次round共识是否达成都会view-change。

超时的处理

在proposal阶段,非区块提议者节点会启动一个定时器T,如果在一段时间内(超时时间是动态调整的),没有收到本次round proposer发送的消息,那么就投票给一个特殊的空块,共识的流程会在空块的继续上继续进行prevote、precommit、commit,只不过到了commit阶段不会将空块写入区块链,直到下一轮选出一个新的区块提议者,相当于本轮空转了。

锁的概念

这里view-change与普通共识流程统一后就会有一个问题?如果当前round共识失败了,那下一个新的proposer如何处理上一个round提出的遗留下的block呢?

例如在precommit阶段,有一部分验证者收到了超过2/3的投票,有一部分没收到。那么收到的那部分验证者就会认为在该Height上达成了一致。没收到的验证者则等待下一个round。那么如果新的区块提议者(proposer)作恶,在该Height上面,提交一个新的区块,那么就有一部分节点会在该Height上产生“二义性”不知道是用上一个round提供的区块,还是新的区块了。

所以Tendermint共识算法规定,如果一个验证者接收到了超过2/3的Prevote消息(也就是该验证者需要发出precommit该区块的消息),该验证者就被锁定在该区块。

那么接下来的共识流程就如下图所示:

如果有一部分节点被锁定,那么新的Proposer如果是被锁定的节点,就广播上一个Proposer提出的区块+锁定证明(自己已经接收到超过2/3节点关于该区块的Prevote证明),那么不管该节点是否锁定,都会投票给上一个Proposer提出的区块。

如果新的Proposer不是被锁定的节点,它在同一个Height提议了新的区块,就有两种情况,一种是被锁定的节点少于1/3,那么当被锁定的节点收到超过2/3节点的对新节点的投票时,它解锁投票给新区块。另一种情况就是这些节点数量可能大于1/3,无法收到超过2/3节点的对新节点投票,那么本次round也将无法达成共识,只有通过不断轮换 Proposer 使其最后落在一个锁定在迁移区块的验证者上面,从而达成一致。

Tendermint共识算法的关键点

  1. 每一轮都会更换Proposer,将view-change和普通共识流程统一起来,使整个共识流程变的简单。
  2. 通过锁定机制,保证系统安全性。

与PBFT的主要区别

  1. PBFT需要显式的视图变更消息,节点间交换大量状态和日志,保证状态一致性。而Tendermint在设计上实现了出块流程与视图切换的无缝结合(统一),避免了复杂状态同步。
  2. PBFT在进行view-change的时候需要传递大量的信息(需要传递历史执行信息),但是Tendermint不用,所以相对于PBFT O(n^3) 的复杂度,Tendermint 是 O(n^2) 的,复杂度的不同就差在传递消息量上面。

简单代码实现

来自AI,供学习使用

import random

class Node:
    def __init__(self, node_id, total_nodes):
        self.id = node_id
        self.total_nodes = total_nodes
        self.locked_block = None       # 已锁定区块(高度的当前锁)
        self.locked_round = -1         # 锁定的轮次

    def propose_block(self, round_number):
        # 提议区块由 proposer 产生,简单用字符串表示
        block = f"Block_H{height}_R{round_number}_Proposer{self.id}"
        print(f"Node {self.id} proposes block: {block}")
        return block

    def prevote(self, block, round_number):
        # 判断是否投票给该区块,模拟简单规则:
        # 如果有锁定区块且锁定轮次 >= 当前轮次,则投票锁定区块
        # 否则投票给提议区块(假设有效)
        if self.locked_block and self.locked_round >= round_number:
            print(f"Node {self.id} prevotes for locked block: {self.locked_block}")
            return self.locked_block
        else:
            print(f"Node {self.id} prevotes for proposed block: {block}")
            return block

    def precommit(self, prevotes, round_number):
        # 统计 prevotes 投票结果
        vote_counts = {}
        for vote in prevotes:
            vote_counts[vote] = vote_counts.get(vote, 0) + 1
        # 查找得票超过 2/3 的区块
        threshold = (2 * self.total_nodes) // 3 + 1
        for block, count in vote_counts.items():
            if count >= threshold and block != "nil":
                self.locked_block = block
                self.locked_round = round_number
                print(f"Node {self.id} precommits block: {block}")
                return block
        print(f"Node {self.id} precommits nil")
        return "nil"

def run_tendermint_consensus(nodes, height):
    round_number = 0
    committed_block = None

    while True:
        print(f"\n=== Height {height} Round {round_number} ===")

        proposer_id = round_number % len(nodes)
        proposer = nodes[proposer_id]

        # Propose 阶段
        proposed_block = proposer.propose_block(round_number)

        # Prevote 阶段
        prevotes = []
        for node in nodes:
            vote = node.prevote(proposed_block, round_number)
            prevotes.append(vote)

        # 统计 prevote 投票是否达到 2/3
        vote_counts = {}
        for vote in prevotes:
            vote_counts[vote] = vote_counts.get(vote, 0) + 1
        threshold = (2 * len(nodes)) // 3 + 1

        # Precommit 阶段
        precommits = []
        if any(count >= threshold and block != "nil" for block, count in vote_counts.items()):
            # 找出获得超过 2/3 的区块
            for block, count in vote_counts.items():
                if count >= threshold and block != "nil":
                    block_to_commit = block
                    break
            for node in nodes:
                precommit_vote = node.precommit(prevotes, round_number)
                precommits.append(precommit_vote)

            # 统计 precommit 投票
            precommit_counts = {}
            for vote in precommits:
                precommit_counts[vote] = precommit_counts.get(vote, 0) + 1
            if precommit_counts.get(block_to_commit, 0) >= threshold:
                committed_block = block_to_commit
                print(f"\nBlock committed at height {height}: {committed_block}")
                break
        else:
            print("No block got enough prevotes, moving to next round")

        round_number += 1

if __name__ == "__main__":
    total_validators = 4  # 4 个节点
    height = 1

    # 初始化节点
    nodes = [Node(i, total_validators) for i in range(total_validators)]

    run_tendermint_consensus(nodes, height)

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 共识算法 区块链 链开发
最后更新:2 8 月, 2025

hhxxttxs

五年服务端开发,现专职区块链,偏零知识Layer2工程方向

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

Archives

  • 2026 年 2 月
  • 2025 年 9 月
  • 2025 年 8 月
  • 2025 年 7 月
  • 2025 年 1 月
  • 2024 年 9 月
  • 2024 年 8 月
  • 2024 年 7 月
  • 2024 年 6 月
  • 2024 年 5 月
  • 2024 年 4 月
  • 2024 年 3 月

Categories

  • BTC
  • cuda
  • L2
  • rust
  • 其他
  • 区块链
  • 后端开发
  • 哲学思考
  • 文学创作
  • 算法
  • 经济投资
  • 链开发
  • 零知识

COPYRIGHT © 2024 好好学习,天天向上. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang