Skip to content

Commit

Permalink
Rewrote ibc guide for basecli and relay
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanfrey committed Jun 19, 2017
1 parent 9bb3493 commit 0b7b639
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 72 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ BREAKING CHANGES:
- enhanced relay subcommand
- relay start did what relay used to do
- relay init registers both chains on one another (to set it up so relay start just works)
- docs
- removed `example-plugin`, put `counter` inside `docs/guide`

ENHANCEMENTS:
- intergrates tendermint 0.10.0 (not the rc-2, but the real thing)
Expand All @@ -33,6 +35,7 @@ ENHANCEMENTS:

BUG FIXES:
- no longer panics on missing app_options in genesis (thanks, anton)
- updated all docs... again


## 0.5.2 (June 2, 2017)
Expand Down
237 changes: 167 additions & 70 deletions docs/guide/ibc.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,22 @@ the key and value are contained in the Merkle tree.
The results of a query can thus be used as proof in an `IBCPacketPostTx`.
## Relay
While we need all these packet types internally to keep track of all the
proofs on both chains in a secure manner, for the normal work-flow, where
we just use the FIFO queue on each side for pending message to send as soon
as possible.
In this case, there are only two steps. First `basecoin relay init`,
which must be run once to register each chain with the other one,
and make sure they are ready to send and recieve. And then
`basecoin relay start`, which is a long-running process polling the queue
on each side, and relaying all new message to the other block.
This requires that the relay has access to accounts with some funds on both
chains to pay for all the ibc packets it will be forwarding.
## Try it out
Now that we have all the background knowledge, let's actually walk through the
Expand All @@ -173,116 +189,197 @@ comes with an `IBC` plugin enabled by default.
You will also want to install the [jq](https://stedolan.github.io/jq/) for
handling JSON at the command line.
Now let's start the two blockchains. In this tutorial, each chain will have
only a single validator, where the initial configuration files are already
generated. Let's change directory so these files are easily accessible:
If you have any trouble with this, you can also look at the
[test scripts](/tests/cli/ibc.sh) or just run `make test_cli` in basecoin repo.
Otherwise, open up 5 (yes 5!) terminal tabs....
``` cd $GOPATH/src/github.com/tendermint/basecoin/demo ```
### Setup Chain 1
The relevant data is now in the `data` directory. Before we begin, let's set
some environment variables for convenience:
All commands will be prefixed by the name of the terminal window in which to
run it...
``` export BCHOME="." BCHOME1="./data/chain1" BCHOME2="./data/chain2"
```
# first, clean up any old garbage for a fresh slate...
rm -rf ~/.ibcdemo/
```

export CHAIN_ID1=test_chain_1 export CHAIN_ID2=test_chain_2
Set up some accounts so we can init everything nicely:

CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from $BCHOME1/key.json"
CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from $BCHOME2/key.json --node
tcp://localhost:36657" ```
**Client1**
```
export BCHOME=~/.ibcdemo/chain1/client
CHAIN_ID=test-chain-1
PORT=12347
basecli keys new money
basecli keys new gotnone
```

Prepare the genesis block and start the server:

**Server1**
```
# set up the directory, chainid and port of this chain...
export BCHOME=~/.ibcdemo/chain1/server
CHAIN_ID=test-chain-1
PREFIX=1234
basecoin init
GENKEY=`basecli keys get money -o json --home=$HOME/.ibcdemo/chain1/client | jq .pubkey.data`
GENJSON=`cat $BCHOME/genesis.json`
echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY | jq ".chain_id=\"$CHAIN_ID\"" > $BCHOME/genesis.json
sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml
basecoin start
```

In previous examples, we started basecoin in-process with tendermint. Here, we
will run them in different processes, using the `--without-tendermint` flag, as
described in the [guide to the basecoin tool](basecoin-tool.md). We can start
the two chains as follows:
Attach the client to the chain and confirm state. The first account should
have money, the second none:

``` TMROOT=$BCHOME1 tendermint node --log_level=info &> chain1_tendermint.log &
BCHOME=$BCHOME1 basecoin start --without-tendermint &> chain1_basecoin.log &
**Client1**
```
basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT}
ME=`basecli keys get money -o=json | jq .address | tr -d '"'`
YOU=`basecli keys get gotnone -o=json | jq .address | tr -d '"'`
basecli query account $ME
basecli query account $YOU
```

### Setup Chain 2

and
This is the same as above, except in two new terminal windows with
different chain ids, ports, etc. Note that you need to make new accounts
on this chain, as the "cool" key only has money on chain 1.

``` TMROOT=$BCHOME2 tendermint node --log_level=info --node_laddr
tcp://localhost:36656 --rpc_laddr tcp://localhost:36657 --proxy_app
tcp://localhost:36658 &> chain2_tendermint.log & BCHOME=$BCHOME2 basecoin start
--address tcp://localhost:36658 --without-tendermint &> chain2_basecoin.log &

