docs: remove reference to middleware/isolation

This commit is contained in:
Zach Ramsay 2018-02-02 20:28:47 +00:00 committed by Ethan Buchman
parent 5ed30b2a62
commit b655d902de
3 changed files with 832 additions and 20 deletions

View File

@ -44,8 +44,7 @@ Context (ctx)
-------------
As a request passes through the system, it may pick up information such
as the authorization it has received from another middleware, or the
block height the request runs at. In order to carry this information
as the block height the request runs at. In order to carry this information
between modules it is saved to the context. Further, all information
must be deterministic from the context in which the request runs (based
on the transaction and the block it was included in) and can be used to
@ -90,18 +89,18 @@ separate module.
The second is to add permissions to the transaction context. The
transaction context can specify that the tx has been signed by one or
multiple specific
`actors <https://github.com/tendermint/basecoin/blob/unstable/context.go#L18>`__.
multiple specific actors.
A transactions will only be executed if the permission requirements have
been fulfilled. For example the sender of funds must have signed, or 2
out of 3 multi-signature actors must have signed a joint account. To
prevent the forgery of account signatures from unintended modules each
permission is associated with the module that granted it (in this case
`auth <https://github.com/cosmos/cosmos-sdk/tree/master/modules/auth>`__),
`auth <https://github.com/cosmos/cosmos-sdk/tree/master/x/auth>`__),
and if a module tries to add a permission for another module, it will
panic. There is also protection if a module creates a brand new fake
context to trick the downstream modules. Each context enforces the rules
on how to make child contexts, and the stack middleware builder enforces
on how to make child contexts, and the stack builder enforces
that the context passed from one level to the next is a valid child of
the original one.
@ -152,7 +151,7 @@ the super minimal
`negroni <https://github.com/urfave/negroni/blob/master/README.md>`__
package, we just provide one more ``Middleware`` interface, which has an
extra ``next`` parameter, and a ``Stack`` that can wire all the levels
together (which also gives us a place to perform isolation of each
together (which also gives us a place to perform seperation of each
step).
.. code:: golang
@ -165,6 +164,8 @@ step).
Modules
-------
TODO: update (s/Modules/handlers+mappers+stores/g) & add Msg + Tx (a signed message)
A module is a set of functionality which should be typically designed as
self-sufficient. Common elements of a module are:
@ -172,13 +173,6 @@ self-sufficient. Common elements of a module are:
- custom error codes
- data models (to persist in the kv-store)
- handler (to handle any end transactions)
- middleware (to handler any wrapper transactions)
To enable a module, you must add the appropriate middleware (if any) to
the stack in ``main.go`` for the client application (default:
``basecli/main.go``), as well as adding the handler (if any) to the
dispatcher (default: ``app/app.go``). Once the stack is compiled into a
``Handler``, then each transaction is handled by the appropriate module.
Dispatcher
----------
@ -189,7 +183,7 @@ have ``coin`` sending money, ``roles`` to create multi-sig accounts, and
``ibc`` for following other chains all working together without
interference.
After the chain of middleware, we can register a ``Dispatcher``, which
We can then register a ``Dispatcher``, which
also implements the ``Handler`` interface. We then register a list of
modules with the dispatcher. Every module has a unique ``Name()``, which
is used for isolating its state space. We use this same name for routing
@ -300,8 +294,3 @@ and charge a fee. Within the SDK this can be achieved using separate
modules in a stack, one to send the coins and the other to charge the
fee, however both modules do not need to check the nonce. This can occur
as a separate module earlier in the stack.
IBC (Inter-Blockchain Communication)
------------------------------------
Stay tuned!

424
docs/ibc.rst Normal file
View File

