Cosmos SDK Rosetta API Gateway and library - 0.39 Launchpad

At Tendermint, we’ve just announced the release of an initial implementation of the Rosetta API specifications that will enable blockchain applications built on Cosmos SDK 0.39 “Launchpad” to make blockchain data available through Rosetta API-compliant endpoints.

Application developers can provide their applications with Rosetta API support by either executing a standalone gateway application or embedding the gateway functionalities in the blockchain application’s node.

How to install the Rosetta API Standalone gateway

Clone the repo

$ git clone -b v0.1.0 https://github.com/tendermint/cosmos-rosetta-gateway

Make sure you GOPATH is set, compile and install the gateway:

$ cd cosmos-rosetta-gateway
$ make install
$ crg --help

Testing the API

Requirements:
Any chain that uses the Cosmos SDK version 0.39.1 should work. (If not please open an issue). We will use Starport tool to scaffold and run a blockchain application and test against it. Here we go!

Download starport and create a new application:

$ starport app github.com/jgimeno/blog
$ cd blog
$ starport serve --verbose

These 3 commands should initiate a blockchain to run on your machine.

Look for flags:

  • -prefix : This flag is important, as not every cosmos blockchain uses the default “cosmos” prefix. For example, for IOV blockchain we would use -prefix star.
  • -blockchain and -network: These flags allow you to change the name of your blockchain application and the network name. These values are used by Rosseta in the network’s list endpoint. For example, for Bitcoin you would set — blockchain bitcoin — network mainnet.
  • -app-rpc and -tendermint-rpc: As default this point to localhost:1317 and localhost:26657. But you can put the endpoints that you need for testing. Remember that in Rosetta’s spec is mentioned that they should not talk with an external service when packing it to a Dockerfile.
  • -port: By default the Rosetta service listens on 8080, use the one that works better for you.

Execute the application:

$ crg

If everything went, well we would have our service listening at port 8080.

Pulling Data

On top of the endpoints that are documented in the official Rosetta site, we have prepared a basic Postman collection in order to help with testing and using the endpoints, that you can find here.

2 Likes

Very cool, @alessio! Have you begun testing any implementations (or your demo implementation) with the rosetta-cli yet?

Many teams also post the configuration file they used to validate their implementation’s adherence to the Rosetta Spec (example for Bitcoin).

Hello Patrick! :handshake:

Yes, the team found the tool extremely helpful and is now working to integrate it in our CI pipelines.

This is an initial implementation/MVP, as such it still lacks a few things (e.g. staking support). In our next release we’re planning to improve it and introduce support for the Cosmos SDK’s would-be next stable release (0.40 Stargate). So stay tuned please, further updates will ensue shortly! :sunglasses:

Thanks!

Great to hear! If they have any feedback on the tool or experience, I’m all ears.

:rocket: :rocket:

1 Like

Hello Patrick! We have made it, we made the construction pass.

+--------------------------+--------------------------------+-------+
| CHECK:CONSTRUCTION STATS |          DESCRIPTION           | VALUE |
+--------------------------+--------------------------------+-------+
| Addresses Created        | # of addresses created         |     2 |
+--------------------------+--------------------------------+-------+
| Transactions Created     | # of transactions created      |     1 |
+--------------------------+--------------------------------+-------+
| Stale Broadcasts         | # of broadcasts missing after  |     0 |
|                          | stale depth                    |       |
+--------------------------+--------------------------------+-------+
| Transactions Confirmed   | # of transactions seen         |     1 |
|                          | on-chain                       |       |
+--------------------------+--------------------------------+-------+
| Failed Broadcasts        | # of transactions that         |     0 |
|                          | exceeded broadcast limit       |       |
+--------------------------+--------------------------------+-------+
+------------------------------+-------+
| CHECK:CONSTRUCTION WORKFLOWS | COUNT |
+------------------------------+-------+
| request_funds                |     1 |
+------------------------------+-------+
| create_account               |     2 |
+------------------------------+-------+
| transfer                     |     1 |
+------------------------------+-------+

I share the config files used for the validation:

