335 lines
15 KiB
ReStructuredText
335 lines
15 KiB
ReStructuredText
Glossary
|
|
========
|
|
|
|
This glossary defines many terms used throughout documentation of Quark.
|
|
If there is every a concept that seems unclear, check here. This is
|
|
mainly to provide a background and general understanding of the
|
|
different words and concepts that are used. Other documents will explain
|
|
in more detail how to combine these concepts to build a particular
|
|
application.
|
|
|
|
Transaction
|
|
-----------
|
|
|
|
A transaction is a packet of binary data that contains all information
|
|
to validate and perform an action on the blockchain. The only other data
|
|
that it interacts with is the current state of the chain (key-value
|
|
store), and it must have a deterministic action. The transaction is the
|
|
main piece of one request.
|
|
|
|
We currently make heavy use of
|
|
`go-wire <https://github.com/tendermint/go-wire>`__ and
|
|
`data <https://github.com/tendermint/go-wire/tree/master/data>`__ to
|
|
provide binary and json encodings and decodings for ``struct`` or
|
|
interface\ ``objects. Here, encoding and decoding operations are designed to operate with interfaces nested any amount times (like an onion!). There is one public``\ TxMapper\`
|
|
in the basecoin root package, and all modules can register their own
|
|
transaction types there. This allows us to deserialize the entire
|
|
transaction in one location (even with types defined in other repos), to
|
|
easily embed an arbitrary transaction inside another without specifying
|
|
the type, and provide an automatic json representation allowing for
|
|
users (or apps) to inspect the chain.
|
|
|
|
Note how we can wrap any other transaction, add a fee level, and not
|
|
worry about the encoding in our module any more?
|
|
|
|
.. code:: golang
|
|
|
|
type Fee struct {
|
|
Fee coin.Coin `json:"fee"`
|
|
Payer basecoin.Actor `json:"payer"` // the address who pays the fee
|
|
Tx basecoin.Tx `json:"tx"`
|
|
}
|
|
|
|
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
|
|
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
|
|
validate the transaction.
|
|
|
|
Data Store
|
|
----------
|
|
|
|
In order to provide proofs to Tendermint, we keep all data in one
|
|
key-value (kv) store which is indexed with a merkle tree. This allows
|
|
for the easy generation of a root hash and proofs for queries without
|
|
requiring complex logic inside each module. Standardization of this
|
|
process also allows powerful light-client tooling as any store data may
|
|
be verified on the fly.
|
|
|
|
The largest limitation of the current implemenation of the kv-store is
|
|
that interface that the application must use can only ``Get`` and
|
|
``Set`` single data points. That said, there are some data structures
|
|
like queues and range queries that are available in ``state`` package.
|
|
These provide higher-level functionality in a standard format, but have
|
|
not yet been integrated into the kv-store interface.
|
|
|
|
Isolation
|
|
---------
|
|
|
|
One of the main arguments for blockchain is security. So while we
|
|
encourage the use of third-party modules, all developers must be
|
|
vigilant against security holes. If you use the
|
|
`stack <https://github.com/cosmos/cosmos-sdk/tree/master/stack>`__
|
|
package, it will provide two different types of compartmentalization
|
|
security.
|
|
|
|
The first is to limit the working kv-store space of each module. When
|
|
``DeliverTx`` is called for a module, it is never given the entire data
|
|
store, but rather only its own prefixed subset of the store. This is
|
|
achieved by prefixing all keys transparently with
|
|
``<module name> + 0x0``, using the null byte as a separator. Since the
|
|
module name must be a string, no malicious naming scheme can ever lead
|
|
to a collision. Inside a module, we can write using any key value we
|
|
desire without the possibility that we have modified data belonging to
|
|
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>`__.
|
|
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>`__),
|
|
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
|
|
that the context passed from one level to the next is a valid child of
|
|
the original one.
|
|
|
|
These security measures ensure that modules can confidently write to
|
|
their local section of the database and trust the permissions associated
|
|
with the context, without concern of interference from other modules.
|
|
(Okay, if you see a bunch of C-code in the module traversing through all
|
|
the memory space of the application, then get worried....)
|
|
|
|
Handler
|
|
-------
|
|
|
|
The ABCI interface is handled by ``app``, which translates these data
|
|
structures into an internal format that is more convenient, but unable
|
|
to travel over the wire. The basic interface for any code that modifies
|
|
state is the ``Handler`` interface, which provides four methods:
|
|
|
|
.. code:: golang
|
|
|
|
Name() string
|
|
CheckTx(ctx Context, store state.KVStore, tx Tx) (Result, error)
|
|
DeliverTx(ctx Context, store state.KVStore, tx Tx) (Result, error)
|
|
SetOption(l log.Logger, store state.KVStore, module, key, value string) (string, error)
|
|
|
|
Note the ``Context``, ``KVStore``, and ``Tx`` as principal carriers of
|
|
information. And that Result is always success, and we have a second
|
|
error return for errors (which is much more standard golang that
|
|
``res.IsErr()``)
|
|
|
|
The ``Handler`` interface is designed to be the basis for all modules
|
|
that execute transactions, and this can provide a large degree of code
|
|
interoperability, much like ``http.Handler`` does in golang web
|
|
development.
|
|
|
|
Middleware
|
|
----------
|
|
|
|
Middleware is a series of processing steps that any request must travel
|
|
through before (and after) executing the registered ``Handler``. Some
|
|
examples are a logger (that records the time before executing the
|
|
transaction, then outputs info - including duration - after the
|
|
execution), of a signature checker (which unwraps the transaction by one
|
|
layer, verifies signatures, and adds the permissions to the Context
|
|
before passing the request along).
|
|
|
|
In keeping with the standardization of ``http.Handler`` and inspired by
|
|
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
|
|
step).
|
|
|
|
.. code:: golang
|
|
|
|
Name() string
|
|
CheckTx(ctx Context, store state.KVStore, tx Tx, next Checker) (Result, error)
|
|
DeliverTx(ctx Context, store state.KVStore, tx Tx, next Deliver) (Result, error)
|
|
SetOption(l log.Logger, store state.KVStore, module, key, value string, next Optioner) (string, error)
|
|
|
|
Modules
|
|
-------
|
|
|
|
A module is a set of functionality which should be typically designed as
|
|
self-sufficient. Common elements of a module are:
|
|
|
|
- transaction types (either end transactions, or transaction wrappers)
|
|
- 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
|
|
----------
|
|
|
|
We usually will want to have multiple modules working together, and need
|
|
to make sure the correct transactions get to the correct module. So we
|
|
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
|
|
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
|
|
transactions. Each transaction implementation must be registed with
|
|
go-wire via ``TxMapper``, so we just look at the registered name of this
|
|
transaction, which should be of the form ``<module name>/xxx``. The
|
|
dispatcher grabs the appropriate module name from the tx name and routes
|
|
it if the module is present.
|
|
|
|
This all seems like a bit of magic, but really we're just making use of
|
|
go-wire magic that we are already using, rather than add another layer.
|
|
For all the transactions to be properly routed, the only thing you need
|
|
to remember is to use the following pattern:
|
|
|
|
.. code:: golang
|
|
|
|
const (
|
|
NameCoin = "coin"
|
|
TypeSend = NameCoin + "/send"
|
|
)
|
|
|
|
Inter-Plugin Communication (IPC)
|
|
--------------------------------
|
|
|
|
But wait, there's more... since we have isolated all the modules from
|
|
each other, we need to allow some way for them to interact in a
|
|
controlled fashion. One example is the ``fee`` middleware, which wants
|
|
to deduct coins from the calling account and can be accomplished most
|
|
easily with the ``coin`` module.
|
|
|
|
To make a call from the middleware, we the ``next`` Handler, which will
|
|
execute the rest of the stack. It can create a new SendTx and pass it
|
|
down the stack. If it returns success, do the rest of the processing
|
|
(and send the original transaction down the stack), otherwise abort.
|
|
|
|
However, if one ``Handler`` inside the ``Dispatcher`` wants to do this,
|
|
it becomes more complex. The solution is that the ``Dispatcher`` accepts
|
|
not a ``Handler``, but a ``Dispatchable``, which looks like a
|
|
middleware, except that the ``next`` argument is a callback to the
|
|
dispatcher to execute a sub-transaction. If a module doesn't want to use
|
|
this functionality, it can just implement ``Handler`` and call
|
|
``stack.WrapHandler(h)`` to convert it to a ``Dispatchable`` that never
|
|
uses the callback.
|
|
|
|
One example of this is the counter app, which can optionally accept a
|
|
payment. If the transaction contains a payment, it must create a SendTx
|
|
and pass this to the dispatcher to deduct the amount from the proper
|
|
account. Take a look at `counter
|
|
plugin <https://github.com/cosmos/cosmos-sdk/blob/master/docs/guide/counter/plugins/counter/counter.go>`__\ for
|
|
a better idea.
|
|
|
|
Permissions
|
|
-----------
|
|
|
|
IPC requires a more complex permissioning system to allow the modules to
|
|
have limited access to each other and also to allow more types of
|
|
permissions than simple public key signatures. Rather than just use an
|
|
address to identify who is performing an action, we can use a more
|
|
complex structure:
|
|
|
|
.. code:: golang
|
|
|
|
type Actor struct {
|
|
ChainID string `json:"chain"` // this is empty unless it comes from a different chain
|
|
App string `json:"app"` // the app that the actor belongs to
|
|
Address data.Bytes `json:"addr"` // arbitrary app-specific unique id
|
|
}
|
|
|
|
Here, the ``Actor`` abstracts any address that can authorize actions,
|
|
hold funds, or initiate any sort of transaction. It doesn't just have to
|
|
be a pubkey on this chain, it could stem from another app (such as
|
|
multi-sig account), or even another chain (via IBC)
|
|
|
|
``ChainID`` is for IBC, discussed below. Let's focus on ``App`` and
|
|
``Address``. For a signature, the App is ``auth``, and any modules can
|
|
check to see if a specific public key address signed like this
|
|
``ctx.HasPermission(auth.SigPerm(addr))``. However, we can also
|
|
authorize a tx with ``roles``, which handles multi-sig accounts, it
|
|
checks if there were enough signatures by checking as above, then it can
|
|
add the role permission like
|
|
``ctx= ctx.WithPermissions(NewPerm(assume.Role))``
|
|
|
|
In addition to the permissions schema, the Actors are addresses just
|
|
like public key addresses. So one can create a mulit-sig role, then send
|
|
coin there, which can only be moved upon meeting the authorization
|
|
requirements from that module. ``coin`` doesn't even know the existence
|
|
of ``roles`` and one could build any other sort of module to provide
|
|
permissions (like bind the outcome of an election to move coins or to
|
|
modify the accounts on a role).
|
|
|
|
One idea - not yet implemented - is to provide scopes on the
|
|
permissions. Currently, if I sign a transaction to one module, it can
|
|
pass it on to any other module over IPC with the same permissions. It
|
|
could move coins, vote in an election, or anything else. Ideally, when
|
|
signing, one could also specify the scope(s) that this signature
|
|
authorizes. The `oauth
|
|
protocol <https://api.slack.com/docs/oauth-scopes>`__ also has to deal
|
|
with a similar problem, and maybe could provide some inspiration.
|
|
|
|
Replay Protection
|
|
-----------------
|
|
|
|
In order to prevent `replay
|
|
attacks <https://en.wikipedia.org/wiki/Replay_attack>`__ a multi account
|
|
nonce system has been constructed as a module, which can be found in
|
|
``modules/nonce``. By adding the nonce module to the stack, each
|
|
transaction is verified for authenticity against replay attacks. This is
|
|
achieved by requiring that a new signed copy of the sequence number
|
|
which must be exactly 1 greater than the sequence number of the previous
|
|
transaction. A distinct sequence number is assigned per chain-id,
|
|
application, and group of signers. Each sequence number is tracked as a
|
|
nonce-store entry where the key is the marshaled list of actors after
|
|
having been sorted by chain, app, and address.
|
|
|
|
.. code:: golang
|
|
|
|
// Tx - Nonce transaction structure, contains list of signers and current sequence number
|
|
type Tx struct {
|
|
Sequence uint32 `json:"sequence"`
|
|
Signers []basecoin.Actor `json:"signers"`
|
|
Tx basecoin.Tx `json:"tx"`
|
|
}
|
|
|
|
By distinguishing sequence numbers across groups of Signers,
|
|
multi-signature Actors need not lock up use of their Address while
|
|
waiting for all the members of a multi-sig transaction to occur. Instead
|
|
only the multi-sig account will be locked, while other accounts
|
|
belonging to that signer can be used and signed with other sequence
|
|
numbers.
|
|
|
|
By abstracting out the nonce module in the stack, entire series of
|
|
transactions can occur without needing to verify the nonce for each
|
|
member of the series. An common example is a stack which will send coins
|
|
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!
|