Building an application specific blockchain using Cosmos SDK Part-5

Harish Bhawnani
Coinmonks
6 min readApr 7, 2022

--

Photo by Markus Spiske on Unsplash

In last part we covered handling the msg transactions. Hope you have tested handlers locally :) . In current part we will learn about indexing custom events & how users can subscribe to them via tendermint rpc websocket. Also we will see, how one can handle the state migrations during chain upgrade.

Indexing & Subscribing to custom events:

Tendermint allows us to index transactions and blocks and later query or subscribe to their results. By default tendermint uses the KV storage for indexing and tx.height, tx.hash are always indexed by default. Let’s see the custom event indexing in action.

One can index the custom events based on composite key. For suppose, we emit a custom event when creating a deal -

Here the composite keys for above custom events are -

  • message.module=’deal’
  • message.action=’create_deal’
  • message.idvalue={dealId}

etc…

Lets index the composite key message.action=’create_deal’

Configuration, genesis, private keys and storage files are generally stored under home directory in a hidden folder (.appName). In our case hidden folder name would be .deal You can find the same on your local machine. Among various configuration files,config.toml is the one that contains different parameters related to tendermint consensus engine, whereas app.toml contains app-specific parameters. Genesis.json contains the genesis state for each of the module.

Open the config.toml file and add the following tags field under indexer=kv.

Save the file and restart the chain. Before creating any deal let us subscribe to the composite key “message.action=’create_deal’” via web socket. You can use any web socket cli client or install the one- https://github.com/oliver006/ws-client for testing.

Open another terminal and run the command-

Now we are subscribed to the /subscribe tendermint RPC endpoint for custom event type create_deal . Let’s open a new instance of terminal to issue the create deal tx -

As soon as execution gets completed, tendermint indexes the event and we get back the response via web-socket. For instance, I got back the response as below:

You can also index multiple-events using tags field in config.toml-

Note that tendermint will be implementing psql indexer & kv will be deprecated in future as the query syntax is limited for the kv indexer type whereas psql indexer will be able to proxy events to an external configured Postgresql instance. This will leverage SQL to perform a series of rich and complex queries which are not supported by the kv indexer type. Good to see more interesting features soon :)

Handling chain upgrades via in-place store migrations:

Suppose our chain is live in production and we want to upgrade the same. For instance to add the new feature, we might want to change the state structure. Or let us consider a simple task of removing expired contracts from the store. We do have an upgrade chain guide available here as part of cosmos sdk documentation - doc . We will refer the same for our migration example.

Let’s create a migrator concrete type inside our keeper package.

The migrator wraps around the keeper which will be useful to make state transitions in migration script. We will put our migration script inside legacy folder under v01 package as suggested in the guide.

We are iterating over the contracts for each deal, to identify and delete the expired contracts. We will invoke this script via method on migration object -

We will now register the Migrate2to3 method under configurator via registerMigration method for consensus version 3. Note the configurator is accessible under module method- RegisterServices

One can register multiple migrations on configurator.

The x/upgrade module keeps track of all module consensus versions in the VersionMap store. To trigger the migration during upgrade we also need to update the consensus version for our module. Let’s change it from 2 to 3-

Any number of migrations registered on configurator for version 3 will be triggered during chain upgrade from module consensus version 2.

The chain upgrades usually takes place via voting on proposals. Proposals are usually submitted by the stakeholders via tx corresponding to gov module. Once validators and delegators participate and vote for the submitted proposal and voting period is completed, upgrade takes place at a certain block height via upgrade keeper handler. Thus we need to set the upgrade handler to carry out the migrations.

The upgradeHandler will invoke the RunMigrations method on module manager which will internally invoke our module migration script. RunMigrations will also return back the new consensus version which will be then persisted in VersionMap store of x/upgrade module. Thus confirming the stable upgrade and latest consensus version of module.

One can submit the proposal to governance module-

and vote for it

Upgrade will occur automatically at block height 100.

As part of local development, one might want to test the migration scripts locally, without going via proposal way. To achieve it, one of the hack could be invoking migration script in module EndBlock method (As EndBlock gets automatically executed after each block, we will be able to test our migration script locally however this hack is not advisable for huge amount of migration data)-

Enough learning for today :) Will cover the blockchain test simulation in next part.

--

--