Cosmos Sdk === [TOC] ## What is the Cosmos SDK? **The Cosmos SDK** is a development kit for building the application layer of a Tendermint-based blockchain. It has a number of generic modules used for a blockchain’s most common functions such as creating accounts, staking, and token management. ### Architecture - **State Machine** (Application Layer) - Multipe states but only 1 at a time - For each transaction **`T`** in block `B` apply to current state `S` to derive new state `S1` - Deterministic - `Merkle Tree` - **Tendermint** (state-machine replication) - Handles ***networking*** and ***consensus*** layer. (propagating and ordering transaction bytes) - **ABCI** (interface communication between Application and Tendermint) ![Tendermint Stack](https://i.imgur.com/MjTTRXC.png) *Tendermint stack visualization* ### **Simplified Overview** 1. Decode `transactions` received from the Tendermint consensus engine (deals with `[]bytes`). 2. Extract `messages` from `transactions` and do basic sanity checks. 3. Route each message to the appropriate module so that it can be processed. 4. Commit state changes. ### Components - `baseapp` - boilerplate implementation of a Cosmos SDK application. - Comes with base implementation of **ABCI** - Provide a secure interface between the store and the extensible state machine while defining as little about the state machine as possible. - **Multistore -** persistant storage of state using `KVStores` - Only accept `[]byte` - custom structures need marshaling with a **codec** - **Modules -** defines a subset of the state and contains its own message/transaction processor and `keeper` to access multistore ## Application-speicific Blockchains ![](https://i.imgur.com/JYdsu5P.png) **Zones** - heterogeneous blockchains carrying out the authentication of accounts and transactions, the creation and distribution of tokens, and the execution of changes to the chain.  **Hubs** are blockchains designed to connect the so-called **zones**. Once a zone connects to a hub through an IBC connection, it gets automatic access to the other zones connected to that hub. At this point, data and value can be sent and received between the zones without risk of, for example, double-spending tokens. This helps reduce the number of chain-to-chain connections that need to be established for interoperability. ### Tradeoffs (Appchains vs EVM / CosmWasm) 1. **EVM / Cosmwasm** - **+** Little overhead on speed of development and technical knowledge on the **Consensus and P2P Networking Layer.** (Remix IDE, Hardhat, Truffle, Third party services) - **-** Limited set of cryptographic functions, bugs caused by the underlying blockchain architecture, competition for resources - high fees and network congestion. - **-** Learn a new novel language for each VM ? 2. **Appchains** - **+** Full customization of **validator set, throughouput, safety (cryptography), performance.** - **+** Custom tailored consensus mechanisms powered by Tendermint (PoS, PBFT, DPoS) - **+** Automatic code executing before or after a block. - **-** More technical overhead, sourcing your own validator set (**prior to Interchain security)**, How Does Cosmos SDK Work --- ### Anatomy of Cosmos SDK application `app.go` - core of state machine, contains **type definitions of the application** and functions to **create and initialize it.** - **Type Definition of the Application** ``` rust type App struct { *baseapp.BaseApp cdc *codec.LegacyAmino appCodec codec.Marshaler interfaceRegistry types.InterfaceRegistry invCheckPeriod uint // keys to access the substores keys map[string]*sdk.KVStoreKey tkeys map[string]*sdk.TransientStoreKey memKeys map[string]*sdk.MemoryStoreKey // keepers AccountKeeper authkeeper.AccountKeeper BankKeeper bankkeeper.Keeper CapabilityKeeper *capabilitykeeper.Keeper StakingKeeper stakingkeeper.Keeper SlashingKeeper slashingkeeper.Keeper MintKeeper mintkeeper.Keeper DistrKeeper distrkeeper.Keeper GovKeeper govkeeper.Keeper CrisisKeeper crisiskeeper.Keeper UpgradeKeeper upgradekeeper.Keeper ParamsKeeper paramskeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly IBCKeeper *ibckeeper.Keeper EvidenceKeeper evidencekeeper.Keeper TransferKeeper ibctransferkeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper // this line is used by starport scaffolding # stargate/app/keeperDeclaration CheckersKeeper checkersmodulekeeper.Keeper // the module manager mm *module.Manager ``` - **Constructor Function** - Initialize **codec, keepers, store keys, module manager.** - Initialize routes - When a transaction is relayed to the application by Tendermint via the ABCI, it is routed to the appropriate module's `Msg` service using the routes defined here. - With the module manager, register the **application’s module’s invariants.** Predicatble value present in the module, otherwise special case triggered (usually halting of chain). - With the module manager, set the order of execution between `InitGenesis`, `BeginBlocker` and `EndBlocker`functions of each of the application’s modules. - `BeginBlocker` , `EndBlocker` , `InitChainer` , `anteHandler` - Mount the stores and return the application. - **BeginBlocker and EndBlocker** - Usually composed of each individual module’s `BeginBlock` and `EndBlock` functions. Speicifc order must be set with `SetOrderBeginBlocker` and `SetOrderEndBlockers`. (must be set before `SetBeginBlocker` and `SetEdnBlocker` ) - **EncodingConfig** - Define the codecs that will be used throughout the app. ### What are messages and transactions? When users want to make state changes they create transactions. Each transaction can have multiple messages expressed in `sdk.Msg` which must be signed using the private keys associated with the account before the transaction is broadcasted to the network.  `sdk.Msg` are module-specific objects that trigger state transitions within the scope of the module they belong to. ```go // Tx defines the interface a transaction must fulfill. Tx interface { // Gets the all the transaction's messages. GetMsgs() []Msg // ValidateBasic does a simple and lightweight validation check that doesn't // require access to any other information. ValidateBasic() error } ``` ### Ethereum Tx vs Cosmos Tx - Cosmos has sign modes - `SIGN_MODE_DIRECT` ,`SIGN_MODE_LEGACY_AMINO` ,`SIGN_MODE_DIRECT_AUX` - Cosmos `Tx` can be rejected with speicifc checks and logic at any layer (more control) Cosmos SDK Modules --- ### Module Components - Module Genesis - **Import?** The module manager of the application is responsible for calling the `InitGenesis` method of each of the application's modules in order. This order is set by the application developer via the manager's `SetOrderGenesisMethod`, which is called in the application's constructor function. - **Export?** The `ExportGenesis` method is executed whenever an export of the state is made. It takes the latest known version of the subset of the state managed by the module and creates a new `GenesisState`out of it. This is mainly used when the chain needs to be upgraded via a hard fork. - ABCI - **BeginBlock?** Run some code at the beginning of every block. Ex. ***slashing*** module performs a liveness check, ***distribution*** module sends out all fees from the previous block. - **EndBlock?** Run some code at the end of every block. Ex. EVMOS ***feemarket*** module updates `block_gas_used` value in `KVStore` and resets to `block_gas` defined at genesis. - Tx (Msg) and Query service: - **gRPC -** based on the idea of defining a service and specifying the methods that can be called remotely with their parameters and return types. Define in `proto` folder the types of `Msg` and `Queries` or generate them with Ignite CLI. `ignite scaffold message` - Module types (`struct` ’s) definition - Generated using **Ignite CLI** or manually as a proto file defining the queries and messages. Afterwards a protobuf Go bindings file is generated. - Keeper - **What are they?** An abstraction used to access a module’s store(s) and update and query the state. - **How do they relate with the blockchain store?** They are module specific i.e the subset of state defined by a module can only be accessed by a `keeper` defined in said module. If a module needs to access the subset of state defined by another module, a reference to the second module's internal `keeper` needs to be passed to the first one. This is done in `app.go` during the instantiation of module keepers. - **How is data stored in a module?** Using an [`IAVL` store](https://github.com/cosmos/iavl). `O(log(n))` access. Retrieve tha approriate store from the `ctx` using `storeKey.` Marshal the value to `[]byte` using a codec. Set the encoded value in the store at location `key`. Transaction Lifecycle --- 1. Creation - Client Side with various tools, CLIs or frontends. 2. Addition to Mempool - Nodes send an ABCI message - `CheckTx` to the application layer to check for validity and receive `abci.ResponseCheckTx`. **Stateless Checks -** do not require nodes to access state. Can be done by light clients or offline nodes. Checks for basic errors like emtpy addresses or nonegative numbers. **Stateful Checks** - validate transactions based on commited state. Things like if values exist, address has sufficient funds or authorization checks. 1. `CheckTx` 1. **Decoding** - decoded from `[]byte` to `Tx` 2. `runTx` - `ValidateBasic()` is called on each `sdk.Msg` in the `Tx` which runs preliminary ***stateless*** validity checks. 3. Then the `anteHandler` of the application is run (if it exists). 4. Finally, the `RunMsgs()` function is called to process the `sdk.Msg`s in the `Tx`. If `CheckTx` is sucecessfull the default protocol is to relay it to peer nodes and add it to the **Mempool** so that the transactions is a candidate for the next **Block.** 💡 Full-nodes keep a **mempool cache** of the last `mempool.cache_size` transactions they have seen, as a first line of defense to prevent replay attacks. Currently existing preventative measures include fees and a `sequence` (nonce) counter to distinguish replayed transactions from identical but valid ones. If an attacker tries to spam nodes with many copies of a `Tx`, full-nodes keeping a mempool cache will reject identical copies instead of running `CheckTx` on all of them. 3. Inclusion in a Block - Each **round** begins with a proposer creating a block of the most recent transactions and ends with **validators**, special full-nodes with voting power responsible for consensus, agreeing to accept the block or go with a `nil` block instead. 4. State Changes - To fully validate transactions - all nodes execute ABCI functions `BeginBlock`, `DeliverTx` for each transaction and `EndBlock`. - This process should yield a single, unambigious result since everything is deterministic and ordering is explicit ( determined by block proposer ). - `DeliverTx` 1. Like`CheckTx` but calls the `runTx` in ***Deliver Mode*** instead of ***Check Mode***. 2. **Decoding** 3. **Checks and AnteHandler** 4. **`MsgServiceRouter` -** used because transactions may have messages from different modules. 5. **`Msg` service -** executing each message in the transaction. 6. **PostHandlers** - runs checks after executing of a message and reverts state if anything fails. 7. **Gas** - `GasMeter` is used to track how much gas is being used. If any gas errors occur (like running out) revert state changes. 5. Commit When they (nodes) receive enough validator votes (2/3+ *precommits* weighted by voting power), full nodes commit to a new block to be added to the blockchain and finalize the state transitions in the application layer. A new state root is generated to serve as a merkle proof for the state transitions As soon as the state changes are committed, `checkState`start afresh from the most recently committed state and `deliverState`resets to `nil` in order to be consistent and reflect the changes. ## Evmos Ethereum Transaction Lifecycle ### Client Side 1. An instance of `MsgEthereumTx` is created after populating the RPC transaction using `SetTxDefaults` to fill missing tx arguments with default values. 2. The transaction is validated using `ValidateBasic()`  3. Build a Cosmos `Tx` from an Ethereum message 4. The `Tx` is broadcast in **sync mode** (waits for the `CheckTx - Tendermint` execution response only) `sync`: Wait for the tx to pass/fail CheckTx `async`: Don't wait for pass/fail CheckTx; send and return tx immediately `block`: Wait for the tx to pass/fail CheckTx, DeliverTx, and be committed in a block (not-recommended) ### Server Side Each `Tx` is handled by the application by calling `RunTx` After a ***stateless*** validation on each `sdk.Msg` in the `Tx`, the `AnteHandler`confirms whether the `Tx` is an Ethereum or SDK transaction. As an Ethereum transaction it's containing msgs are then handled by the `x/evm` module to update the application's state. ### AnteHandler ```go // All relevant state transition prechecks for the MsgEthereumTx are performed on the AnteHandler, // prior to running the transaction against the state. The prechecks run are the following: // // 1. the nonce of the message caller is correct // 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) // 3. the amount of gas required is available in the block // 4. the purchased gas is enough to cover intrinsic usage // 5. there is no overflow when calculating intrinsic gas // 6. caller has enough balance to cover asset transfer for **topmost** call ``` An `anteHandler` is run for every transaction which checks if the transaction is an Ethereum tx and routes it to an internal `anteHandler` . It executes a number of decorator checks that make sure the transaction is valid. These include: - `EthSetUpContextDecorator()` is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption by setting the gas meter to infinite - `EthValidateBasicDecorator(evmKeeper)` validates the fields of an Ethereum type Cosmos `Tx` msg - `EthSigVerificationDecorator(evmKeeper)` validates that the registered chain id is the same as the one on the message, and that the signer address matches the one defined on the message. It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work. Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user won't see the error message. - `EthAccountVerificationDecorator(ak, bankKeeper, evmKeeper)` that the sender balance is greater than the total transaction cost. The account will be set to store if it doesn't exist, i.e cannot be found on store. This AnteHandler decorator will fail if: - any of the msgs is not a MsgEthereumTx - from address is empty - account balance is lower than the transaction cost - `EthNonceVerificationDecorator(ak)` validates that the transaction nonces are valid and equivalent to the sender account’s current nonce. - `EthGasConsumeDecorator(evmKeeper)` validates that the Ethereum tx message has enough to cover intrinsic gas (during CheckTx only) and that the sender has enough balance to pay for the gas cost. Intrinsic gas for a transaction is the amount of gas that the transaction uses before the transaction is executed. The gas is a constant value plus any cost incurred by additional bytes of data supplied with the transaction. This AnteHandler decorator will fail if: - the transaction contains more than one message - the message is not a MsgEthereumTx - sender account cannot be found - transaction's gas limit is lower than the intrinsic gas - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price) - transaction or block gas meter runs out of gas - `CanTransferDecorator(evmKeeper, feeMarketKeeper)` creates an EVM from the message and calls the BlockContext CanTransfer function to see if the address can execute the transaction. - `EthIncrementSenderSequenceDecorator(ak)` handles incrementing the sequence of the signer (i.e sender). If the transaction is a contract creation, the nonce will be incremented during the transaction execution and not within this AnteHandler decorator. ### EVM module 1. Convert `Msg` to an Ethereum `Tx` type 2. Apply `Tx` with `EVMConfig` and attempt to perform a state transition, that will only be persisted (committed) to the underlying KVStore if the transaction does not fail: 1. Confirm that `EVMConfig` is created 2. Create the Ethereum signer using chain config value from `EVMConfig` 3. Set the ethereum transaction hash to the (impermanent) transient store so that it's also available on the StateDB functions 4. Confirm that EVM params for contract creation (`EnableCreate`) and contract execution (`EnableCall`) are enabled 5. Generate a new EVM instance 7. Apply message. If `To` address is `nil`, create new contract using code as deployment code. Else call contract at given address with the given input as parameters 8. Calculate gas used by the evm operation 3. If `Tx` applied sucessfully 1. Execute EVM `Tx` postprocessing hooks. If hooks return error, revert the whole `Tx` 2. Refund gas according to Ethereum gas accounting rules 3. Update block bloom filter value using the logs generated from the tx **(stored in state in Cosmos)** 4. Emit SDK events for the transaction fields and tx logs ### BeginBlock - Set the context for the current block so that the block header, store, gas meter, etc are available to the `Keeper` once one of the `StateDB` functions are called during EVM state transitions. - Set the EIP155 `ChainID` number (obtained from the full chain-id), in case it hasn't been set before during `InitChain` ### EndBlock - Emit Block bloom events - This is due for Web3 compatibility as the Ethereum headers contain this type as a field. The JSON-RPC service uses this event query to construct an Ethereum Header from a Tendermint Header. - The block Bloom filter value is obtained from the Transient Store and then emitted ## Chain Upgrades When new software implementations need to be added to a blockchain network all nodes in that network must implement that software. If a certain subset of nodes does not adopt the new software impelementations the blockchain is at risk of producing a **hard fork** essentially rendering 2 chains with the same history. **A Cosmos SDK blockchain built for a specific application can be upgraded without forks** 💡 Generally, when a blockchain is upgraded it is vital that all nodes upgrade simultaneously and at the same block height ### Proccess Overview A "plan" is an upgrade process to take place at a specific block height in the future. It includes a `SideCar` process that executes when the upgrade commences, which names the plan and specifies a block height at which to execute. ```go type Plan struct { Name string Height int64 Info string } ``` - A `SideCar` is a binary which nodes can run to attend to processes outside of Cosmos binaries. This can include steps such as downloading and compiling software from a certain commit in a repo. - An `UpgradeHandler` may be executed after the `SideCar` process is finished and the binary has been upgraded. It attends to on-chain activities that may be necessary before normal processing resumes. An upgrade handler may trigger a `StoreLoader`. - A `StoreLoader` prepares the on-chain state for use by the new binary. This can include reorganizing existing data. The node does not resume normal operation until the store loader has returned and the handler has completed its work. - **Cosmovisor** is a tool that node operators can use to automate the on-chain processes described above. Tendermint === ## What is BFT **Byzantine Fault Tolerance(BFT)** is the feature of a distributed network to reach consensus(agreement on the same value) even when some of the nodes in the network fail to respond or respond with incorrect information. The objective of a BFT mechanism is to safeguard against the system failures by employing collective decision making(both – correct and faulty nodes) which aims to reduce to influence of the faulty nodes. BFT is derived from Byzantine Generals’ Problem Blockchain is a solution to the double-spending problem. The double-spending problem refers to the challenge of designing a digital cash system in which tokens are digital artifacts but cannot be spent more than once. ## What is Finality Finality is the guarantee that transactions cannot be altered, reversed, or canceled after they are completed. Blockchain latency affects finality rate. ## Safety vs Liveness *In an asynchronous distributed system, is there a deterministic consensus algorithm that can satisfy agreement, validity, termination, and fault tolerance?* - ***No*** Simply put, **safety** should guarantee that “a bad thing never happens” and **liveness** guarantees that “something good eventually happens”. 💡 Safety and Liveness cannot be simultaneously guaranteed by any consensus algorithm. ***Absolute Finality*** Tendermint guarantees safety but not liveness - 2/3 + 1 votes are needed for consensus. Consistency over availability. If 1/3 of validators go down the network halts. ***PoW*** Nakamoto consensus guarantees liveness but not safety. Whoever discovers a chain that is longer than the previous ones is indeed the correct one. Optimized for censorship resistance. ## Synchrony, Asynchrony, Partial Synchrony **Synchronous system** - there is a known fixed upper bound…on the time required for a message to be sent from one processor to another and a known fixed upper bound…on the relative speeds of different processors. **Asynchronous system** - no fixed upper bounds exist. **Partially synchronous system** - fixed bounds ***may*** exists but are not known beforehand. **Tendermint** is solving for **Partially synchronous sytems** (modified version of the DLS Protocol which uses 'distributed clocks') **Tendermint** belongs to a class of protocols which solve consensus under partially synchronous communication, wherein, a partially synchronous system model alternates between periods of synchrony and asynchrony; we sometimes refer to this model as “weakly synchronous”. What this means is, Tendermint does rely on timing assumptions in order to make progress. However, in contrast to synchronous systems, the speed of progress does not depend on system parameters, but instead depends on real network speed. ## ABCI++ State machine is always the server while consensus layer is the client. i.e the consensus layer always initiates the communication ### The Problem - Application layer has no control over the proposed value. Cannot filter invalid `Tx`. - No defense against Byzantine proposers. - Mempool front-running. - Suboptimal API for `decide()`. `DeliverTx` delivers sequentially. ### The Solution ![](https://i.imgur.com/bb9Pe1i.jpg) - `FinalizeBlock` and `Commit` - More efficient: orthogonal `Tx` are executed in parallel. - State-machine transaition more flexible(but deterministic) - `PrepareProposal` sends the proposed block `Tx` back to the State Machine. - Add, remove, reorder `Tx` - Immediate execution - can execute the proposal as a decision. - `ProcessProposal` - Validity check is extended to State machine level. 💡 Tendermint is rejecting proposals that used to be accepted based on logic that is not in the algorithm. This has Liveness implications. - `ExtendVote` - provide vote extension prior to voting i.e sending a message from the node. - 💡 Extension is not covered by agreement. - `VerifyVoteExtension` - bad vote extension = bad vote - Filter Byzantine "voters" ### Potential Risks ### ABCI++ Use cases - `PrepareProposal` / `ProccessProposal` - Transaction reordering - Transaction aggregation - Transaction reorg - Celestia **further reading** - Dealing with Byzantine proposers - Immediate execution - 100% certainty: all `Tx` valid, small performance penalty - `ExtendVote` / `VerifyVoteExtension` - 2/3+ majority of votes with verified extension or else thrown out - `PrepareProposal` consumes the vote extension in next block - Oracles - prices of tokens - Threshold decryption - Front running protection. Transactions encrypted with Public Key and key shares shared in nodes.