Building a Tendermint & Cosmos SDK App (Part 1): Intro to Blockchain & Tendermint
This is the first blog post in a mini series that will serve to demonstrate how to build application-specific blockchains using Tendermint and Cosmos-SDK.
This post will provide a small introduction on blockchains and Tendermint, which is one of the most well known blockchain platforms that allows building arbitrary applications on top of the blockchain.
On future posts, we will guide you through the development process of how to build your own logic on top of the blockchain process, as well as how to develop front end applications for blockchains. The goal is to demonstrate the whole process of building full stack application with a blockchain backend.
A blockchain is a time-stamped list of records. These records are chained together using cryptographic hashes to ensure data integrity, where new records, or blocks of records, contain hashes of the previous ones, therefore confirming them, and all of their predecessors. Hence the name blockchain. This property is often called immutability of blockchains. Although they are not by themselves immutable, as no data can be, the change is easy to see as any change in data would result in a different hash, and thus the hash chain would be broken. This enables trust in an environment where trust is not already present, allowing everybody to verify the data integrity themselves.
Blockchain is essentially a state machine whose inputs are the time-stamped records, also called transactions. By ensuring that all of the network participants agree upon which transactions, and in which order, form the blockchain, and by having the state machine be completely deterministic, we ensure reaching the exact same state in all of the network participants. This allows for a truly distributed and decentralized system in which the same state is ensured on the majority of the participants, if that majority is following the rules.
These time-stamped records can represent anything. For example, in Bitcoin, they represent changes of ownership of certain Bitcoins. Or, more specifically, unlocking and locking of certain Bitcoins. In Ethereum, they represent the invocations of the Ethereum Virtual Machine, where each record, or transaction, is a sequence of byte codes. All of the blockchains have transactions of different formats carrying different information, and have different logic for their processing, tailored for the use case.
The core part of making blockchain work is ensuring that all (or the majority) of the network participants agree upon which transactions form the blockchain, as well as what their exact order is. This is the role of consensus. Without reaching consensus, we do not have a functioning distributed ledger technology, as every participant will have its own version of the world. There would be no global truth.
There are different consensus algorithms, and they differ in many dimensions — how open is it (can anyone join), how exactly is the order agreed upon, how well does it scale, which kinds of failures it can handle etc. The consensus protocols, or how to reach an agreement between different distributed participants, is a whole field in itself, and is the focus of research for many computer scientists.
Architecturally speaking, the blockchains can be split into three major components:
- Consensus layer — responsible for reaching consensus amongst a group of participants who may or may not trust each other. There are many different types of consensus algorithms, but they all have one single main goal — reaching an agreement over the order of transactions in the network, across the majority of the participants. This is the core piece that makes the Distributed Ledger Technology work. Reaching consensus between all of the mutually untrusting miners across the world is what made Bitcoin so revolutionary. The design of the consensus protocol requires a lot of expertise and can be very consuming. The implementation needs to be very safe and tested as well.
- Networking layer — it is responsible for the communication between peers in the network, that is usually thought of as an exchange of messages of different semantics. Usually it is some kind of a gossip protocol, where peers exchange information with few other peers, passing all of the acquired information from previous exchanges, constantly allowing the information about the current state of the network flow throughout.
- Application logic layer — responsible for implementing business logic, whether it is a general smart contract platform or more specific blockchain. For example, Ethereum is a smart contract platform, implemented as a virtual machine, with a bytecode interpreter. Its transactions are sequences of byte codes which represent an invocation of an Ethereum Virtual Machine. On the other hand, Bitcoin is more narrow and although it has its own scripting language, it is not a virtual machine, but a blockchain that keeps account of bitcoins, using the concept of unspent transaction output. There are no restrictions as to what can be the application logic of the blockchain, although some applications are more suited than others.
Tendermint is a platform for building application-specific blockchains. Before Tendermint was created, when we wanted to implement our own solution with blockchains, we needed either to heavily modify the original bitcoin blockchain adding our business logic, build on a general platform like Ethereum and implement our logic as a set of smart contracts, or we could have opted to develop the entire stack ourselves.
The first option requires deep knowledge of the Bitcoin codebase including all the constraints that it already has and that need to be re-adapted for a specific use case. It also means dealing with all of the legacy code and keeping track of every-day upstream updates and merging them into the already changed code base.
The second option has certain limitations — it forces us to use one of the languages that compile to Ethereum’s byte code. It also gives us all of the advantages and disadvantages of Ethereum. This also means sharing the blockchain with all of the other applications, making it susceptible to the “CryptoKitties problem”.
The third option gives us a lot of freedom, as we can handpick all of the features that we want to have, but requires a large amount of resources and expertise to build the whole stack from bottom up. It prevents focusing on the business problem itself. And also if everybody builds its own blockchain from scratch, the quality has to be lower than if the community focus is on the few well-proven platforms.
So how exactly does Tendermint help?
Tendermint (https://www.tendermint.com/) is a platform that handles consensus and networking layer, leaving the implementation of the application logic to the developers that want to build their own solutions using the blockchain technology. It offers an easy to understand and elegant API to integrate into the platform, called ABCI (Application BlockChain Interface). That is the interface between the Tendermint and user’s application. It offers a great base that is generic enough to handle the majority of the applications, leaving the developers to worry only about the business logic itself.
Tendermint takes care of almost everything — from the moment the transaction is sent by the user to when a transaction is ordered into the blockchain and handed off to the custom application logic to process it, after the voting process between the validators. To Tendermint, the transaction is just a sequence of bytes, lacking any meaning. All of the interpretation and processing is performed on the application side, invoked through the ABCI methods by Tendermint. Tendermint’s main job is ensuring that the validators from the validator set provided by the application agree on the order of these transactions — opaque sequences of bytes, forming the blocks of the blockchain.
The core ABCI methods are:
- InitChain — this is called exactly once, upon the starting of blockchain and processing the genesis file. The application logic needs to return the initial application state that is formed when the information from genesis file is processed by our application logic. This is the starting point of the whole flow, and this initial state will be used as the initial state of the state machine, with the input being the first transaction of the first block.
- CheckTx — called by Tendermint for every transaction received from the network users, before it enters the mempool (set of transactions that are waiting to be processed and included in a block). This is intended to filter out transactions to avoid filling out the mempool and polluting the blocks with invalid transactions. At this level, only the basic checks are performed — whether the transaction can be decoded, whether there is a registered handler in the application for the messages that the transaction contains, etc. Important thing to note — it is still possible for transactions that wouldn’t pass the CheckTx, to be included in the blockchain. The same validation should occur at the DeliverTx as well, to mark those transactions as invalid once they are processed after they are in the block.
- BeginBlock — called by Tendermint before every new block that has been agreed upon by the majority of the validators in the validator set. Tendermint provides general information about block, like height, timestamp, etc. Application logic may decide to do something at this point of time — some arbitrary processing or it can simply do nothing. It can be considered a hook that gets invoked every X seconds, where X is Tendermint’s block time.
- DeliverTx — called by Tendermint for every transaction contained in a block. To restate, for Tendermint a transaction is simply a sequence of bytes. It is up to the application logic to decide how to interpret and process it. Application should return transaction status code, marking the transaction as valid or invalid after processing it, and update the internal state appropriately in the first case.
- EndBlock — called by Tendermint at the end of each block’s processing. Application can process this event in any way it sees fit, kicking of arbitrary logic. This also can be considered a hook that gets invoked every X seconds, where X is Tendermint’s block time. Also, it can deliver a set of validator updates here, changing the validator set for Tendermint. Tendermint will take those updates and react appropriately in consensus and network layers, removing the validators marked for removal from the voting process, and adding new ones. This is how Tendermint provides generality, allowing the upper layers to decide who the validators are, while it takes care of everything else.
- Commit — called by Tendermint after the block’s processing. The application logic should return the state hash (Merkle root hash) of application state at this point in time, after processing all of the transactions included in the block. This will be included in the next block and will be signed by the validators, serving as a commit of the whole application state at that point in time
- Query — called by Tendermint on user’s query, with data and path fields. It is up to the application to process the query and return the response, either with error or containing the required information. This allows to implement a very broad and flexible read operations, without any constraints being imposed by the underlying platform
Implementing applications on top of Tendermint
Even though Tendermint takes care of both consensus and networking, with all of its details, the effort to build a solution on top of Tendermint is still fairly significant and requires core blockchain knowledge.
To implement an application on top of Tendermint, we would need to do the following:
- Pick an encoding method. For example, we could use human-readable JSON or we can opt for something more efficient, a binary encoding like protobuf.
- Decide the structure of a transaction
- Implement transaction validation
- Application state
- We need to decide the best way to store application state. One of the most common ways is using Patricia-Merkle trees to store state in a key-value format, with its root hash being included in the blocks as state root
- Implement the application state — data structure and basic required operations
- Cryptography — cryptography required for performing basic operations like signing and signature verification needs to be decided, and implemented if needed.
- Storage layer
- Decide how the blockchain data (blocks) will be stored
- Decide how the application data will be stored
- For both of those the most usual way is a simple key-value database like LevelDB
- Implement the ABCI — all of the ABCI methods need to be implemented
- Implement validator set election — while Tendermint takes care of consensus, it requires to know the validator set, which is to be provided and maintained by the application logic
- Client SDK — all the client related functionalities like maintaining connection, communicating with server, verifying responses, processing block headers, etc. need to be implemented
- CLI — command line interface needs to be implemented to allow users to manage their keys, interact with the network, sign and submit transactions, and query the blockchain through terminal commands
- Wallet/Key Management — At least basic key management needs to be provided for users, to ensure easier user onboarding, especially as the network is growing and there are no third party solutions. This involves key generation, encrypting and decrypting keys for storing them on file system, using private keys to sign transactions on user’s request, etc
All of this is essential to building a solution on top of the Tendermint platform. But all of it requires a significant amount of design, implementation and testing, which might not be something that we want to do, especially if we are only getting started with Tendermint and/or do not have sufficient expertise to implement it
This concludes the initial post. The following posts will explain Cosmos-SDK, and how to build application using it, on top of Tendermint.
Follow SentryLink on Medium to get the latest articles and guides!
If you have any questions or ideas to share, please feel free to reach out to us at firstname.lastname@example.org
For more information, please visit: https://sentrylink.io