290 lines
9.3 KiB
ReStructuredText
290 lines
9.3 KiB
ReStructuredText
|
Basecoin Basics
|
||
|
===============
|
||
|
|
||
|
Here we explain how to get started with a basic Basecoin blockchain, how
|
||
|
to send transactions between accounts using the ``basecoin`` tool, and
|
||
|
what is happening under the hood.
|
||
|
|
||
|
Install
|
||
|
-------
|
||
|
|
||
|
With go, it's one command:
|
||
|
|
||
|
::
|
||
|
|
||
|
go get -u github.com/cosmos/cosmos-sdk
|
||
|
|
||
|
If you have trouble, see the `installation guide <./install.html>`__.
|
||
|
|
||
|
TODO: update all the below
|
||
|
|
||
|
Generate some keys
|
||
|
~~~~~~~~~~~~~~~~~~
|
||
|
|
||
|
Let's generate two keys, one to receive an initial allocation of coins,
|
||
|
and one to send some coins to later:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli keys new cool
|
||
|
basecli keys new friend
|
||
|
|
||
|
You'll need to enter passwords. You can view your key names and
|
||
|
addresses with ``basecli keys list``, or see a particular key's address
|
||
|
with ``basecli keys get <NAME>``.
|
||
|
|
||
|
Initialize Basecoin
|
||
|
-------------------
|
||
|
|
||
|
To initialize a new Basecoin blockchain, run:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecoin init <ADDRESS>
|
||
|
|
||
|
If you prefer not to copy-paste, you can provide the address
|
||
|
programatically:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecoin init $(basecli keys get cool | awk '{print $2}')
|
||
|
|
||
|
This will create the necessary files for a Basecoin blockchain with one
|
||
|
validator and one account (corresponding to your key) in
|
||
|
``~/.basecoin``. For more options on setup, see the `guide to using the
|
||
|
Basecoin tool </docs/guide/basecoin-tool.md>`__.
|
||
|
|
||
|
If you like, you can manually add some more accounts to the blockchain
|
||
|
by generating keys and editing the ``~/.basecoin/genesis.json``.
|
||
|
|
||
|
Start Basecoin
|
||
|
~~~~~~~~~~~~~~
|
||
|
|
||
|
Now we can start Basecoin:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecoin start
|
||
|
|
||
|
You should see blocks start streaming in!
|
||
|
|
||
|
Initialize Light-Client
|
||
|
-----------------------
|
||
|
|
||
|
Now that Basecoin is running we can initialize ``basecli``, the
|
||
|
light-client utility. Basecli is used for sending transactions and
|
||
|
querying the state. Leave Basecoin running and open a new terminal
|
||
|
window. Here run:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli init --node=tcp://localhost:46657 --genesis=$HOME/.basecoin/genesis.json
|
||
|
|
||
|
If you provide the genesis file to basecli, it can calculate the proper
|
||
|
chainID and validator hash. Basecli needs to get this information from
|
||
|
some trusted source, so all queries done with ``basecli`` can be
|
||
|
cryptographically proven to be correct according to a known validator
|
||
|
set.
|
||
|
|
||
|
Note: that ``--genesis`` only works if there have been no validator set
|
||
|
changes since genesis. If there are validator set changes, you need to
|
||
|
find the current set through some other method.
|
||
|
|
||
|
Send transactions
|
||
|
~~~~~~~~~~~~~~~~~
|
||
|
|
||
|
Now we are ready to send some transactions. First Let's check the
|
||
|
balance of the two accounts we setup earlier:
|
||
|
|
||
|
::
|
||
|
|
||
|
ME=$(basecli keys get cool | awk '{print $2}')
|
||
|
YOU=$(basecli keys get friend | awk '{print $2}')
|
||
|
basecli query account $ME
|
||
|
basecli query account $YOU
|
||
|
|
||
|
The first account is flush with cash, while the second account doesn't
|
||
|
exist. Let's send funds from the first account to the second:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1
|
||
|
|
||
|
Now if we check the second account, it should have ``1000`` 'mycoin'
|
||
|
coins!
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli query account $YOU
|
||
|
|
||
|
We can send some of these coins back like so:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli tx send --name=friend --amount=500mycoin --to=$ME --sequence=1
|
||
|
|
||
|
Note how we use the ``--name`` flag to select a different account to
|
||
|
send from.
|
||
|
|
||
|
If we try to send too much, we'll get an error:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli tx send --name=friend --amount=500000mycoin --to=$ME --sequence=2
|
||
|
|
||
|
Let's send another transaction:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli tx send --name=cool --amount=2345mycoin --to=$YOU --sequence=2
|
||
|
|
||
|
Note the ``hash`` value in the response - this is the hash of the
|
||
|
transaction. We can query for the transaction by this hash:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli query tx <HASH>
|
||
|
|
||
|
See ``basecli tx send --help`` for additional details.
|
||
|
|
||
|
Proof
|
||
|
-----
|
||
|
|
||
|
Even if you don't see it in the UI, the result of every query comes with
|
||
|
a proof. This is a Merkle proof that the result of the query is actually
|
||
|
contained in the state. And the state's Merkle root is contained in a
|
||
|
recent block header. Behind the scenes, ``countercli`` will not only
|
||
|
verify that this state matches the header, but also that the header is
|
||
|
properly signed by the known validator set. It will even update the
|
||
|
validator set as needed, so long as there have not been major changes
|
||
|
and it is secure to do so. So, if you wonder why the query may take a
|
||
|
second... there is a lot of work going on in the background to make sure
|
||
|
even a lying full node can't trick your client.
|
||
|
|
||
|
Accounts and Transactions
|
||
|
-------------------------
|
||
|
|
||
|
For a better understanding of how to further use the tools, it helps to
|
||
|
understand the underlying data structures.
|
||
|
|
||
|
Accounts
|
||
|
~~~~~~~~
|
||
|
|
||
|
The Basecoin state consists entirely of a set of accounts. Each account
|
||
|
contains a public key, a balance in many different coin denominations,
|
||
|
and a strictly increasing sequence number for replay protection. This
|
||
|
type of account was directly inspired by accounts in Ethereum, and is
|
||
|
unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). Note
|
||
|
Basecoin is a multi-asset cryptocurrency, so each account can have many
|
||
|
different kinds of tokens.
|
||
|
|
||
|
::
|
||
|
|
||
|
type Account struct {
|
||
|
PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known.
|
||
|
Sequence int `json:"sequence"`
|
||
|
Balance Coins `json:"coins"`
|
||
|
}
|
||
|
|
||
|
type Coins []Coin
|
||
|
|
||
|
type Coin struct {
|
||
|
Denom string `json:"denom"`
|
||
|
Amount int64 `json:"amount"`
|
||
|
}
|
||
|
|
||
|
If you want to add more coins to a blockchain, you can do so manually in
|
||
|
the ``~/.basecoin/genesis.json`` before you start the blockchain for the
|
||
|
first time.
|
||
|
|
||
|
Accounts are serialized and stored in a Merkle tree under the key
|
||
|
``base/a/<address>``, where ``<address>`` is the address of the account.
|
||
|
Typically, the address of the account is the 20-byte ``RIPEMD160`` hash
|
||
|
of the public key, but other formats are acceptable as well, as defined
|
||
|
in the `Tendermint crypto
|
||
|
library <https://github.com/tendermint/go-crypto>`__. The Merkle tree
|
||
|
used in Basecoin is a balanced, binary search tree, which we call an
|
||
|
`IAVL tree <https://github.com/tendermint/iavl>`__.
|
||
|
|
||
|
Transactions
|
||
|
~~~~~~~~~~~~
|
||
|
|
||
|
Basecoin defines a transaction type, the ``SendTx``, which allows tokens
|
||
|
to be sent to other accounts. The ``SendTx`` takes a list of inputs and
|
||
|
a list of outputs, and transfers all the tokens listed in the inputs
|
||
|
from their corresponding accounts to the accounts listed in the output.
|
||
|
The ``SendTx`` is structured as follows:
|
||
|
|
||
|
::
|
||
|
|
||
|
type SendTx struct {
|
||
|
Gas int64 `json:"gas"`
|
||
|
Fee Coin `json:"fee"`
|
||
|
Inputs []TxInput `json:"inputs"`
|
||
|
Outputs []TxOutput `json:"outputs"`
|
||
|
}
|
||
|
|
||
|
type TxInput struct {
|
||
|
Address []byte `json:"address"` // Hash of the PubKey
|
||
|
Coins Coins `json:"coins"` //
|
||
|
Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput
|
||
|
Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
|
||
|
PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0
|
||
|
}
|
||
|
|
||
|
type TxOutput struct {
|
||
|
Address []byte `json:"address"` // Hash of the PubKey
|
||
|
Coins Coins `json:"coins"` //
|
||
|
}
|
||
|
|
||
|
Note the ``SendTx`` includes a field for ``Gas`` and ``Fee``. The
|
||
|
``Gas`` limits the total amount of computation that can be done by the
|
||
|
transaction, while the ``Fee`` refers to the total amount paid in fees.
|
||
|
This is slightly different from Ethereum's concept of ``Gas`` and
|
||
|
``GasPrice``, where ``Fee = Gas x GasPrice``. In Basecoin, the ``Gas``
|
||
|
and ``Fee`` are independent, and the ``GasPrice`` is implicit.
|
||
|
|
||
|
In Basecoin, the ``Fee`` is meant to be used by the validators to inform
|
||
|
the ordering of transactions, like in Bitcoin. And the ``Gas`` is meant
|
||
|
to be used by the application plugin to control its execution. There is
|
||
|
currently no means to pass ``Fee`` information to the Tendermint
|
||
|
validators, but it will come soon...
|
||
|
|
||
|
Note also that the ``PubKey`` only needs to be sent for
|
||
|
``Sequence == 0``. After that, it is stored under the account in the
|
||
|
Merkle tree and subsequent transactions can exclude it, using only the
|
||
|
``Address`` to refer to the sender. Ethereum does not require public
|
||
|
keys to be sent in transactions as it uses a different elliptic curve
|
||
|
scheme which enables the public key to be derived from the signature
|
||
|
itself.
|
||
|
|
||
|
Finally, note that the use of multiple inputs and multiple outputs
|
||
|
allows us to send many different types of tokens between many different
|
||
|
accounts at once in an atomic transaction. Thus, the ``SendTx`` can
|
||
|
serve as a basic unit of decentralized exchange. When using multiple
|
||
|
inputs and outputs, you must make sure that the sum of coins of the
|
||
|
inputs equals the sum of coins of the outputs (no creating money), and
|
||
|
that all accounts that provide inputs have signed the transaction.
|
||
|
|
||
|
Clean Up
|
||
|
--------
|
||
|
|
||
|
**WARNING:** Running these commands will wipe out any existing
|
||
|
information in both the ``~/.basecli`` and ``~/.basecoin`` directories,
|
||
|
including private keys.
|
||
|
|
||
|
To remove all the files created and refresh your environment (e.g., if
|
||
|
starting this tutorial again or trying something new), the following
|
||
|
commands are run:
|
||
|
|
||
|
::
|
||
|
|
||
|
basecli reset_all
|
||
|
rm -rf ~/.basecoin
|
||
|
|
||
|
In this guide, we introduced the ``basecoin`` and ``basecli`` tools,
|
||
|
demonstrated how to start a new basecoin blockchain and how to send
|
||
|
tokens between accounts, and discussed the underlying data types for
|
||
|
accounts and transactions, specifically the ``Account`` and the
|
||
|
``SendTx``.
|