Introduction

Imagine a group of generals scattered across a battlefield who must agree on whether to attack or retreat — but some generals may be traitors sending contradictory orders. This is the Byzantine Generals Problem, and it sits at the heart of every distributed system that must tolerate dishonest or crashed nodes.

Tendermint (Buchman, Kwon, Milosevic, 2018) is a solved Byzantine Fault-Tolerant (BFT) consensus protocol that achieves instant finality: once a block is committed, it is final — no forks, no rollbacks. It is the consensus engine behind the Cosmos blockchain ecosystem.

The protocol works in rounds, each with four phases: a designated proposer broadcasts a block, then validators exchange prevote and precommit messages via gossip. A validator only commits when it sees 23\frac{2}{3} of total voting power agree. The clever twist is locking: once a validator prevotes for a value, it is locked to it until it sees enough votes to change — this is what prevents two different blocks from ever being committed at the same height.

The key safety guarantee: as long as fewer than 13\frac{1}{3} of validators (by stake) are Byzantine, no two honest nodes will ever commit different blocks at the same height.

Try It

Step through a Tendermint consensus round with 5 validators (A–E). Each validator has equal voting power; a round needs 235+1=4\lfloor \frac{2}{3} \cdot 5 \rfloor + 1 = 4 votes to proceed. You can toggle faulty nodes that send no messages.

<!-- {{c_intro}} -->
<div class="tm-wrap">
  <div class="tm-header">
    <div class="tm-title">{{title_round}} <span id="roundNum">1</span></div>
    <div class="tm-phase" id="phaseLabel">{{phase_propose}}</div>
  </div>
  <div class="tm-validators" id="validatorRow" title="{{title_validators}}"></div>
  <div class="tm-controls">
    <span class="tm-label">{{label_faulty}}:</span>
    <div id="faultyToggles" class="tm-toggles"></div>
  </div>
  <div class="tm-pipeline" id="pipeline">
    <div class="tm-step" id="step-propose">
      <div class="step-icon">📢</div>
      <div class="step-name">{{phase_propose}}</div>
      <div class="step-desc" id="desc-propose"></div>
    </div>
    <div class="tm-arrow">→</div>
    <div class="tm-step" id="step-prevote">
      <div class="step-icon">🗳️</div>
      <div class="step-name">{{phase_prevote}}</div>
      <div class="step-desc" id="desc-prevote"></div>
    </div>
    <div class="tm-arrow">→</div>
    <div class="tm-step" id="step-precommit">
      <div class="step-icon">🔒</div>
      <div class="step-name">{{phase_precommit}}</div>
      <div class="step-desc" id="desc-precommit"></div>
    </div>
    <div class="tm-arrow">→</div>
    <div class="tm-step" id="step-commit">
      <div class="step-icon">✅</div>
      <div class="step-name">{{phase_commit}}</div>
      <div class="step-desc" id="desc-commit"></div>
    </div>
  </div>
  <div class="tm-vote-grid" id="voteGrid"></div>
  <div class="tm-status" id="statusMsg"></div>
  <div class="tm-btns">
    <button id="btnNext" type="button">{{btn_next}}</button>
    <button id="btnReset" type="button" class="ghost">{{btn_reset}}</button>
  </div>
  <div class="tm-legend">
    <span class="leg-item"><span class="leg-dot dot-ok"></span> {{legend_honest}}</span>
    <span class="leg-item"><span class="leg-dot dot-fault"></span> {{legend_faulty}}</span>
    <span class="leg-item"><span class="leg-dot dot-locked"></span> {{legend_locked}}</span>
  </div>