**Client2**
```
export BCHOME=~/.ibcdemo/chain2/client
CHAIN_ID=test-chain-2
PORT=23457
basecli keys new moremoney
basecli keys new broke
```

Note how we refer to the relevant data directories, and how we set the various
addresses for the second node so as not to conflict with the first.
Prepare the genesis block and start the server:

We can now check on the status of the two chains:
**Server2**
```
# set up the directory, chainid and port of this chain...
export BCHOME=~/.ibcdemo/chain2/server
CHAIN_ID=test-chain-2
PREFIX=2345
basecoin init
``` curl localhost:46657/status curl localhost:36657/status ```
If either command fails, the nodes may not have finished starting up. Wait a
couple seconds and try again. Once you see the status of both chains, it's
time to move on.
GENKEY=`basecli keys get moremoney -o json --home=$HOME/.ibcdemo/chain2/client | jq .pubkey.data`
GENJSON=`cat $BCHOME/genesis.json`
echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY | jq ".chain_id=\"$CHAIN_ID\"" > $BCHOME/genesis.json
In this tutorial, we're going to send some data from `test_chain_1` to
`test_chain_2`. We begin by registering `test_chain_1` on `test_chain_2`:
sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml
``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --ibc_chain_id
$CHAIN_ID1 --genesis $BCHOME1/genesis.json ```
basecoin start
```

Now we can create the outgoing packet on `test_chain_1`:
Attach the client to the chain and confirm state. The first account should
have money, the second none:

``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --ibc_from
$CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --ibc_sequence 1
**Client2**
```
basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT}
ME=`basecli keys get moremoney -o=json | jq .address | tr -d '"'`
YOU=`basecli keys get broke -o=json | jq .address | tr -d '"'`
basecli query account $ME
basecli query account $YOU
```

Note our payload is just `DEADBEEF`. Now that the packet is committed in the
chain, let's get some proof by querying:
### Connect these chains

``` QUERY=$(basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,1) echo $QUERY ```
Great, so we have two chains running on your local machine, with different
keys on each. Now it is time to hook them up together. Let's start
a relay to forward the messages.

The result contains the latest height, a value (i.e. the hex-encoded binary
serialization of our packet), and a proof (i.e. hex-encoded binary
serialization of a list of nodes from the Merkle tree) that the value is in the
Merkle tree. We keep the result in the `QUERY` variable so we can easily
reference subfields using the `jq` tool.
The relay account needs some money in it to pay for the ibc messages, so
for now, we have to transfer some cash from the rich accounts before we start
the actual relay.

If we want to send this data to `test_chain_2`, we first have to update what it
knows about `test_chain_1`. We'll need a recent block header and a set of
commit signatures. Fortunately, we can get them with the `block` command:
**Client1**
```
# note that this key.json file is a hardcoded demo for all chains, this will
# be updated in a future release
RELAY_KEY=${BCHOME}/../server/key.json
RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \")
basecli tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=money
basecli query account $RELAY_ADDR
```

``` BLOCK=$(basecoin block $(echo $QUERY | jq .height)) echo $BLOCK ```
**Client2**
```
# note that this key.json file is a hardcoded demo for all chains, this will
# be updated in a future release
RELAY_KEY=${BCHOME}/../server/key.json
RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \")
basecli tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney
basecli query account $RELAY_ADDR
```

Here, we are passing `basecoin block` the `height` from our earlier query.
Note the result contains both a hex-encoded and json-encoded version of the
header and the commit. The former is used as input for later commands; the
latter is human-readable, so you know what's going on!
**Relay**
```
# lots of config...
SERVER_1=~/.ibcdemo/chain1/server
SERVER_2=~/.ibcdemo/chain2/server
CHAIN_ID_1=test-chain-1
CHAIN_ID_2=test-chain-2
PORT_1=12347
PORT_2=23457
RELAY_KEY=${SERVER_1}/key.json
basecoin relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \
--chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \
--genesis1=${SERVER_1}/genesis.json --genesis2=${SERVER_2}/genesis.json \
--from=$RELAY_KEY
basecoin relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \
--chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \
--from=$RELAY_KEY
```

Let's send this updated information about `test_chain_1` to `test_chain_2`.
First, output the header and commit for reference:
This should start up the relay, and assuming no error messages came out,
the two chains are now fully connected over IBC. Let's use this to send
our first tx accross the chains...

``` echo $BLOCK | jq .hex.header echo $BLOCK | jq .hex.commit ```
### Sending cross-chain payments

And now forward those values to `test_chain_2`:
The hard part is over, we set up two blockchains, a few private keys, and
a secure relay between them. Now we can enjoy the fruits of our labor...

``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 update --header 0x<header>
--commit 0x<commit> ```
**Client2**

