docs cleanup

This commit is contained in:
Ethan Buchman
2018-04-19 12:03:17 -04:00
committed by Zach Ramsay
parent 1b9afdab48
commit 266ea5ce82
11 changed files with 7 additions and 12 deletions
+289
View File
@@ -0,0 +1,289 @@
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``.
+215
View File
@@ -0,0 +1,215 @@
Basecoin Extensions
===================
TODO: re-write for extensions
In the `previous guide <basecoin-basics.md>`__, we saw how to use the
``basecoin`` tool to start a blockchain and the ``basecli`` tools to
send transactions. We also learned about ``Account`` and ``SendTx``, the
basic data types giving us a multi-asset cryptocurrency. Here, we will
demonstrate how to extend the tools to use another transaction type, the
``AppTx``, so we can send data to a custom plugin. In this example we
explore a simple plugin named ``counter``.
Example Plugin
--------------
The design of the ``basecoin`` tool makes it easy to extend for custom
functionality. The Counter plugin is bundled with basecoin, so if you
have already `installed basecoin <install.md>`__ and run
``make install`` then you should be able to run a full node with
``counter`` and the a light-client ``countercli`` from terminal. The
Counter plugin is just like the ``basecoin`` tool. They both use the
same library of commands, including one for signing and broadcasting
``SendTx``.
Counter transactions take two custom inputs, a boolean argument named
``valid``, and a coin amount named ``countfee``. The transaction is only
accepted if both ``valid`` is set to true and the transaction input
coins is greater than ``countfee`` that the user provides.
A new blockchain can be initialized and started just like in the
`previous guide <basecoin-basics.md>`__:
::
# WARNING: this wipes out data - but counter is only for demos...
rm -rf ~/.counter
countercli reset_all
countercli keys new cool
countercli keys new friend
counter init $(countercli keys get cool | awk '{print $2}')
counter start
The default files are stored in ``~/.counter``. In another window we can
initialize the light-client and send a transaction:
::
countercli init --node=tcp://localhost:46657 --genesis=$HOME/.counter/genesis.json
YOU=$(countercli keys get friend | awk '{print $2}')
countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1
But the Counter has an additional command, ``countercli tx counter``,
which crafts an ``AppTx`` specifically for this plugin:
::
countercli tx counter --name cool
countercli tx counter --name cool --valid
The first transaction is rejected by the plugin because it was not
marked as valid, while the second transaction passes. We can build
plugins that take many arguments of different types, and easily extend
the tool to accomodate them. Of course, we can also expose queries on
our plugin:
::
countercli query counter
Tada! We can now see that our custom counter plugin transactions went
through. You should see a Counter value of 1 representing the number of
valid transactions. If we send another transaction, and then query
again, we will see the value increment. Note that we need the sequence
number here to send the coins (it didn't increment when we just pinged
the counter)
::
countercli tx counter --name cool --countfee=2mycoin --sequence=2 --valid
countercli query counter
The Counter value should be 2, because we sent a second valid
transaction. And this time, since we sent a countfee (which must be less
than or equal to the total amount sent with the tx), it stores the
``TotalFees`` on the counter as well.
Keep it mind that, just like with ``basecli``, the ``countercli``
verifies a proof that the query response is correct and up-to-date.
Now, before we implement our own plugin and tooling, it helps to
understand the ``AppTx`` and the design of the plugin system.
AppTx
-----
The ``AppTx`` is similar to the ``SendTx``, but instead of sending coins
from inputs to outputs, it sends coins from one input to a plugin, and
can also send some data.
::
type AppTx struct {
Gas int64 `json:"gas"`
Fee Coin `json:"fee"`
Input TxInput `json:"input"`
Name string `json:"type"` // Name of the plugin
Data []byte `json:"data"` // Data for the plugin to process
}
The ``AppTx`` enables Basecoin to be extended with arbitrary additional
functionality through the use of plugins. The ``Name`` field in the
``AppTx`` refers to the particular plugin which should process the
transaction, and the ``Data`` field of the ``AppTx`` is the data to be
forwarded to the plugin for processing.
Note the ``AppTx`` also has a ``Gas`` and ``Fee``, with the same meaning
as for the ``SendTx``. It also includes a single ``TxInput``, which
specifies the sender of the transaction, and some coins that can be
forwarded to the plugin as well.
Plugins
-------
A plugin is simply a Go package that implements the ``Plugin``
interface:
::
type Plugin interface {
// Name of this plugin, should be short.
Name() string
// Run a transaction from ABCI DeliverTx
RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result)
// Other ABCI message handlers
SetOption(store KVStore, key string, value string) (log string)
InitChain(store KVStore, vals []*abci.Validator)
BeginBlock(store KVStore, hash []byte, header *abci.Header)
EndBlock(store KVStore, height uint64) (res abci.ResponseEndBlock)
}
type CallContext struct {
CallerAddress []byte // Caller's Address (hash of PubKey)
CallerAccount *Account // Caller's Account, w/ fee & TxInputs deducted
Coins Coins // The coins that the caller wishes to spend, excluding fees
}
The workhorse of the plugin is ``RunTx``, which is called when an
``AppTx`` is processed. The ``Data`` from the ``AppTx`` is passed in as
the ``txBytes``, while the ``Input`` from the ``AppTx`` is used to
populate the ``CallContext``.
Note that ``RunTx`` also takes a ``KVStore`` - this is an abstraction
for the underlying Merkle tree which stores the account data. By passing
this to the plugin, we enable plugins to update accounts in the Basecoin
state directly, and also to store arbitrary other information in the
state. In this way, the functionality and state of a Basecoin-derived
cryptocurrency can be greatly extended. One could imagine going so far
as to implement the Ethereum Virtual Machine as a plugin!
For details on how to initialize the state using ``SetOption``, see the
`guide to using the basecoin tool <basecoin-tool.md#genesis>`__.
Implement your own
------------------
To implement your own plugin and tooling, make a copy of
``docs/guide/counter``, and modify the code accordingly. Here, we will
briefly describe the design and the changes to be made, but see the code
for more details.
First is the ``cmd/counter/main.go``, which drives the program. It can
be left alone, but you should change any occurrences of ``counter`` to
whatever your plugin tool is going to be called. You must also register
your plugin(s) with the basecoin app with ``RegisterStartPlugin``.
The light-client is located in ``cmd/countercli/main.go`` and allows for
transaction and query commands. This file can also be left mostly alone
besides replacing the application name and adding references to new
plugin commands.
Next is the custom commands in ``cmd/countercli/commands/``. These files
are where we extend the tool with any new commands and flags we need to
send transactions or queries to our plugin. You define custom ``tx`` and
``query`` subcommands, which are registered in ``main.go`` (avoiding
``init()`` auto-registration, for less magic and more control in the
main executable).
Finally is ``plugins/counter/counter.go``, where we provide an
implementation of the ``Plugin`` interface. The most important part of
the implementation is the ``RunTx`` method, which determines the meaning
of the data sent along in the ``AppTx``. In our example, we define a new
transaction type, the ``CounterTx``, which we expect to be encoded in
the ``AppTx.Data``, and thus to be decoded in the ``RunTx`` method, and
used to update the plugin state.
For more examples and inspiration, see our `repository of example
plugins <https://github.com/tendermint/basecoin-examples>`__.
Conclusion
----------
In this guide, we demonstrated how to create a new plugin and how to
extend the ``basecoin`` tool to start a blockchain with the plugin
enabled and send transactions to it. In the next guide, we introduce a
`plugin for Inter Blockchain Communication <ibc.md>`__, which allows us
to publish proofs of the state of one blockchain to another, and thus to
transfer tokens and data between them.