</div>
/* {{c_styles}} */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.tm-wrap { padding: .5rem; max-width: 520px; margin: 0 auto; }
.tm-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: .5rem; }
.tm-title { font-weight: 700; font-size: 1rem; }
.tm-phase { font-size: .85rem; font-weight: 600; color: #1d3557; background: #dde8f5; padding: .2rem .6rem; border-radius: 12px; }
.tm-validators { display: flex; gap: .4rem; margin-bottom: .5rem; flex-wrap: wrap; }
.val-chip { display: flex; align-items: center; gap: .25rem; font-size: .82rem; font-weight: 700;
            padding: .3rem .55rem; border-radius: 8px; background: #e3edf7; border: 2px solid #aac4de;
            cursor: default; transition: all .15s; }
.val-chip.proposer { border-color: #1d3557; background: #1d3557; color: #fff; }
.val-chip.faulty { background: #fde8ea; border-color: #e63946; color: #c92f3c; text-decoration: line-through; }
.val-chip.locked { border-color: #e67e22; background: #fef5e7; }
.tm-controls { display: flex; align-items: center; gap: .5rem; margin-bottom: .6rem; font-size: .82rem; }
.tm-label { color: #555; }
.tm-toggles { display: flex; gap: .35rem; flex-wrap: wrap; }
.tog-btn { font-size: .78rem; font-weight: 700; padding: .2rem .45rem; border: 1px solid #adb1b8;
           background: #f0f0f0; color: #333; border-radius: 6px; cursor: pointer; transition: all .1s; }
.tog-btn.active { background: #e63946; border-color: #c92f3c; color: #fff; }
.tm-pipeline { display: flex; align-items: flex-start; gap: .2rem; margin-bottom: .5rem; flex-wrap: wrap; }
.tm-step { flex: 1 1 80px; background: #f4f7fb; border: 1.5px solid #ccd6e0; border-radius: 10px;
           padding: .4rem .3rem; text-align: center; transition: all .2s; min-width: 72px; }
.tm-step.active { border-color: #1d3557; background: #dde8f5; }
.tm-step.done { border-color: #0a7d33; background: #e6f5ec; }
.tm-step.failed { border-color: #e63946; background: #fde8ea; }
.step-icon { font-size: 1.1rem; }
.step-name { font-size: .72rem; font-weight: 700; margin: .15rem 0; color: #1d3557; }
.step-desc { font-size: .68rem; color: #555; min-height: 1.1em; }
.tm-arrow { font-size: 1rem; color: #aaa; align-self: center; margin-top: -.6rem; }
.tm-vote-grid { margin: .4rem 0; }
.vote-row { display: flex; align-items: center; gap: .3rem; margin: .18rem 0; font-size: .8rem; }
.vote-label { width: 30px; font-weight: 700; color: #333; }
.vote-phase { display: flex; gap: .25rem; }
.vote-dot { width: 18px; height: 18px; border-radius: 4px; display: flex; align-items: center;
            justify-content: center; font-size: .65rem; font-weight: 700; border: 1.5px solid #ccc;
            background: #eee; color: #999; }
.vote-dot.yes { background: #d4edda; border-color: #0a7d33; color: #0a7d33; }
.vote-dot.no { background: #fde8ea; border-color: #e63946; color: #e63946; }
.vote-dot.pending { background: #fff; border-color: #ccc; color: #ccc; }
.tm-status { font-size: .9rem; font-weight: 600; min-height: 1.4em; margin: .4rem 0; }
.tm-status.ok { color: #0a7d33; }
.tm-status.warn { color: #c07000; }
.tm-status.bad { color: #c92f3c; }
.tm-btns { display: flex; gap: .5rem; margin-bottom: .4rem; }
button { font: 600 13px system-ui; padding: .4rem .85rem; border: 1px solid #1d3557;
         background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
button:disabled { opacity: .45; cursor: default; }
.tm-legend { display: flex; gap: .7rem; flex-wrap: wrap; font-size: .75rem; color: #555; }
.leg-item { display: flex; align-items: center; gap: .3rem; }
.leg-dot { width: 12px; height: 12px; border-radius: 3px; border: 1.5px solid; }
.dot-ok { background: #e3edf7; border-color: #aac4de; }
.dot-fault { background: #fde8ea; border-color: #e63946; }
.dot-locked { background: #fef5e7; border-color: #e67e22; }
// Code not found

Notice how the round advances only when enough votes accumulate. With 2 faulty nodes the protocol stalls — you need at least 3f+13f + 1 validators to tolerate ff Byzantine faults. Tendermint's locking rule ensures that even if a round times out and a new proposer takes over, the same value will be proposed again until it is committed.

The Real Complexity

How hard is it to reach consensus in the presence of Byzantine failures?

  • The FLP impossibility (Fischer, Lynch, Paterson, 1985) says that in a fully asynchronous network, no deterministic protocol can guarantee both safety and liveness — even with a single crash failure.
  • Tendermint's answer: it assumes partial synchrony (Dwork, Lynch, Stockmeyer, 1988). Messages may be delayed arbitrarily, but after some unknown stabilization time Δ\Delta, the network eventually becomes synchronous. Under this model, Tendermint achieves both safety and liveness.
  • Message complexity: each round requires O(n2)O(n^{2}) messages — every validator gossips its prevote and precommit to every other. For large nn this is expensive; modern designs use threshold signatures to reduce it to O(n)O(n).
  • The 13\frac{1}{3} bound is tight: if Byzantine nodes hold exactly 13\frac{1}{3} of stake, the protocol fails. This follows from the general lower bound on BFT consensus: you need at least 3f+13f + 1 nodes to tolerate ff faults.
  • Instant finality vs. probabilistic finality: Nakamoto-style Proof-of-Work gives only probabilistic finality (a fork can always be replaced by a longer chain). Tendermint gives deterministic finality — once 23\frac{2}{3} precommit, the block is irreversible.

The locking mechanism is the deep insight: a validator that has prevoted for block BB cannot precommit a different block BB' unless it sees 23\frac{2}{3} prevotes for BB' — a proof of lock-change. This prevents equivocation at the commit step.

Where It Matters

Tendermint's combination of safety, liveness, and instant finality makes it foundational across several domains:

  • Cosmos ecosystem: Tendermint Core is the consensus engine for the Cosmos Hub, Binance Chain, and over 50 sovereign blockchains connected via the Inter-Blockchain Communication (IBC) protocol. Instant finality makes cross-chain asset transfers safe.
  • Proof-of-Stake blockchains: Ethereum's Casper FFG is inspired by Tendermint's locking ideas, and many PoS systems borrow the 23\frac{2}{3} supermajority quorum.
  • Database replication: CockroachDB and TiKV use Raft (a simpler CFT variant), but BFT systems like Byzantine Paxos target cloud databases that must survive malicious operator nodes.
  • State machine replication: any service that must survive node failures — from financial exchanges to coordination services — benefits from BFT consensus when the threat model includes dishonest nodes.

Understanding Tendermint means understanding the tension between P vs NP style impossibility results and the engineering trade-offs that make real systems work.

Conclusion

Tendermint distills decades of distributed-systems research into four message phases and one elegant locking rule. It proves that you can have both safety and liveness in a network where up to 13\frac{1}{3} of participants actively try to cheat — as long as you accept that the network must eventually become synchronous.

The price is O(n2)O(n^{2}) messages per round and a validator set that must be known in advance. But the payoff — instant, deterministic finality — makes it the backbone of a new class of blockchains that can safely interoperate without trusting each other.

Next time you send tokens across the Cosmos network in seconds, you're watching Tendermint's four phases fire in real time, keeping Byzantine generals in check one round at a time.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/tendermint/Content licensed under CC BY-NC 4.0.