At its core, a blockchain application is a replicated deterministic state machine.
A state machine is a computer science concept whereby a machine can have multiple states, but only one at any given time. There is a state, which describes the current state of the system, and transactions, that trigger state transitions.
Given a state S and a transaction T, the state machine will return a new state S'.
+--------+ +--------+
| | | |
| S +---------------->+ S' |
| | apply(T) | |
+--------+ +--------+
In practice, the transactions are bundled in blocks to make the process more efficient. Given a state S and a block of transactions B, the state machine will return a new state S'.
+--------+ +--------+
| | | |
| S +----------------------------> | S' |
| | For each T in B: apply(T) | |
+--------+ +--------+
In a blockchain context, the state machine is deterministic. This means that if you start at a given state and replay the same sequence of transactions, you will always end up with the same final state.
The Cosmos SDK gives you maximum flexibility to define the state of your application, transaction types and state-transition functions. The process of building the state-machine with the SDK will be described more in depth in the following sections. But first, let us see how it is replicated using Tendermint.
As a developer, you just have to define the state machine using the Cosmos-SDK, and Tendermint will handle replication over the network for you.
^ +-------------------------------+ ^
| | | | Built with Cosmos SDK
| | State-machine = Application | |
| | | v
| +-------------------------------+
| | | ^
Blockchain node | | Consensus | |
| | | |
| +-------------------------------+ | Tendermint Core
| | | |
| | Networking | |
| | | |
v +-------------------------------+ v
Tendermint is an application-agnostic engine that is responsible for handling the networking and consensus layers of your blockchain. In practice, this means that Tendermint is responsible for propagating and ordering transaction bytes. Tendermint Core relies on an eponymous Byzantine-Fault-Tolerant (BFT) algorithm to reach consensus on the order of transactions. For more on Tendermint, click here.
Tendermint consensus algorithm works with a set of special nodes called Validators. Validators are responsible for adding blocks of transactions to the blockchain. At any given block, there is a validator set V. A validator in V is chosen by the algorithm to be the proposer of the next block. This block is considered valid if more than two thirds of V signed a prevote and a precommit on it, and if all the transactions that it contains are valid. The validator set can be changed by rules written in the state-machine. For a deeper look at the algorithm, click here.
The main part of a Cosmos SDK application is a blockchain daemon that is run by each node in the network locally. If less than one third of the validator set is byzantine (i.e. malicious), then each node should obtain the same result when querying the state at the same time.
Tendermint passes transactions from the network to the application through an interface called the ABCI, which the application must implement.
+---------------------+
| |
| Application |
| |
+--------+---+--------+
^ |
| | ABCI
| v
+--------+---+--------+
| |
| |
| Tendermint |
| |
| |
+---------------------+
Note that Tendermint only handles transaction bytes. It has no knowledge of what these bytes really mean. All Tendermint does is to order them deterministically. It is the job of the application to give meaning to these bytes. Tendermint passes the bytes to the application via the ABCI, and expects a return code to inform it if the message was successful or not.
Here are the most important messages of the ABCI:
CheckTx
: When a transaction is received by Tendermint Core, it is passed to the application to check its validity. A special handler called the "Ante Handler" is used to execute a series of validation steps such as checking for sufficient fees and validating the signatures. If the transaction is valid, the transaction is added to the mempool and relayed to peer nodes. Note that transactions are not processed (i.e. no modification of the state occurs) withCheckTx
since they have not been included in a block yet.DeliverTx
: When a valid block is received by Tendermint Core, each transaction in the given block is passed to the application viaDeliverTx
to be processed. It is during this stage where the state transitions occur. The "Ante Handler" executes again along with the actual handlers for each message in the transaction.BeginBlock
/EndBlock
: These messages are executed at the beginning and the end of each block, whether the block contains transaction or not. It is useful to trigger automatic execution of logic. Proceed with caution though, as computationally expensive loops could slow down your blockchain, or even freeze it if the loop is infinite.
For a more detailed view of the ABCI methods and types, click here.
Any application built on Tendermint needs to implement the ABCI interface in order to communicate with the underlying local Tendermint engine. Fortunately, you do not have to implement the ABCI interface. The Cosmos SDK provides a boilerplate implementation of it in the form of baseapp.