Now that `test_chain_2` knows about some recent state of `test_chain_1`, we can
post the packet to `test_chain_2`, along with proof the packet was committed on
`test_chain_1`. Since `test_chain_2` knows about some recent state of
`test_chain_1`, it will be able to verify the proof!
```
# this should be empty
basecli query account $YOU
# now, we get the key to copy to the other terminal
echo $YOU
```

First, output the height, packet, and proof for reference:
**Client1**

```
echo $QUERY | jq .height
echo $QUERY | jq .value
echo $QUERY | jq .proof
# set TARGET to be $YOU from the other chain
basecli tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$TARGET --name=money
```

And forward those values to `test_chain_2`:
**Client2**

```
basecoin tx ibc --amount=10mycoin $CHAIN_FLAGS2 packet post --ibc_from $CHAIN_ID1 --height <height> --packet 0x<packet> --proof 0x<proof>
# give it time to arrive...
sleep 1
# now you should see 12345 coins!
basecli query account $YOU
```

If the command does not return an error, then we have successfuly transfered
data from `test_chain_1` to `test_chain_2`. Tada!
Cool, huh? Now have fun exploring and sending coins across the chains. And
making more accounts as you want to.

## Conclusion

Expand Down
4 changes: 2 additions & 2 deletions tests/cli/ibc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@ startRelay() {
${SERVER_EXE} relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \
--chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \
--genesis1=${BASE_DIR_1}/server/genesis.json --genesis2=${BASE_DIR_2}/server/genesis.json \
--from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log &
--from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log
if [ $? != 0 ]; then echo "can't initialize relays"; cat ${BASE_DIR_1}/../relay.log; return 1; fi

# now start the relay (constantly send packets)
${SERVER_EXE} relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \
--chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \
--from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log &
--from=$RELAY_KEY >> ${BASE_DIR_1}/../relay.log &
sleep 2
PID_RELAY=$!
disown
Expand Down

0 comments on commit 0b7b639

Please sign in to comment.