Published on

Dissecting a Cosmos DApp Chain

Authors

I have spent the last few weeks building a Cosmos app. To help myself better crystallize the concepts I learnt and to help others I have written this article.

This article is a work in progress and will be updated when/if I work in this space more and discover additional information.

In this article I walkthrough:

  • Basic concepts and terminology often used within Cosmos chain codebases.
  • Where one would start looking when digging through a Cosmos dApp chain codebase.
  • The folders and file structure that makes up an app chain.
    • What the different files are used for.

Concepts

  • Query: This is any action that results in a read from the chain.
    • From the cli perspective this is normally of the form nscli query some-command-that-reads-from-the-chain.
  • Transaction: This is any action that results in a write to the chain.
    • From the cli perspective this is normally of the form nscli tx some-command-that-writes-to-the-chain.
  • Keeper: This is the class that exposes a module's object capabilities.
    • This is what is used to interact with a chain/module's data. This should be the only way other modules can interact with your chain's data.
  • LCD: This is like a light wallet on Cosmos.
  • Address: These use the Bech32 standard and can be used to refer to different things. See here for the different types of addresses in Cosmos.
  • Account: This is the user's wallet. It is managed by the auth module.
    • See here for an example of what a Cosmos account looks like.
  • Sequence: This is a sequence (an integer) linked to an account. It is sort of like a salt for the account.

Where to Start with a Cosmos dApp Chain Project

When looking through the code base of any type of project you generally start by looking at certain files. For example with a JavaScript project you would start with the package.json file to see what scripts and dependencies are being used. From there you would look for a main.js or index.js file.

With Cosmos dApp chains the files to look at in order are:

  • types.go
    • This tells you what data types this chain works with.
    • As dApp chains are data-driven this is the best place to start as everything else in the code base will be built around this.
  • keeper.go
    • This tells you what is exposed on this chain.
    • Cosmos uses the concept of capabilities - roughly that only a module should be able to directly access and modify its data. Other module's and external entities wishing to interact with the chain's data need to do so through a well defined interface and never access the data directly (sort of how DAOs are used to prevent direct raw access to traditional DBs).
    • The keeper is the thing you use in other modules to access and modify the chain's data.
  • handler.go
    • This can be thought of as the business service to the chain for anything that mutates chain state.
    • The handler is like a Redux reducer where it has a switch-case that routes messages to the correct method for processing.
  • querier.go
    • This is like the handler except only for handling requests that read from and do not modify the chain state.
    • This is often referred to as the querier handler in the Cosmos documentation.
    • This handler also has a Redux type switch statement that directs different message types to the appropriate handler function for processing.
  • msgs.go
    • This is where messages used by the REST and CLI layer are defined.
    • The REST and CLI layer must use the same messages since the handler.go and querier.go route using these.
  • tx.go
    • This is generally defined for the cli layer but can also be defined for the REST layer.
    • This is a very lite file that simply relays messages that would mutate chain state to the handler.go for processing.
  • query.go
    • This is generally defined for the cli layer but can also be defined for the REST layer.
    • This is a very lite file that simply relays messages that would mutate chain state to the querier.go for processing.
  • rest.go
    • This file is a very thin layer that takes rest requests and relays them to the handler.go or querier.go for requests that mutate state and only read state respectively.
  • module.go
    • This is where all the above files get wired together.

Project Structure

The namecoin tutorial and the dApp chain I built have the following structure (names of the core package will change based on your particular app):

README.md
app.go
cmd/
    -> nscli/
                    -> main.go

    -> nsd/
                    -> main.go
go.mod
go.sum
makefile
scripts/
                    -> ...
x/
    -> nameservice/
                    -> alias.go
                    -> client/
                                        -> cli/
                                                        -> query.go
                                                        -> tx.go
                    -> rest/
                                        -> rest.go
                    -> genesis.go
                    -> handler.go
                    -> keeper.go
                    -> module.go
                    -> querier.go
                    -> types/
                                        -> codec.go
                                        -> key.go
                                        -> msgs.go
                                        -> querier.go
                                        -> types.go

This structure is more a convention than a requirement but sticking to convention makes it easier to follow through another Cosmos dApp chain's codebase.

I found many of these files are very generic and boilerplate which I will point out. I will highlight which ones drive the core business logic.

Breakdown

I walk through this structure in the order (lowest to highest number) that I think makes sense when starting a new project.

PathFileOrderDescription
x/nameservice/types/types.go1This is where you define the core types that make up your chain. For example, in the namecoin tutorial the whois structs are defined here.
msgs.go2This is where you define the messages that are used to interact with the types you defined in the previous file. Used by the cli and rest layer.
codec.go3Boilerplate - you register any messages that will need to be un/marshalled. These are messages that come in via the cli or/and rest layer.
querier.go4This contains structs used by your query.go files. These will generally be different to your types.go as this can differ based on the query
key.go5Boilerplate - contains constants used often across your codebase like the ModuleName and StoreKey (used to set and get values from the MultiStore).
x/nameservice/keeper.go6This is like the DAO to your chain's data. It has the CRUD methods to manage the types defined under types.go.
genesis.go8888
handler.go7This is like a business service for the operations that modify your chain's state. It uses the Keeper to access and modify chain state.
module.go9999Boilerplate - this is where everything gets wired together. This is fairly standard and you should not need to do much other than copy-paste here.
querier.go8This is like a business service but for read-only operations. It uses the Keeper to access chain state.
/app.go

