Using The Staking Module

This project is a demonstration of the Cosmos Hub staking functionality; it is designed to get validator acquianted with staking concepts and procedures.

Potential validators will be declaring their candidacy, after which users can delegate and, if they so wish, unbond. This can be practiced using a local or public testnet.

This example covers initial setup of a two-node testnet between a server in the cloud and a local machine. Begin this tutorial from a cloud machine that you’ve ssh’d into.

Install

The gaiad and gaiacli binaries:

go get github.com/cosmos/cosmos-sdk
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
make get_vendor_deps
make install

Let’s jump right into it. First, we initialize some default files:

gaiad init

which will output:

I[03-30|11:20:13.365] Found private validator                      module=main path=/root/.gaiad/config/priv_validator.json
I[03-30|11:20:13.365] Found genesis file                           module=main path=/root/.gaiad/config/genesis.json
Secret phrase to access coins:
citizen hungry tennis noise park hire glory exercise link glow dolphin labor design grit apple abandon

This tell us we have a priv_validator.json and genesis.json in the ~/.gaiad/config directory. A config.toml was also created in the same directory. It is a good idea to get familiar with those files. Write down the seed.

The next thing we’ll need to is add the key from priv_validator.json to the gaiacli key manager. For this we need a seed and a password:

gaiacli keys add alice --recover

which will give you three prompts:

Enter a passphrase for your key:
Repeat the passphrase:
Enter your recovery seed phrase:

create a password and copy in your seed phrase. The name and address of the key will be output:

::
NAME: ADDRESS: PUBKEY: alice 67997DD03D527EB439B7193F2B813B05B219CC02 1624DE6220BB89786C1D597050438C728202436552C6226AB67453CDB2A4D2703402FB52B6

You can see all available keys with:

gaiacli keys list

Setup Testnet

Next, we start the daemon (do this in another window):

gaiad start

and you’ll see blocks start streaming through.

For this example, we’re doing the above on a cloud machine. The next steps should be done on your local machine or another server in the cloud, which will join the running testnet then bond/unbond.

Accounts

We have:

  • alice the initial validator (in the cloud)
  • bob receives tokens from alice then declares candidacy (from local machine)
  • charlie will bond and unbond to bob (from local machine)

Remember that alice was already created. On your second machine, install the binaries and create two new keys:

gaiacli keys add bob
gaiacli keys add charlie

both of which will prompt you for a password. Now we need to copy the genesis.json and config.toml from the first machine (with alice) to the second machine. This is a good time to look at both these files.

The genesis.json should look something like:

{
  "app_state": {
    "accounts": [
      {
        "address": "1D9B2356CAADF46D3EE3488E3CCE3028B4283DEE",
        "coins": [
          {
            "denom": "steak",
            "amount": 100000
          }
        ]
      }
    ],
    "stake": {
      "pool": {
        "total_supply": 0,
        "bonded_shares": {
          "num": 0,
          "denom": 1
        },
        "unbonded_shares": {
          "num": 0,
          "denom": 1
        },
        "bonded_pool": 0,
        "unbonded_pool": 0,
        "inflation_last_time": 0,
        "inflation": {
          "num": 7,
          "denom": 100
        }
      },
      "params": {
        "inflation_rate_change": {
          "num": 13,
          "denom": 100
        },
        "inflation_max": {
          "num": 20,
          "denom": 100
        },
        "inflation_min": {
          "num": 7,
          "denom": 100
        },
        "goal_bonded": {
          "num": 67,
          "denom": 100
        },
        "max_validators": 100,
        "bond_denom": "steak"
      }
    }
  },
  "validators": [
    {
      "pub_key": {
        "type": "AC26791624DE60",
        "value": "rgpc/ctVld6RpSfwN5yxGBF17R1PwMTdhQ9gKVUZp5g="
      },
      "power": 10,
      "name": ""
    }
  ],
  "app_hash": "",
  "genesis_time": "0001-01-01T00:00:00Z",
  "chain_id": "test-chain-Uv1EVU"
}

To notice is that the accounts field has a an address and a whole bunch of “mycoin”. This is alice’s address (todo: dbl check). Under validators we see the pub_key.data field, which will match the same field in the priv_validator.json file.

The config.toml is long so let’s focus on one field:

# Comma separated list of seed nodes to connect to
seeds = ""