@ -0,0 +1,424 @@
InterBlockchain Communication with the Cosmos SDK
=================================================
TODO: update in light of latest SDK (this document is currently out of date)
One of the most exciting elements of the Cosmos Network is the
InterBlockchain Communication (IBC) protocol, which enables
interoperability across different blockchains. We implemented IBC as a
basecoin plugin, and we'll show you how to use it to send tokens across
blockchains!
Please note: this tutorial assumes familiarity with the Cosmos SDK.
The IBC plugin defines a new set of transactions as subtypes of the
``AppTx``. The plugin's functionality is accessed by setting the
``AppTx.Name`` field to ``"IBC"``, and setting the ``Data`` field to the
serialized IBC transaction type.
We'll demonstrate exactly how this works below.
IBC
---
Let's review the IBC protocol. The purpose of IBC is to enable one
blockchain to function as a light-client of another. Since we are using
a classical Byzantine Fault Tolerant consensus algorithm, light-client
verification is cheap and easy: all we have to do is check validator
signatures on the latest block, and verify a Merkle proof of the state.
In Tendermint, validators agree on a block before processing it. This
means that the signatures and state root for that block aren't included
until the next block. Thus, each block contains a field called
``LastCommit``, which contains the votes responsible for committing the
previous block, and a field in the block header called ``AppHash``,
which refers to the Merkle root hash of the application after processing
the transactions from the previous block. So, if we want to verify the
``AppHash`` from height H, we need the signatures from ``LastCommit`` at
height H+1. (And remember that this ``AppHash`` only contains the
results from all transactions up to and including block H-1)
Unlike Proof-of-Work, the light-client protocol does not need to
download and check all the headers in the blockchain - the client can
always jump straight to the latest header available, so long as the
validator set has not changed much. If the validator set is changing,
the client needs to track these changes, which requires downloading
headers for each block in which there is a significant change. Here, we
will assume the validator set is constant, and postpone handling
validator set changes for another time.
Now we can describe exactly how IBC works. Suppose we have two
blockchains, ``chain1`` and ``chain2``, and we want to send some data
from ``chain1`` to ``chain2``. We need to do the following: 1. Register
the details (ie. chain ID and genesis configuration) of ``chain1`` on
``chain2`` 2. Within ``chain1``, broadcast a transaction that creates an
outgoing IBC packet destined for ``chain2`` 3. Broadcast a transaction
to ``chain2`` informing it of the latest state (ie. header and commit
signatures) of ``chain1`` 4. Post the outgoing packet from ``chain1`` to
``chain2``, including the proof that it was indeed committed on
``chain1``. Note ``chain2`` can only verify this proof because it has a
recent header and commit.
Each of these steps involves a separate IBC transaction type. Let's take
them up in turn.
IBCRegisterChainTx
~~~~~~~~~~~~~~~~~~
The ``IBCRegisterChainTx`` is used to register one chain on another. It
contains the chain ID and genesis configuration of the chain to
register:
.. code:: golang
type IBCRegisterChainTx struct { BlockchainGenesis }
type BlockchainGenesis struct { ChainID string Genesis string }
This transaction should only be sent once for a given chain ID, and
successive sends will return an error.
IBCUpdateChainTx
~~~~~~~~~~~~~~~~
The ``IBCUpdateChainTx`` is used to update the state of one chain on
another. It contains the header and commit signatures for some block in
the chain:
.. code:: golang
type IBCUpdateChainTx struct {
Header tm.Header
Commit tm.Commit
}
In the future, it needs to be updated to include changes to the
validator set as well. Anyone can relay an ``IBCUpdateChainTx``, and
they only need to do so as frequently as packets are being sent or the
validator set is changing.
IBCPacketCreateTx
~~~~~~~~~~~~~~~~~
The ``IBCPacketCreateTx`` is used to create an outgoing packet on one
chain. The packet itself contains the source and destination chain IDs,
a sequence number (i.e. an integer that increments with every message
sent between this pair of chains), a packet type (e.g. coin, data,
etc.), and a payload.
.. code:: golang
type IBCPacketCreateTx struct {
Packet
}
type Packet struct {
SrcChainID string
DstChainID string
Sequence uint64
Type string
Payload []byte
}
We have yet to define the format for the payload, so, for now, it's just
arbitrary bytes.
One way to think about this is that ``chain2`` has an account on
``chain1``. With a ``IBCPacketCreateTx`` on ``chain1``, we send funds to
that account. Then we can prove to ``chain2`` that there are funds
locked up for it in it's account on ``chain1``. Those funds can only be
unlocked with corresponding IBC messages back from ``chain2`` to
``chain1`` sending the locked funds to another account on ``chain1``.
IBCPacketPostTx
~~~~~~~~~~~~~~~
The ``IBCPacketPostTx`` is used to post an outgoing packet from one
chain to another. It contains the packet and a proof that the packet was
committed into the state of the sending chain:
.. code:: golang
type IBCPacketPostTx struct {
FromChainID string // The immediate source of the packet, not always Packet.SrcChainID
FromChainHeight uint64 // The block height in which Packet was committed, to check Proof Packet
Proof *merkle.IAVLProof
}
The proof is a Merkle proof in an IAVL tree, our implementation of a
balanced, Merklized binary search tree. It contains a list of nodes in
the tree, which can be hashed together to get the Merkle root hash. This
hash must match the ``AppHash`` contained in the header at
``FromChainHeight + 1``
- note the ``+ 1`` is necessary since ``FromChainHeight`` is the height
in which the packet was committed, and the resulting state root is
not included until the next block.
IBC State
~~~~~~~~~
Now that we've seen all the transaction types, let's talk about the
state. Each chain stores some IBC state in its Merkle tree. For each
chain being tracked by our chain, we store:
- Genesis configuration
- Latest state
- Headers for recent heights
We also store all incoming (ingress) and outgoing (egress) packets.
The state of a chain is updated every time an ``IBCUpdateChainTx`` is
committed. New packets are added to the egress state upon
``IBCPacketCreateTx``. New packets are added to the ingress state upon
``IBCPacketPostTx``, assuming the proof checks out.
Merkle Queries
--------------
The Basecoin application uses a single Merkle tree that is shared across
all its state, including the built-in accounts state and all plugin
state. For this reason, it's important to use explicit key names and/or
hashes to ensure there are no collisions.
We can query the Merkle tree using the ABCI Query method. If we pass in
the correct key, it will return the corresponding value, as well as a
proof that 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, we
can run a relay node that handles the cross-chain interaction.
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 tutorial.
Make sure you have installed `basecoin and
basecli </docs/guide/install.md>`__.
Basecoin is a framework for creating new cryptocurrency applications. It
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.
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....
Preliminaries
~~~~~~~~~~~~~
::
# first, clean up any old garbage for a fresh slate...
rm -rf ~/.ibcdemo/
Let's start by setting up some environment variables and aliases:
::
export BCHOME1_CLIENT=~/.ibcdemo/chain1/client
export BCHOME1_SERVER=~/.ibcdemo/chain1/server
export BCHOME2_CLIENT=~/.ibcdemo/chain2/client
export BCHOME2_SERVER=~/.ibcdemo/chain2/server
alias basecli1="basecli --home $BCHOME1_CLIENT"
alias basecli2="basecli --home $BCHOME2_CLIENT"
alias basecoin1="basecoin --home $BCHOME1_SERVER"
alias basecoin2="basecoin --home $BCHOME2_SERVER"
This will give us some new commands to use instead of raw ``basecli``
and ``basecoin`` to ensure we're using the right configuration for the
chain we want to talk to.
We also want to set some chain IDs:
::
export CHAINID1="test-chain-1"
export CHAINID2="test-chain-2"
And since we will run two different chains on one machine, we need to
maintain different sets of ports:
::
export PORT_PREFIX1=1234
export PORT_PREFIX2=2345
export RPC_PORT1=${PORT_PREFIX1}7
export RPC_PORT2=${PORT_PREFIX2}7
Setup Chain 1
~~~~~~~~~~~~~
Now, let's create some keys that we can use for accounts on
test-chain-1:
::
basecli1 keys new money
basecli1 keys new gotnone
export MONEY=$(basecli1 keys get money | awk '{print $2}')
export GOTNONE=$(basecli1 keys get gotnone | awk '{print $2}')
and create an initial configuration giving lots of coins to the $MONEY
key:
::
basecoin1 init --chain-id $CHAINID1 $MONEY
Now start basecoin:
::
sed -ie "s/4665/$PORT_PREFIX1/" $BCHOME1_SERVER/config.toml
basecoin1 start &> basecoin1.log &
Note the ``sed`` command to replace the ports in the config file. You
can follow the logs with ``tail -f basecoin1.log``
Now we can attach the client to the chain and verify the state. The
first account should have money, the second none:
::
basecli1 init --node=tcp://localhost:${RPC_PORT1} --genesis=${BCHOME1_SERVER}/genesis.json
basecli1 query account $MONEY
basecli1 query account $GOTNONE
Setup Chain 2
~~~~~~~~~~~~~
This is the same as above, except with ``basecli2``, ``basecoin2``, and
``$CHAINID2``. We will also need to change the ports, since we're
running another chain on the same local machine.
Let's create new keys for test-chain-2:
::
basecli2 keys new moremoney
basecli2 keys new broke
MOREMONEY=$(basecli2 keys get moremoney | awk '{print $2}')
BROKE=$(basecli2 keys get broke | awk '{print $2}')
And prepare the genesis block, and start the server:
::
basecoin2 init --chain-id $CHAINID2 $(basecli2 keys get moremoney | awk '{print $2}')
sed -ie "s/4665/$PORT_PREFIX2/" $BCHOME2_SERVER/config.toml
basecoin2 start &> basecoin2.log &
Now attach the client to the chain and verify the state. The first
account should have money, the second none:
::
basecli2 init --node=tcp://localhost:${RPC_PORT2} --genesis=${BCHOME2_SERVER}/genesis.json
basecli2 query account $MOREMONEY
basecli2 query account $BROKE
Connect these chains
~~~~~~~~~~~~~~~~~~~~
OK! So we have two chains running on your local machine, with different
keys on each. Let's hook them up together by starting a relay process to
forward messages from one chain to the other.
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.
::
# note that this key.json file is a hardcoded demo for all chains, this will
# be updated in a future release
RELAY_KEY=$BCHOME1_SERVER/key.json
RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \")
basecli1 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR--name=money
basecli1 query account $RELAY_ADDR
basecli2 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney
basecli2 query account $RELAY_ADDR
Now we can start the relay process.
::
basecoin relay init --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \
--chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \
--genesis1=${BCHOME1_SERVER}/genesis.json --genesis2=${BCHOME2_SERVER}/genesis.json \
--from=$RELAY_KEY
basecoin relay start --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \
--chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \
--from=$RELAY_KEY &> relay.log &
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...
Sending cross-chain payments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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...
::
# Here's an empty account on test-chain-2
basecli2 query account $BROKE
::
# Let's send some funds from test-chain-1
basecli1 tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$BROKE --name=money
::
# give it time to arrive...
sleep 2
# now you should see 12345 coins!
basecli2 query account $BROKE
You're no longer broke! Cool, huh? Now have fun exploring and sending
coins across the chains. And making more accounts as you want to.
Conclusion
----------
In this tutorial we explained how IBC works, and demonstrated how to use
it to communicate between two chains. We did the simplest communciation
possible: a one way transfer of data from chain1 to chain2. The most
important part was that we updated chain2 with the latest state (i.e.
header and commit) of chain1, and then were able to post a proof to
chain2 that a packet was committed to the outgoing state of chain1.
In a future tutorial, we will demonstrate how to use IBC to actually
transfer tokens between two blockchains, but we'll do it with real
testnets deployed across multiple nodes on the network. Stay tuned!

