docs cleanup
This commit is contained in:
committed by
Zach Ramsay
parent
1b9afdab48
commit
266ea5ce82
@@ -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``.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user