On the alice cloud machine, we don’t need to do anything here. Instead, we need its IP address. After copying this file (and the genesis.json to your local machine, you’ll want to put the IP in the seeds =  "138.197.161.74" field, in this case, we have a made-up IP. For joining testnets with many nodes, you can add more comma-seperated IPs to the list.

Now that your files are all setup, it’s time to join the network. On your local machine, run:

gaiad start

and your new node will connect to the running validator (alice).

Sending Tokens

We’ll have alice send some mycoin to bob, who has now joined the network:

gaiacli send --amount=1000mycoin --sequence=0 --name=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU

where the --sequence flag is to be incremented for each transaction, the --name flag is the sender (alice), and the --to flag takes bob’s address. You’ll see something like:

Please enter passphrase for alice:
{
  "check_tx": {
    "gas": 30
  },
  "deliver_tx": {
    "tags": [
      {
        "key": "height",
        "value_type": 1,
        "value_int": 2963
      },
      {
        "key": "coin.sender",
        "value_string": "5D93A6059B6592833CBC8FA3DA90EE0382198985"
      },
      {
        "key": "coin.receiver",
        "value_string": "5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6"
      }
    ]
  },
  "hash": "423BD7EA3C4B36AF8AFCCA381C0771F8A698BA77",
  "height": 2963
}

TODO: check the above with current actual output.

Check out bob’s account, which should now have 1000 mycoin:

gaiacli account 5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6

Adding a Second Validator

This section is wrong/needs to be updated

Next, let’s add the second node as a validator.

First, we need the pub_key data:

** need to make bob a priv_Val above?

cat $HOME/.gaia2/priv_validator.json

the first part will look like:

{"address":"7B78527942C831E16907F10C3263D5ED933F7E99","pub_key":{"type":"ed25519","data":"96864CE7085B2E342B0F96F2E92B54B18C6CC700186238810D5AA7DFDAFDD3B2"},

and you want the pub_key data that starts with 96864CE.

Now bob can declare candidacy to that pubkey:

gaiacli declare-candidacy --amount=10mycoin --name=bob --pubkey=<pub_key data> --moniker=bobby

with an output like:

Please enter passphrase for bob:
{
  "check_tx": {
    "gas": 30
  },
  "deliver_tx": {},
  "hash": "2A2A61FFBA1D7A59138E0068C82CC830E5103799",
  "height": 4075
}

We should see bob’s account balance decrease by 10 mycoin:

gaiacli account 5D93A6059B6592833CBC8FA3DA90EE0382198985

To confirm for certain the new validator is active, ask the tendermint node:

curl localhost:46657/validators

If you now kill either node, blocks will stop streaming in, because there aren’t enough validators online. Turn it back on and they will start streaming again.

Now that bob has declared candidacy, which essentially bonded 10 mycoin and made him a validator, we’re going to get charlie to delegate some coins to bob.

Delegating

First let’s have alice send some coins to charlie:

gaiacli tx --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF

Then charlie will delegate some mycoin to bob:

gaiacli tx delegate --amount=10mycoin --name=charlie --pubkey=<pub_key data>

You’ll see output like:

Please enter passphrase for charlie:
{
  "check_tx": {
    "gas": 30
  },
  "deliver_tx": {},
  "hash": "C3443BA30FCCC1F6E3A3D6AAAEE885244F8554F0",
  "height": 51585
}

And that’s it. You can query charlie’s account to see the decrease in mycoin.

To get more information about the candidate, try:

gaiacli query candidate --pubkey=<pub_key data>

and you’ll see output similar to:

{
  "height": 51899,
  "data": {
    "pub_key": {
      "type": "ed25519",
      "data": "52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B"
    },
    "owner": {
      "chain": "",
      "app": "sigs",
      "addr": "5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6"
    },
    "shares": 20,
    "voting_power": 20,
    "description": {
      "moniker": "bobby",
      "identity": "",
      "website": "",
      "details": ""
    }
  }
}

It’s also possible the query the delegator’s bond like so:

gaiacli query delegator-bond --delegator-address 48F74F48281C89E5E4BE9092F735EA519768E8EF --pubkey 52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B

with an output similar to:

{
  "height": 325782,
  "data": {
    "PubKey": {
      "type": "ed25519",
      "data": "52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B"
    },
    "Shares": 20
  }
}

where the --delegator-address is charlie’s address and the -pubkey is the same as we’ve been using.

Unbonding

Finally, to relinquish your voting power, unbond some coins. You should see your VotingPower reduce and your account balance increase.

gaiacli unbond --amount=5mycoin --name=charlie --pubkey=<pub_key data>
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF

See the bond decrease with gaiacli query delegator-bond like above.