CometBFT vs. X
CometBFT is broadly similar to two classes of software. The first class consists of distributed key-value stores, like Zookeeper, etcd, and consul, which use non-BFT consensus. The second class is known as “blockchain technology”, and consists of both cryptocurrencies like Bitcoin and Ethereum, and alternative distributed ledger designs like Hyperledger’s Burrow.Zookeeper, etcd, consul
Zookeeper, etcd, and consul are all implementations of key-value stores atop a classical, non-BFT consensus algorithm. Zookeeper uses an algorithm called Zookeeper Atomic Broadcast, while etcd and consul use the Raft log replication algorithm. A typical cluster contains 3-5 machines, and can tolerate crash failures in less than 1/2 of the machines (e.g., 1 out of 3 or 2 out of 5), but even a single Byzantine fault can jeopardize the whole system. Each offering provides a slightly different implementation of a featureful key-value store, but all are generally focused around providing basic services to distributed systems, such as dynamic configuration, service discovery, locking, leader-election, and so on. CometBFT is in essence similar software, but with two key differences:- It is Byzantine Fault Tolerant, meaning it can only tolerate less than 1/3 of machines failing, but those failures can include arbitrary behavior - including hacking and malicious attacks.
- It does not specify a particular application, like a fancy key-value store. Instead, it focuses on arbitrary state machine replication, so developers can build the application logic that’s right for them, from key-value store to cryptocurrency to e-voting platform and beyond.
Bitcoin, Ethereum, etc
Tendermint consensus algorithm, adopted by CometBFT, emerged in the tradition of cryptocurrencies like Bitcoin, Ethereum, etc. with the goal of providing a more efficient and secure consensus algorithm than Bitcoin’s Proof of Work. In the early days, Tendermint consensus-based blockchains had a simple currency built in, and to participate in consensus, users had to “bond” units of the currency into a security deposit which could be revoked if they misbehaved -this is what made Tendermint consensus a Proof-of-Stake algorithm. Since then, CometBFT has evolved to be a general purpose blockchain consensus engine that can host arbitrary application states. That means it can be used as a plug-and-play replacement for the consensus engines of other blockchain software. So one can take the current Ethereum code base, whether in Rust, or Go, or Haskell, and run it as an ABCI application using CometBFT. Indeed, we did that with Ethereum. And we plan to do the same for Bitcoin, ZCash, and various other deterministic applications as well. Another example of a cryptocurrency application built on CometBFT is the Cosmos network.Other Blockchain Projects
Fabric takes a similar approach to CometBFT, but is more opinionated about how the state is managed, and requires that all application behavior runs in potentially many docker containers, modules it calls “chaincode”. It uses an implementation of PBFT. from a team at IBM that is augmented to handle potentially non-deterministic chaincode. It is possible to implement this docker-based behavior as an ABCI app in CometBFT, though extending CometBFT to handle non-determinism remains for future work. Burrow is an implementation of the Ethereum Virtual Machine and Ethereum transaction mechanics, with additional features for a name-registry, permissions, and native contracts, and an alternative blockchain API. It uses CometBFT as its consensus engine, and provides a particular application state.ABCI Overview
The Application BlockChain Interface (ABCI) allows for Byzantine Fault Tolerant replication of applications written in any programming language.Motivation
Thus far, all blockchains “stacks” (such as Bitcoin) have had a monolithic design. That is, each blockchain stack is a single program that handles all the concerns of a decentralized ledger; this includes P2P connectivity, the “mempool” broadcasting of transactions, consensus on the most recent block, account balances, Turing-complete contracts, user-level permissions, etc. Using a monolithic architecture is typically bad practice in computer science. It makes it difficult to reuse components of the code, and attempts to do so result in complex maintenance procedures for forks of the codebase. This is especially true when the codebase is not modular in design and suffers from “spaghetti code”. Another problem with monolithic design is that it limits you to the language of the blockchain stack (or vice versa). In the case of Ethereum which supports a Turing-complete bytecode virtual-machine, it limits you to languages that compile down to that bytecode; while the list is growing, it is still very limited. In contrast, our approach is to decouple the consensus engine and P2P layers from the details of the state of the particular blockchain application. We do this by abstracting away the details of the application to an interface, which is implemented as a socket protocol.Intro to ABCI
CometBFT, the “consensus engine”, communicates with the application via a socket protocol that satisfies the ABCI, the CometBFT Socket Protocol. To draw an analogy, let’s talk about a well-known cryptocurrency, Bitcoin. Bitcoin is a cryptocurrency blockchain where each node maintains a fully audited Unspent Transaction Output (UTXO) database. If one wanted to create a Bitcoin-like system on top of ABCI, CometBFT would be responsible for- Sharing blocks and transactions between nodes
- Establishing a canonical/immutable order of transactions (the blockchain)
- Maintaining the UTXO database
- Validating cryptographic signatures of transactions
- Preventing transactions from spending non-existent transactions
- Allowing clients to query the UTXO database.
A Note on Determinism
The logic for blockchain transaction processing must be deterministic. If the application logic weren’t deterministic, consensus would not be reached among the CometBFT replica nodes. Solidity on Ethereum is a great language of choice for blockchain applications because, among other reasons, it is a completely deterministic programming language. However, it’s also possible to create deterministic applications using existing popular languages like Java, C++, Python, or Go, by avoiding sources of non-determinism such as:- random number generators (without deterministic seeding)
- race conditions on threads (or avoiding threads altogether)
- the system clock
- uninitialized memory (in unsafe programming languages like C or C++)
- floating point arithmetic
- language features that are random (e.g. map iteration in Go)
Consensus Overview
CometBFT adopts Tendermint consensus, an easy-to-understand, mostly asynchronous, BFT consensus algorithm. The algorithm follows a simple state machine that looks like this:
Participants in the algorithm are called validators; they take turns
proposing blocks of transactions and voting on them. Blocks are
committed in a chain, with one block at each height. A block may
fail to be committed, in which case the algorithm moves to the next
round, and a new validator gets to propose a block for that height.
Two stages of voting are required to successfully commit a block; we
call them pre-vote and pre-commit.
There is a picture of a couple doing the polka because validators are
doing something like a polka dance. When more than two-thirds of the
validators pre-vote for the same block, we call that a polka. Every
pre-commit must be justified by a polka in the same round.
A block is committed when
more than 2/3 of validators pre-commit for the same block in the same
round.
Validators may fail to commit a block for a number of reasons; the
current proposer may be offline, or the network may be slow. Tendermint consensus
allows them to establish that a validator should be skipped. Validators
wait a small amount of time to receive a complete proposal block from
the proposer before voting to move to the next round. This reliance on a
timeout is what makes Tendermint consensus a weakly synchronous algorithm, rather
than an asynchronous one. However, the rest of the algorithm is
asynchronous, and validators only make progress after hearing from more
than two-thirds of the validator set. A simplifying element of
Tendermint consensus is that it uses the same mechanism to commit a block as it
does to skip to the next round.
Assuming less than one-third of the validators are Byzantine, Tendermint consensus algorithm
guarantees that safety will never be violated - that is, validators will
never commit conflicting blocks at the same height. To do this it
introduces a few locking rules which modulate which paths can be
followed in the flow diagram. Once a validator precommits a block, it is
locked on that block. Then,
- it must prevote for the block it is locked on
- it can only unlock, and precommit for a new block, if there is a polka for that block in a later round