{
 "network": {
  "blockchain": "Test",
  "network": "Test"
 },
 "online_url": "http://localhost:8080",
 "data_directory": "",
 "http_timeout": 300,
 "max_retries": 5,
 "retry_elapsed_time": 0,
 "max_online_connections": 0,
 "max_sync_concurrency": 0,
 "tip_delay": 60,
 "log_configuration": true,
 "construction": {
  "offline_url": "http://localhost:8080",
  "max_offline_connections": 0,
  "stale_depth": 0,
  "broadcast_limit": 0,
  "ignore_broadcast_failures": false,
  "clear_broadcasts": false,
  "broadcast_behind_tip": false,
  "block_broadcast_limit": 0,
  "rebroadcast_all": false,
  "constructor_dsl_file": "cosmos.ros",
  "end_conditions": {
   "create_account": 10,
   "transfer": 10
  }
 },
 "data": {
  "active_reconciliation_concurrency": 0,
  "inactive_reconciliation_concurrency": 0,
  "inactive_reconciliation_frequency": 0,
  "log_blocks": false,
  "log_transactions": false,
  "log_balance_changes": false,
  "log_reconciliations": false,
  "ignore_reconciliation_error": false,
  "exempt_accounts": "",
  "bootstrap_balances": "bootstrap.json",
  "interesting_accounts": "",
  "reconciliation_disabled": false,
  "inactive_discrepency_search_disabled": false,
  "balance_tracking_disabled": false,
  "coin_tracking_disabled": false,
  "end_conditions": {
   "reconciliation_coverage": {
     "coverage":0.95,
     "from_tip": true
   }
  },
  "results_output_file": "myresult.json"
 }
}

And the cosmos.ros:

request_funds(1){
  find_account{
    currency = {"symbol":"token", "decimals":0};
    random_account = find_balance({
      "minimum_balance":{
        "value": "0",
        "currency": {{currency}}
      },
      "create_limit":1
    });
  },

  // Create a separate scenario to request funds so that
  // the address we are using to request funds does not
  // get rolled back if funds do not yet exist.
  request{
    loaded_account = find_balance({
      "account_identifier": {{random_account.account_identifier}},
      "minimum_balance":{
        "value": "100",
        "currency": {{currency}}
      }
    });
  }
}

create_account(1){
  create{
    network = {"network":"Test", "blockchain":"Test"};
    key = generate_key({"curve_type": "secp256k1"});
    account = derive({
      "network_identifier": {{network}},
      "public_key": {{key.public_key}}
    });

    // If the account is not saved, the key will be lost!
    save_account({
      "account_identifier": {{account.account_identifier}},
      "keypair": {{key}}
    });
  }
}


transfer(10){
  transfer{
    transfer.network = {"network":"Test", "blockchain":"Test"};
    currency = {"symbol":"token", "decimals":0};
    sender = find_balance({
      "minimum_balance":{
        "value": "100",
        "currency": {{currency}}
      }
    });

    // Set the recipient_amount as some value <= sender.balance-max_fee
    max_fee = "0";
    available_amount = {{sender.balance.value}} - {{max_fee}};
    recipient_amount = random_number({"minimum": "1", "maximum": {{available_amount}}});
    print_message({"recipient_amount":{{recipient_amount}}});

    // Find recipient and construct operations
    sender_amount = 0 - {{recipient_amount}};
    recipient = find_balance({
      "not_account_identifier":[{{sender.account_identifier}}],
      "minimum_balance":{
        "value": "0",
        "currency": {{currency}}
      },
      "create_limit": 100,
      "create_probability": 50
    });
    transfer.confirmation_depth = "1";
    transfer.operations = [
      {
        "operation_identifier":{"index":0},
        "type":"Transfer",
        "account":{{sender.account_identifier}},
        "amount":{
          "value":{{sender_amount}},
          "currency":{{currency}}
        }
      },
      {
        "operation_identifier":{"index":1},
        "type":"Transfer",
        "account":{{recipient.account_identifier}},
        "amount":{
          "value":{{recipient_amount}},
          "currency":{{currency}}
        }
      }
    ];
  }
}

Thanks a lot, this tool has been very helpful in order to validate the spec.

2 Likes

Great to hear! I’m all ears if you have any recommendations on how we can make things even better.

On another note, you may find it useful to setup automated account fauceting and fund return (upon test completion) if you plan to run rosetta-cli in some sort of CI scenario. We don’t have any public examples we’ve shared that perform fauceting but I’m sure you could imagine how it could be done with the load_env action (to load any API token) and the http_request action. We do, however, have an example of fund return for Ethereum:

Thanks Patrick!

As we are not really using a real network (not event a public testnet) that we need to return the funds, for the CI we plan to execute a new network everytime the CI is executed and then parse the logs in order to generate a transaction to set funds.

I think this will work for us.