399
docs/sdk/overview.rst Normal file
View File

@ -0,0 +1,399 @@
SDK Overview
============
The SDK design optimizes flexibility and security. The
framework is designed around a modular execution stack which allows
applications to mix and match modular elements as desired. In addition,
all modules are sandboxed for greater application security.
Framework Overview
------------------
### Object-Capability Model
When thinking about security, it's good to start with a specific threat model. Our threat model is the following:
> We want to assume a thriving ecosystem of Cosmos-SDK modules that are easy to compose into a blockchain application. Some of these modules will be faulty or malicious.
The Cosmos-SDK is designed to address this threat by being the foundation of an object capability system.
```
The structural properties of object capability systems favor
modularity in code design and ensure reliable encapsulation in
code implementation.
These structural properties facilitate the analysis of some
security properties of an object-capability program or operating
system. Some of these — in particular, information flow properties
— can be analyzed at the level of object references and
connectivity, independent of any knowledge or analysis of the code
that determines the behavior of the objects. As a consequence,
these security properties can be established and maintained in the
presence of new objects that contain unknown and possibly
malicious code.
These structural properties stem from the two rules governing
access to existing objects:
1) An object A can send a message to B only if object A holds a
reference to B.
2) An object A can obtain a reference to C only
if object A receives a message containing a reference to C. As a
consequence of these two rules, an object can obtain a reference
to another object only through a preexisting chain of references.
In short, "Only connectivity begets connectivity."
- https://en.wikipedia.org/wiki/Object-capability_model
```
Strictly speaking, Golang does not implement object capabilities completely, because of several issues:
* pervasive ability to import primitive modules (e.g. "unsafe", "os")
* pervasive ability to override module vars https://github.com/golang/go/issues/23161
* data-race vulnerability where 2+ goroutines can create illegal interface values
The first is easy to catch by auditing imports and using a proper dependency version control system like Glide. The second and third are unfortunate but it can be audited with some cost.
Perhaps [Go2 will implement the object capability model](https://github.com/golang/go/issues/23157).
### What does it look like?
Only reveal what is necessary to get the work done.
For example, the following code snippet violates the object capabilities principle:
```golang
type AppAccount struct {...}
var account := &AppAccount{
Address: pub.Address(),
Coins: sdk.Coins{{"ATM", 100}},
}
var sumValue := externalModule.ComputeSumValue(account)
```
The method "ComputeSumValue" implies a pure function, yet the implied capability of accepting a pointer value is the capability to modify that value. The preferred method signature should take a copy instead.
```golang
var sumValue := externalModule.ComputeSumValue(*account)
```
In the Cosmos SDK, you can see the application of this principle in the basecoin examples folder.
```golang
// File: cosmos-sdk/examples/basecoin/app/init_handlers.go
package app
import (
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/sketchy"
)
func (app *BasecoinApp) initRouterHandlers() {
// All handlers must be added here.
// The order matters.
app.router.AddRoute("bank", bank.NewHandler(app.accountMapper))
app.router.AddRoute("sketchy", sketchy.NewHandler())
}
```
In the Basecoin example, the sketchy handler isn't provided an account mapper, which does provide the bank handler with the capability (in conjunction with the context of a transaction run).
Security Overview
-----------------
If you want to see some examples, take a look at the [examples/basecoin](/examples/basecoin) directory.
## Design Goals
The design of the Cosmos SDK is based on the principles of "capabilities systems".
## Capabilities systems
### Need for module isolation
### Capability is implied permission
### TODO Link to thesis
## Tx & Msg
The SDK distinguishes between transactions (Tx) and messages
(Msg). A Tx is a Msg wrapped with authentication and fee data.
### Messages
Users can create messages containing arbitrary information by
implementing the `Msg` interface:
```golang
type Msg interface {
// Return the message type.
// Must be alphanumeric or empty.
Type() string
// Get some property of the Msg.
Get(key interface{}) (value interface{})
// Get the canonical byte representation of the Msg.
GetSignBytes() []byte
// ValidateBasic does a simple validation check that
// doesn't require access to any other information.
ValidateBasic() error
// Signers returns the addrs of signers that must sign.
// CONTRACT: All signatures must be present to be valid.
// CONTRACT: Returns addrs in some deterministic order.
GetSigners() []crypto.Address
}
```
Messages must specify their type via the `Type()` method. The type should
correspond to the messages handler, so there can be many messages with the same
type.
Messages must also specify how they are to be authenticated. The `GetSigners()`
method return a list of addresses that must sign the message, while the
`GetSignBytes()` method returns the bytes that must be signed for a signature
to be valid.
Addresses in the SDK are arbitrary byte arrays that are hex-encoded when
displayed as a string or rendered in JSON.
Messages can specify basic self-consistency checks using the `ValidateBasic()`
method to enforce that message contents are well formed before any actual logic
begins.
Finally, messages can provide generic access to their contents via `Get(key)`,
but this is mostly for convenience and not type-safe.
For instance, the `Basecoin` message types are defined in `x/bank/tx.go`:
```golang
type SendMsg struct {
Inputs []Input `json:"inputs"`
Outputs []Output `json:"outputs"`
}
type IssueMsg struct {
Banker crypto.Address `json:"banker"`
Outputs []Output `json:"outputs"`
}
```
Each specifies the addresses that must sign the message:
```golang
func (msg SendMsg) GetSigners() []crypto.Address {
addrs := make([]crypto.Address, len(msg.Inputs))
for i, in := range msg.Inputs {
addrs[i] = in.Address
}
return addrs
}
func (msg IssueMsg) GetSigners() []crypto.Address {
return []crypto.Address{msg.Banker}
}
```
### Transactions
A transaction is a message with additional information for authentication:
```golang
type Tx interface {
GetMsg() Msg
// The address that pays the base fee for this message. The fee is
// deducted before the Msg is processed.
GetFeePayer() crypto.Address
// Get the canonical byte representation of the Tx.
// Includes any signatures (or empty slots).
GetTxBytes() []byte
// Signatures returns the signature of signers who signed the Msg.
// CONTRACT: Length returned is same as length of
// pubkeys returned from MsgKeySigners, and the order
// matches.
// CONTRACT: If the signature is missing (ie the Msg is
// invalid), then the corresponding signature is
// .Empty().
GetSignatures() []StdSignature
}
```
The `tx.GetSignatures()` method returns a list of signatures, which must match
the list of addresses returned by `tx.Msg.GetSigners()`. The signatures come in
a standard form:
```golang
type StdSignature struct {
crypto.PubKey // optional
crypto.Signature
Sequence int64
}
```
It contains the signature itself, as well as the corresponding account's
sequence number. The sequence number is expected to increment every time a
message is signed by a given account. This prevents "replay attacks", where
the same message could be executed over and over again.
The `StdSignature` can also optionally include the public key for verifying the
signature. An application can store the public key for each address it knows
about, making it optional to include the public key in the transaction. In the
case of Basecoin, the public key only needs to be included in the first
transaction send by a given account - after that, the public key is forever
stored by the application and can be left out of transactions.
Transactions can also specify the address responsible for paying the
transaction's fees using the `tx.GetFeePayer()` method.
The standard way to create a transaction from a message is to use the `StdTx`:
```golang
type StdTx struct {
Msg
Signatures []StdSignature
}
```
### Encoding and Decoding Transactions
Messages and transactions are designed to be generic enough for developers to
specify their own encoding schemes. This enables the SDK to be used as the
framwork for constructing already specified cryptocurrency state machines, for
instance Ethereum.
When initializing an application, a developer must specify a `TxDecoder`
function which determines how an arbitrary byte array should be unmarshalled
into a `Tx`:
```golang
type TxDecoder func(txBytes []byte) (Tx, error)
```
In `Basecoin`, we use the Tendermint wire format and the `go-wire` library for
encoding and decoding all message types. The `go-wire` library has the nice
property that it can unmarshal into interface types, but it requires the
relevant types to be registered ahead of type. Registration happens on a
`Codec` object, so as not to taint the global name space.
For instance, in `Basecoin`, we wish to register the `SendMsg` and `IssueMsg`
types:
```golang
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
cdc.RegisterConcrete(bank.SendMsg{}, "cosmos-sdk/SendMsg", nil)
cdc.RegisterConcrete(bank.IssueMsg{}, "cosmos-sdk/IssueMsg", nil)
```
Note how each concrete type is given a name - these name determine the type's
unique "prefix bytes" during encoding. A registered type will always use the
same prefix-bytes, regardless of what interface it is satisfying. For more
details, see the [go-wire documentation](https://github.com/tendermint/go-wire/blob/develop).
## MultiStore
### MultiStore is like a filesystem
### Mounting an IAVLStore
```
TODO:
- IAVLStore: Fast balanced dynamic Merkle store.
- supports iteration.
- MultiStore: multiple Merkle tree backends in a single store
- allows using Ethereum Patricia Trie and Tendermint IAVL in same app
- Provide caching for intermediate state during execution of blocks and transactions (including for iteration)
- Historical state pruning and snapshotting.
- Query proofs (existence, absence, range, etc.) on current and retained historical state.
```
## Context
The SDK uses a `Context` to propogate common information across functions. The
`Context` is modelled after the Golang `context.Context` object, which has
become ubiquitous in networking middleware and routing applications as a means
to easily propogate request context through handler functions.
The main information stored in the `Context` includes the application
MultiStore (see below), the last block header, and the transaction bytes.
Effectively, the context contains all data that may be necessary for processing
a transaction.
Many methods on SDK objects receive a context as the first argument.
## Handler
Transaction processing in the SDK is defined through `Handler` functions:
```golang
type Handler func(ctx Context, tx Tx) Result
```
A handler takes a context and a transaction and returns a result. All
information necessary for processing a transaction should be available in the
context.
While the context holds the entire application state (all referenced from the
root MultiStore), a particular handler only needs a particular kind of access
to a particular store (or two or more). Access to stores is managed using
capabilities keys and mappers. When a handler is initialized, it is passed a
key or mapper that gives it access to the relevant stores.
```golang
// File: cosmos-sdk/examples/basecoin/app/init_stores.go
app.BaseApp.MountStore(app.capKeyMainStore, sdk.StoreTypeIAVL)
app.accountMapper = auth.NewAccountMapper(
app.capKeyMainStore, // target store
&types.AppAccount{}, // prototype
)
// File: cosmos-sdk/examples/basecoin/app/init_handlers.go
app.router.AddRoute("bank", bank.NewHandler(app.accountMapper))
// File: cosmos-sdk/x/bank/handler.go
// NOTE: Technically, NewHandler only needs a CoinMapper
func NewHandler(am sdk.AccountMapper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
cm := CoinMapper{am}
...
}
}
```
## AnteHandler
### Handling Fee payment
### Handling Authentication
## Accounts and x/auth
### sdk.Account
### auth.BaseAccount
### auth.AccountMapper
## Wire codec
### Why another codec?
### vs encoding/json
### vs protobuf
## Dummy example
## Basecoin example
The quintessential SDK application is Basecoin - a simple
multi-asset cryptocurrency. Basecoin consists of a set of
accounts stored in a Merkle tree, where each account may have
many coins. There are two message types: SendMsg and IssueMsg.
SendMsg allows coins to be sent around, while IssueMsg allows a
set of predefined users to issue new coins.
## Conclusion