<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>CaseyLuo</title>
        <link>https://paragraph.com/@luoyx</link>
        <description>undefined</description>
        <lastBuildDate>Sun, 17 May 2026 20:15:20 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Tendermint中的evidence机制]]></title>
            <link>https://paragraph.com/@luoyx/tendermint-evidence</link>
            <guid>BCGMsq1EwaFMg2Ybsa2Z</guid>
            <pubDate>Sat, 29 Oct 2022 17:14:35 GMT</pubDate>
            <description><![CDATA[在之前介绍过的tendermint共识机制中提到过，共识协议能够容忍小于1/3的byzantine节点。但是即使在>=1/3的节点出现byzantine问题后，tendermint依然提供了一个尽力而为的安全机制-evidence，用于找出系统中存在的byzantine节点并通知其他正常的节点，避免系统出现问题。需要说明的是，被发现的byzantine节点可能会受到没收stake的惩罚，但是evidence机制本身并不执行惩罚，它只是在链上提交evidence，并通知上层的应用。 首先，来介绍一下evidence的检测和产生机制。在tendermint中当前存在两类evidence，分别为DuplicateVoteEvidence和LightClientAttackEvidence。 当byzantine节点控制+1/3的投票权后，可以成功发起重复投票攻击，在同一个height的同一个round内对两个不同的block同时确认并投票，并分别与网络中其他的剩余正常节点达成+2/3共识，就可以导致tendermint网络出现不一致的确认状态。但是DuplicateVoteEviden...]]></description>
            <content:encoded><![CDATA[<p>在之前介绍过的tendermint共识机制中提到过，共识协议能够容忍小于1/3的byzantine节点。但是即使在&gt;=1/3的节点出现byzantine问题后，tendermint依然提供了一个尽力而为的安全机制-evidence，用于找出系统中存在的byzantine节点并通知其他正常的节点，避免系统出现问题。需要说明的是，被发现的byzantine节点可能会受到没收stake的惩罚，但是evidence机制本身并不执行惩罚，它只是在链上提交evidence，并通知上层的应用。</p><p>首先，来介绍一下evidence的检测和产生机制。在tendermint中当前存在两类evidence，分别为DuplicateVoteEvidence和LightClientAttackEvidence。</p><p>当byzantine节点控制+1/3的投票权后，可以成功发起重复投票攻击，在同一个height的同一个round内对两个不同的block同时确认并投票，并分别与网络中其他的剩余正常节点达成+2/3共识，就可以导致tendermint网络出现不一致的确认状态。但是DuplicateVoteEvidence机制的存在，有机会可以发现并解决这类攻击。例如当一个节点发现来自同一个节点的矛盾的投票（同一个height的同一个round内对两个不同的block同时确认并投票），就可以构造一个DuplicateVoteEvidence并广播。DuplicateVoteEvidence结构如下：</p><pre data-type="codeBlock" text="type DuplicateVoteEvidence struct {
  VoteA *Vote
  VoteB *Vote

  // abci specific information
  TotalVotingPower int64
  ValidatorPower   int64
  Timestamp        time.Time
}
"><code><span class="hljs-keyword">type</span> DuplicateVoteEvidence <span class="hljs-keyword">struct</span> {
  VoteA <span class="hljs-operator">*</span>Vote
  VoteB <span class="hljs-operator">*</span>Vote

  <span class="hljs-comment">// abci specific information</span>
  TotalVotingPower <span class="hljs-keyword">int64</span>
  ValidatorPower   <span class="hljs-keyword">int64</span>
  Timestamp        time.Time
}
</code></pre><p>其中，VoteA和VoteB就是受到的来自同一个节点的矛盾的两个投票。</p><p>light client节点没有足够的资源来验证并执行交易，只是简单向正常节点拉取所需的状态，并对header做轻量的验证工作。light client会连上全节点中的若干集合，选取一个节点作为primary，其他节点作为witnesses，向primary拉取所需状态和header，并同时向witnesses拉取header作为对比验证。这里有两种机制，一种是primary+witnesses需要包含+2/3的投票权，另一种是只需包含+1/3的投票权。第二种是默认的执行机制，因为所需资源更少，而且一般情况下集群中不会出现+1/3的byzantine节点。但是如果出现+1/3点byzantine节点，就有可能对light client节点进行欺骗。如下图所示，light client在height 11时，从primary收到了&apos;A，但从witness收到了&apos;B，存在矛盾。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/443da520537c99acf35905cb0270de464c2a36eecfd4c0ea44d122b505f33592.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>light client在验证header的过程中，一旦发现不一致的header，就会向双方各自发送LightClientAttackEvidence，LightClientAttackEvidence中记录了矛盾的block：</p><pre data-type="codeBlock" text="type LightClientAttackEvidence struct {
  ConflictingBlock *LightBlock
  CommonHeight     int64

  // abci specific information
  ByzantineValidators []*Validator
  TotalVotingPower    int64       
  Timestamp           time.Time 
}
"><code><span class="hljs-keyword">type</span> LightClientAttackEvidence <span class="hljs-keyword">struct</span> {
  ConflictingBlock <span class="hljs-operator">*</span>LightBlock
  CommonHeight     <span class="hljs-keyword">int64</span>

  <span class="hljs-comment">// abci specific information</span>
  ByzantineValidators []<span class="hljs-operator">*</span>Validator
  TotalVotingPower    <span class="hljs-keyword">int64</span>       
  Timestamp           time.Time 
}
</code></pre><p>其中ConflictingBlock为与消息接收节点矛盾的block。如上图中，light client会向primary发送包含&apos;B的LightClientAttackEvidence，向witness发送包含&apos;A的LightClientAttackEvidence。</p><p>上面介绍了DuplicateVoteEvidence和LightClientAttackEvidence的检测和产生机制。接下来介绍一下evidence的执行机制。首先，节点在收到evidence消息后，会验证evidence是否合法以及是否超时。合法且未超时的evidence会持续在全网广播，确保全部节点都收到了该evidence或者evidence超时为止。evidence有两个超时参数：MaxAgeNumBlocks和MaxAgeDuration，超时的evidence将会被忽略。由于stake的质押撤回是需要时间的，因此只要evidence的超时时间小于质押撤回时间，就可以有机会惩罚恶意节点。同时节点中也记录了evidence pool，用于evidence的去重。evidence是在链上被提交的，proposer会优先打包evidence到block上，节点在验证完evidence的合法性之后，就可以对该block进行prevote和precommit的投票，从而最终提交该evidence。</p>]]></content:encoded>
            <author>luoyx@newsletter.paragraph.com (CaseyLuo)</author>
        </item>
        <item>
            <title><![CDATA[Tendermint中的Proof of Stake协议]]></title>
            <link>https://paragraph.com/@luoyx/tendermint-proof-of-stake</link>
            <guid>a3ZIn7tvPAbC4o2UjNvK</guid>
            <pubDate>Tue, 29 Mar 2022 15:45:28 GMT</pubDate>
            <description><![CDATA[在之前的文章中，我有介绍过Tendermint的共识协议： https://mirror.xyz/0xEeEe921AA9FB236b66B22489FdF477066Dc3E74D/wbp32U9S193To3T-sCfY9_i5MZ6faO4vq3-kJqr5d4w 这是一种类似于pBFT的byzantine共识协议，pBFT共识于1999年被提出，但是一直没有大规模地落地于工业界。直到2008年，中本聪提出了采用了POW协议的比特币系统，才是第一个大规模落地的byzantine共识系统。pBFT一直没有大规模落地的原因有一点是因为协议的正确性需要保证+2/3的节点是合法的，因此在集群中节点的数量是固定的，而且新加入的节点需要比较严格的审查。如果我不对新加入的节点做严格审查，则恶意攻击者很容易搞一堆“肉鸡”节点发起攻击，破坏+2/3的正确性保证。但是如果我做了严格审查，并控制节点数量，那我还搞什么byzantine共识协议呢？直接采用性能更好的paxos/raft不是更好？（实际上有一些联盟链就是这么干的）。pBFT的缺点极大地限制了网络的规模。 在2013年比特币论坛有人提...]]></description>
            <content:encoded><![CDATA[<p>在之前的文章中，我有介绍过Tendermint的共识协议：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0xEeEe921AA9FB236b66B22489FdF477066Dc3E74D/wbp32U9S193To3T-sCfY9_i5MZ6faO4vq3-kJqr5d4w">https://mirror.xyz/0xEeEe921AA9FB236b66B22489FdF477066Dc3E74D/wbp32U9S193To3T-sCfY9_i5MZ6faO4vq3-kJqr5d4w</a></p><p>这是一种类似于pBFT的byzantine共识协议，pBFT共识于1999年被提出，但是一直没有大规模地落地于工业界。直到2008年，中本聪提出了采用了POW协议的比特币系统，才是第一个大规模落地的byzantine共识系统。pBFT一直没有大规模落地的原因有一点是因为协议的正确性需要保证+2/3的节点是合法的，因此在集群中节点的数量是固定的，而且新加入的节点需要比较严格的审查。如果我不对新加入的节点做严格审查，则恶意攻击者很容易搞一堆“肉鸡”节点发起攻击，破坏+2/3的正确性保证。但是如果我做了严格审查，并控制节点数量，那我还搞什么byzantine共识协议呢？直接采用性能更好的paxos/raft不是更好？（实际上有一些联盟链就是这么干的）。pBFT的缺点极大地限制了网络的规模。</p><p>在2013年比特币论坛有人提出了Proof of Stake的想法，Tendermint再后续将其和pBFT结合起来，解决了网络的规模的问题，使得BFT网络可以拥有动态的大规模网络节点(目前cosmos hub有150个验证节点)。只有质押了stake的节点才能拥有对应stake数量权重的投票权力，使得恶意的节点即使控制了大量的“肉鸡”节点，但是其并不能控制大量stake拥有者的私钥，因此也无法破坏协议。</p><p>相比于POW，POS还存在几个问题。一个是&quot;Nothing at stake&quot;，说的是pow网络中恶意节点要制造网络分叉是要付出算力成本的，因为一份算力只能同时在一个分叉链上挖矿。但是在pos网络中，对两个不同的block做vote签名投票是成本很低的。因此在pos中引入了&quot;惩罚&quot;机制，验证者如果被检查出曾经对不同的分叉都做过vote将会被惩罚。</p><p>另一个问题是&quot;Long Range Attack&quot;。拥有一定数量的stake的验证者在撤回质押后，可以在历史block做分叉。在pow网络中，其他节点会遵循“最长链原则”继续挖矿，新分叉需要付出极大的算力成本才能成为最长链，因此攻击成本很高。但是在pos链中，构造链的成本很低，因此其他节点无法通过客观的“最长链原则”做出判断，只能主观地选择其中一个分叉。为了避免此类攻击，pos网络采用stake延迟赎回，加上最终确认点的策略。攻击者赎回stake需要一定时间，而block被确认后，状态将被最终确定，任何分叉行为将被拒绝。</p><p>最后一个问题是，网络中的“寡头”。如果某几个验证者上面质押了绝大多数的stake，他们将拥有决定性的话语权。这个问题tendermint并未在协议里解决，而是交给了链外的社区治理来决议。</p><p>最后，对比一下以太坊的Casper协议。tendermint是基于状态机的pos协议，而casper则是基于链的pos协议。基于状态机的pos协议在分布式cap中选择了cp，但是放弃了一定的可用性，避免了分叉的出现。基于链的pos协议则相反，cap中选择了ap，允许出现一定时间的分叉，但是拥有比较高的可用性。</p>]]></content:encoded>
            <author>luoyx@newsletter.paragraph.com (CaseyLuo)</author>
        </item>
        <item>
            <title><![CDATA[Tendermint中的时间生成策略]]></title>
            <link>https://paragraph.com/@luoyx/tendermint</link>
            <guid>5vHO0WL7cne3ilhLVYU1</guid>
            <pubDate>Tue, 29 Mar 2022 15:42:42 GMT</pubDate>
            <description><![CDATA[相对论告诉我们，绝对时间并不存在。但是分布式系统的节点之前却需要相互协商出一个合理的时间，提供给上层的应用使用。 在Tendermint中，提供了一个确定性的，byzantine容错的时间源BFTTime。时间会被记录在每一个区块中，并且保证下面两个性质：1. Time Monotonicity，递增。2. Time Validity，合法。递增说的是每个区块中的时间戳需要比上一个区块大，而合法指的是区块中的时间必须来源于上一个区块的任一合法验证者的precommit消息中的时间戳。 BFTTime的时间策略是将上一个区块的验证者中的precommit中的时间戳按大小排序，而且因为不同的验证者中质押的stake个数不一，按stake划分权重，取总权重的中间值，中间值落到的验证者的precommit的时间戳即为本区块的时间戳。举个例子，例如存在4个验证者和不同的stake权重，(p1, 23), (p2, 27), (p3, 10) and (p4, 10)，p3和p4是byzantine验证者存在恶意(恶意节点权重20小于总权重70 * 1/3，因此系统可以正常工作)，他们在上一...]]></description>
            <content:encoded><![CDATA[<p>相对论告诉我们，绝对时间并不存在。但是分布式系统的节点之前却需要相互协商出一个合理的时间，提供给上层的应用使用。</p><p>在Tendermint中，提供了一个确定性的，byzantine容错的时间源BFTTime。时间会被记录在每一个区块中，并且保证下面两个性质：1. Time Monotonicity，递增。2. Time Validity，合法。递增说的是每个区块中的时间戳需要比上一个区块大，而合法指的是区块中的时间必须来源于上一个区块的任一合法验证者的precommit消息中的时间戳。</p><p>BFTTime的时间策略是将上一个区块的验证者中的precommit中的时间戳按大小排序，而且因为不同的验证者中质押的stake个数不一，按stake划分权重，取总权重的中间值，中间值落到的验证者的precommit的时间戳即为本区块的时间戳。举个例子，例如存在4个验证者和不同的stake权重，(p1, 23), (p2, 27), (p3, 10) and (p4, 10)，p3和p4是byzantine验证者存在恶意(恶意节点权重20小于总权重70 * 1/3，因此系统可以正常工作)，他们在上一个区块块precommit的时间戳分别是(p1, 100), (p2, 98), (p3, x), (p4, y)，假设恶意节点故意将时间戳设小，例如x=1，y=2，则中间权重35的验证者节点为p2，因此最终BFTTime=27，符合Time Validity。同样假如x=1000，y=2000，最终的验证者节点还是p2，同样符合Time Validity。最后，即使是一大一小x=1，y=2000，仍然不会破坏Time Validity。</p><p>上面说到bftime除了Time Validity还需要满足Time Monotonicity，Time Monotonicity比较简单，只需要验证者取max(本地时间，锁定block的时间戳)，proposer取max(本地时间，proposer时间戳)即可。这里之所以使用上一个提交的block对应的precommit的时间戳，是因为proposer在一开始广播block时无法收集到其他验证者的时间戳。因此这也会带来一个问题，block的时间无法和当前实时时间对应起来。所以在Tendermint中有一个新的时间生成策略Proposer-Based Timestamps，由proposer来决定时间戳， 再由验证者来验证时间的合法性，验证规则为:</p><p>ts - PRECISION &lt;= t &lt;= ts + MSGDELAY + PRECISION </p><p>其中t为验证者的本地时间，ts为proposer提出的时间，PRECISION则为预设的机器之间的时间误差，MSGDELAY为预设的消息延迟。假如proposer是byzantine恶意节点，提出了一个过大或者过小的ts，将会被+2/3的合法验证者拒绝。但是我认为其实这里引入预设的PRECISION和MSGDELAY会给系统带来不稳定因素，因为如果设置过大，会导致无法识别出恶意proposer，但是如果设置过小，则会导致正常的proposer无法被通过，从而影响系统可用性。</p><p>其实我认为这里更好的解决方案应该是采用truetime的去中心化时间生成算法，在合法的验证者之间广播协商出合法的时间误差范围。</p>]]></content:encoded>
            <author>luoyx@newsletter.paragraph.com (CaseyLuo)</author>
        </item>
        <item>
            <title><![CDATA[Tendermint中的共识协议-给Paxos打上byzantine补丁]]></title>
            <link>https://paragraph.com/@luoyx/tendermint-paxos-byzantine</link>
            <guid>gUReiH4FsldAD6zxXsUd</guid>
            <pubDate>Tue, 29 Mar 2022 15:38:10 GMT</pubDate>
            <description><![CDATA[Tendermint是一个通用的byzantine共识协议层，把上层的应用抽象为一个复制状态机，只要共识协议对要执行的事件和事件顺序达成共识，状态机依照次序回放事件，最终各个节点存储的状态就能够达成一致。 和常见的分布式数据库、存储等系统中常用到的共识协议paxos，raft等不同，Tendermint能够允许byzantine节点存在的环境中运行，而paxos，raft等则不行，基于他们实现的系统无法解决byzantine节点带来的问题。 而又与比特币，以太坊中使用的POW共识协议不同的点，则在于POW是一种基于链式的应用模型。基于链式的应用模型状态可能会随时出现分叉，而且参与共识的节点数量不受限制，系统中不存在一个最终的状态确认点，只能是基于“合法最长链原则”。 由于tendermint的应用模型更加接近与paxos，raft，因此为了方便大家理解tendermint共识中的核心知识，我会采用和paxos对比的方式来讲解tendermint的共识。 在paxos的实现中，集群机器数为2f + 1，可接受的故障机器数为f，因此只要故障的节点不过半数，共识协议就能继续推进。pax...]]></description>
            <content:encoded><![CDATA[<p>Tendermint是一个通用的byzantine共识协议层，把上层的应用抽象为一个复制状态机，只要共识协议对要执行的事件和事件顺序达成共识，状态机依照次序回放事件，最终各个节点存储的状态就能够达成一致。</p><p>和常见的分布式数据库、存储等系统中常用到的共识协议paxos，raft等不同，Tendermint能够允许byzantine节点存在的环境中运行，而paxos，raft等则不行，基于他们实现的系统无法解决byzantine节点带来的问题。</p><p>而又与比特币，以太坊中使用的POW共识协议不同的点，则在于POW是一种基于链式的应用模型。基于链式的应用模型状态可能会随时出现分叉，而且参与共识的节点数量不受限制，系统中不存在一个最终的状态确认点，只能是基于“合法最长链原则”。</p><p>由于tendermint的应用模型更加接近与paxos，raft，因此为了方便大家理解tendermint共识中的核心知识，我会采用和paxos对比的方式来讲解tendermint的共识。</p><p>在paxos的实现中，集群机器数为2f + 1，可接受的故障机器数为f，因此只要故障的节点不过半数，共识协议就能继续推进。paxos协议分为两个阶段：prepare/commit。prepare阶段中proposer会向多数派的accepter协商本轮的&lt;proposal id, value&gt;，如果value为空，则proposer可以自定义要提交的value，否则proposer只能选择acceptor返回的&lt;proposal id, value&gt;中最大proposal id对应的value。接着，在commit阶段中，proposer会将协商好的&lt;proposal id, value&gt;广播给多数派的accepter，acceptor收到消息后校验并提交value。在整个流程中可能会存在并行执行的多个proposer，因此他们发起的&lt;proposal id, value&gt;之间可能会存在冲突，acceptor解决冲突的原则是只提交proposal id更大的value，当多数派的acceptor都提交同一个value后，value最终被chosen。</p><p>paxos协议中之所以能够保证正确性，是因为当多数acceptor提交一个value后，proposer因为要通过prepare来选择&lt;proposal id, value&gt;，而prepare要发给多数派的acceptor，必定和某个提交了value的acceptor存在交集，因此proposer无论如何都无法发起一个除value之外的commit请求，从而保证了正确性。</p><p>在上述描述paxos节点的行为的时候，都假设了节点会按照协议要求的行为来执行，否则正确性则无法得到保证。例如proposer如果直接无视了prepare阶段中收集到的&lt;proposal id, value&gt;，而直接采用自己选定的value&apos;来发起commit，则会出现已经被提交的value被value&apos;替换的问题。</p><p>为了解决上述节点不按协议“办事”的问题，单纯依赖分布式协议是不够的，首先需要引入密码学的工具。为了防止byzantine节点恶意篡改其受到的&lt;proposal id, value&gt;内容，&lt;proposal id, value&gt;中还需要带上节点用私钥对其进行的签名，accetpor在校验受到的消息时，不能只因为proposalid大于本地值，就接受其value，还需要验证其proposalid来源的&lt;proposal id, value&gt;消息的签名是否合法，以及是否存在恶意节点对不同的&lt;proposal id, value&gt;执行多次签名投票的情况。</p><p>除了消息带上签名，其次还需要故障和byzantine节点的个数均为f，并且小于集群机器数的1/3。当然故障节点f和byzantine节点的f可能存在交集，但是假设一种极端情况，故障f与byzantine f无交集，为了能够使得还在工作的节点中正常节点仍然能够达成多数派，因此要求集群机器为3f+1。当集群机器为3f+1时，即使f的机器出现故障，剩下的2f+1节点中，byzantine节点依然小于半数，从而无法破坏协议。</p><p>最后，需要对paxos协议做一点修改，当acceptor在受到commit消息后，不能直接接受proposalid更大的value，而是检查最新受到的&lt;proposalid, value&gt;是否在prepare阶段被多数派签名过，acceptor只接受被多数派签名过的&lt;proposalid, value&gt;，并在后续锁定该value。后续接受到prepare请求时，也会将该&lt;proposalid, value&gt;签名并返回。因此，当多数派acceptor在commit某个&lt;proposalid, value&gt;后，byzantine节点将无法再有机会伪造出另外一个合法的&lt;proposalid, value&apos;&gt;，因为value&apos;无法得到多数派的签名。这里提一句，在tendermint中prevote/precommit阶段分别对应paxos中的prepare/commit阶段，在tendermint里commit阶段是最终chosen阶段，但paxos的commit阶段并不是最终chosen阶段。</p><p>在给上述paxos协议打上3个补丁后，就可以升级为byzantine的tendermint共识协议了～</p>]]></content:encoded>
            <author>luoyx@newsletter.paragraph.com (CaseyLuo)</author>
        </item>
    </channel>
</rss>