codec.go

Under the cli's tx.go class any msg that gets broadcast using utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) will have to be registered in the codec.go.

Types/Messages

This is where I started my dev. The types will drive the contents of the rest of the different chain constructs. Types live in a package with the same name and include the following files:

  • types: This is where you define the core types that make up your chain. For example, in the namechain tutorial, the whois structs are defined here.
  • messages: This is where you define the messages that are used to interact with the types you defined in the previous file.
    • These messages can be thought of as DTOs that you would have in a traditional app at the REST layer.
    • These are generally used by the keeper which is like a DAO to your chain types. As a result, these messages normally have CRUD type verbs in like MsgDeleteFoo

Keeper

This is like a DAO for chain data. It normally has CRUD methods for the different data types you defined in types.go.

The keeper is also what a module exposes to allow other modules to access and manipulate state from within that module as described here

In practice, this means that instead of having each module keep an access control list for other modules, each module implements special objects called keepers that can be passed to other modules to grant a pre-defined set of capabilities.

If your module was implemented correctly, your module's keeper should be the only way that other modules can access and manipulate data in your app. See this article on object capabilities to understand the keeper concept.

Handler

This is something that implements the following interface:

type Handler func(ctx Context, msg Msg) Result

type Result struct {
    // Code is the response code, is stored back on the chain.
    Code CodeType

    // Codespace is the string referring to the domain of an error
    Codespace CodespaceType

    // Data is any data returned from the app.
    // Data has to be length prefixed in order to separate
    // results from multiple msgs executions
    Data []byte

    // Log contains the txs log information. NOTE: nondeterministic.
    Log string

    // GasWanted is the maximum units of work we allow this tx to perform.
    GasWanted uint64

    // GasUsed is the amount of gas actually consumed. NOTE: unimplemented
    GasUsed uint64

    // Events contains a slice of Event objects that were emitted during some
    // execution.
    Events Events
}

Module

This implements variants of this interface based on what you want your app to be able to do.

How To Do Common Things

  • Getting the user sending the transaction: ctx.GetFromAddress() (this is the equivalent of msg.sender in Ethereum).
    • The CLI context and REST contexts should both have this method.
  • Getting the current block number: ctx.BlockHeight()
    • The CLI context and REST contexts should both have this method.

App

As Cosmos SDKs use the capabilities module it is important to note how the app struct and fields in it are private. Other modules wanting to access this module's data need to do so via the module's keeper or via the module's REST or/and CLI layers (which use the keeper under the hood).

The keeper holds the capability to your module's data. Using the keeper is the only way to get and modify data from within that module. As a result, other modules need a reference to your keeper to be able to access your apps data.

Additional Reading and Resources

Concepts

SDK, Components and Architecture

Examples

Account / wallet

An example of an account/wallet in Cosmos is below:

{
  height: '1404',
  result: {
    type: 'cosmos-sdk/Account',
    value: {
      address: 'cosmos1ujvwjc6tup5wtz54pyhysg458xu34cv9r5yxqm', // this is the account's address
      coins: [
        {
          denom: 'stake',
          amount: '100000000',
        },
        {
          denom: 'nametoken',
          amount: '1000',
        },
      ],
      public_key: {
        type: 'tendermint/PubKeySecp256k1',
        value: 'AlVtjGQaeQJmF7x2P22hiqNjFWL43Z+Nl+1s89qappE9',
      },
      account_number: '1',
      sequence: '1',
    },
  },
}

Resources

Ports Exposed

Dapp Daemon (gaiad)

As per this post the ports exposed by Cosmos gaiad are:


By default gaiad uses the following ports:

  • 26656

    • p2p networking port to connect to the tendermint network
    • On a validator this port needs to be exposed to sentry nodes
    • On a sentry node this port needs to be exposed to the open internet
  • 26657

    • Tendermint RPC port
    • This should be shielded from the open internet
  • 26658

    • Out of process ABCI app
    • This should be shielded from the open internet
    • Some optional ports that might be used by gaiad are as follows:
  • 26660

  • 1317

    • Light Client Daemon
    • For automated management of anything you can do with the CLI
    • This should be shielded from the open internet

You can confirm this by running your dapps daemon and then running:

lsof -i :26656

In the above we check which process is using port 26656.

Rest Endpoint

This should be on port 1317 by default. This is usually the REST server on a node.

Libraries

  • CosmosJS
    • A library for front and backend JS to interact with a Cosmos dApp chain.
    • You can do things like:
      • Sign messages.
      • Broadcast signed messages.
      • Get accounts.
  • Cosmostation-mobile
    • This is from the same people who created CosmosJS.
    • An open-source cosmos wallet app for Android and ios.
  • Library to Generate Mnemonics in JS

Core Cosmos SDK Code Classes

Terms

Lotion is a new way to create blockchain apps in JavaScript, which aims to make writing new blockchains fast and fun. It builds on top of Tendermint using the ABCI protocol. Lotion lets you write secure, scalable applications that can easily interoperate with other blockchains on the Cosmos Network using IBC.