Short Summary of Tendermint
Tendermint BFT is a proof-of-stake consensus algorithm designed and implemented back in 2014-2015. The creators then started a company called Tendermint Inc. oriented around use cases and integrations, culminating in the Cosmos blockchain network. Cosmos positions itself as a “blockchain 3.0” solution, built to address the scalability and interoperability limitations of Ethereum (a 2.0 solution) and Bitcoin (a 1.0 solution).
How Tendermint Backed Applications Work
Tendermint-BFT is paired with a socket protocol called ABCI (Application BlockChain Interface). Tendermint-BFT by itself is a message ordering algorithm for a distributed system trying to process state-updating messages in the same order on every node. But this algorithm can’t tell what messages are valid or invalid for custom applications or how to determine if a node is in a valid state after updating itself with a message.
This is where ABCI comes in. ABCI is the hook that allows the consensus algorithm to pass the responsibility of message validation and state validation to a custom application. Any application that receives and responds to ABCI messages from Tendermint core is called an ABCI application.
Since ABCI is a socket protocol, it is itself language agnostic and is defined by a set of protobuf files. This means that in principle, developers can implement an ABCI application in whatever language you want to.
If you’re a Haskell or Rust developer, you may have heard of competing platforms like Cardano or Substrate that offer similar “blockchain 3.0” solutions. Cardano has a portion of its network in production (
cardano-sl) and shows optimism about delivering an application layer in the future. The first production instances of Substrate blockchains have just begun to appear.
Since Tendermint allows developers to write blockchain applications in whatever language they want, they are only limited to the languages that implement an ABCI server and ideally a framework for abstracting away the more esoteric internals. As of today, the language has the most support is
golang with the official
“We believe that blockchain application development is the most secure and robust when backed by statically typed languages like Haskell and PureScript, so we decided to build out a general-purpose Tendermint SDK in Haskell. Hence Kepler.”
– The FOAM Team
Kepler Architecture Highlights
For the full essence of how applications are made using Kepler, check out the official tutorial.
The basic component of a Kepler application is the
Module. This module declares a few pieces of information:
- The router that the module uses to process transactions.
- The router that the module uses to process state queries.
- The custom effects and interpretation that the module introduces.
There is a standard library of modules that developers can plug into their application, things like
bank for managing token balances, or
auth for managing basic account information. It is also possible for developers to create their own modules for managing whatever it is that their application does.
Developers can easily create dependencies between modules using the type system. For example, if a module will execute token transfers during a transaction, it can explicitly state dependence on the
bank module. It is also possible to be more precise and state a dependent on only the effect that allows for token transfers.
Applications are defined by simply listing the modules the developer wants to be used. In a
servantlike manner, it will compose the routers for transactions and state queries from the individual modules, and will also automatically interpret custom application effects to a lower level system that the SDK knows about.
Sometimes called Algebraic Effects, an Effects system provides a way to strictly segment the capabilities of one section of code from another using the type system. It also allows developers to abstract the code from its runtime execution. Kepler is written using the polysemy higher order effects library.
This has a few main benefits:
- The SDK clearly segments different responsibilities to different sections of code. For example, although handlers for querying state and processing transactions both have access to the database, the type system does not allow write-access during state query execution.
- Application developers can define custom effects (e.g. for dealing with tokens, or managing other custom application state) and can seamlessly integrate them with the effects defined by the SDK.
- The runtime of the SDK can be changed by simply providing a different interpretation for core effects.
When an application has a type, it can be used to derive all kinds of other useful tools. Using the same kind of combinator logic found in servant, Kepler is able to generate client libraries from the application type that contain functions for submitting any kind of transaction or querying any state in an application for free. For example, this means that if a developer changes the type of even a single message that their application uses for transactions, they will get a compile-time error that their tests or a client application are broken.