deprecate /docs/guides/sdk
This commit is contained in:
parent
a051091219
commit
7f603c8d57
|
@ -1,464 +0,0 @@
|
||||||
## Introduction
|
|
||||||
|
|
||||||
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 list of Msgs wrapped with authentication and fee data.
|
|
||||||
|
|
||||||
### Messages
|
|
||||||
|
|
||||||
Users can create messages containing arbitrary information by
|
|
||||||
implementing the `Msg` interface:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Msg interface {
|
|
||||||
|
|
||||||
// Return the message type.
|
|
||||||
// Must be alphanumeric or empty.
|
|
||||||
Type() string
|
|
||||||
|
|
||||||
// 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() []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.
|
|
||||||
|
|
||||||
For instance, the `Basecoin` message types are defined in `x/bank/tx.go`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type MsgSend struct {
|
|
||||||
Inputs []Input `json:"inputs"`
|
|
||||||
Outputs []Output `json:"outputs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type MsgIssue struct {
|
|
||||||
Banker sdk.Address `json:"banker"`
|
|
||||||
Outputs []Output `json:"outputs"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Each specifies the addresses that must sign the message:
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (msg MsgSend) GetSigners() []sdk.Address {
|
|
||||||
addrs := make([]sdk.Address, len(msg.Inputs))
|
|
||||||
for i, in := range msg.Inputs {
|
|
||||||
addrs[i] = in.Address
|
|
||||||
}
|
|
||||||
return addrs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg MsgIssue) GetSigners() []sdk.Address {
|
|
||||||
return []sdk.Address{msg.Banker}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Transactions
|
|
||||||
|
|
||||||
A transaction is a list of messages with additional information for authentication:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Tx interface {
|
|
||||||
|
|
||||||
GetMsgs() Msg
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The standard way to create a transaction from a message is to use the `StdTx` struct defined in the `x/auth` module.
|
|
||||||
|
|
||||||
```go
|
|
||||||
type StdTx struct {
|
|
||||||
Msg sdk.Msg `json:"msg"`
|
|
||||||
Fee StdFee `json:"fee"`
|
|
||||||
Signatures []StdSignature `json:"signatures"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `StdTx.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:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type StdSignature struct {
|
|
||||||
crypto.PubKey // optional
|
|
||||||
crypto.Signature
|
|
||||||
AccountNumber int64
|
|
||||||
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.
|
|
||||||
|
|
||||||
The address responsible for paying the transactions fee is the first address
|
|
||||||
returned by msg.GetSigners(). The convenience function `FeePayer(tx Tx)` is provided
|
|
||||||
to return this.
|
|
||||||
|
|
||||||
The standard bytes for signers to sign over is provided by:
|
|
||||||
|
|
||||||
```go
|
|
||||||
func StdSignByes(chainID string, accnums []int64, sequences []int64, fee StdFee, msg sdk.Msg) []byte
|
|
||||||
```
|
|
||||||
|
|
||||||
in `x/auth`. The standard way to construct fees to pay for the processing of transactions is:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// StdFee includes the amount of coins paid in fees and the maximum
|
|
||||||
// gas to be used by the transaction. The ratio yields an effective "gasprice",
|
|
||||||
// which must be above some miminum to be accepted into the mempool.
|
|
||||||
type StdFee struct {
|
|
||||||
Amount sdk.Coins `json:"amount"`
|
|
||||||
Gas int64 `json:"gas"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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 can specify a `TxDecoder`
|
|
||||||
function which determines how an arbitrary byte array should be unmarshalled
|
|
||||||
into a `Tx`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type TxDecoder func(txBytes []byte) (Tx, error)
|
|
||||||
```
|
|
||||||
|
|
||||||
The default tx decoder is the Tendermint wire format which uses the go-amino library
|
|
||||||
for encoding and decoding all message types.
|
|
||||||
|
|
||||||
In `Basecoin`, we use the default transaction decoder. The `go-amino` 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 `MsgSend` and `MsgIssue`
|
|
||||||
types:
|
|
||||||
|
|
||||||
```go
|
|
||||||
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
|
|
||||||
cdc.RegisterConcrete(bank.MsgSend{}, "cosmos-sdk/MsgSend", nil)
|
|
||||||
cdc.RegisterConcrete(bank.MsgIssue{}, "cosmos-sdk/MsgIssue", 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-amino documentation](https://github.com/tendermint/go-amino/blob/develop).
|
|
||||||
|
|
||||||
If you wish to use a custom encoding scheme, you must define a TxDecoder function
|
|
||||||
and set it as the decoder in your extended baseapp using the `SetTxDecoder(decoder sdk.TxDecoder)`.
|
|
||||||
|
|
||||||
Ex:
|
|
||||||
|
|
||||||
```go
|
|
||||||
app.SetTxDecoder(CustomTxDecodeFn)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Storage
|
|
||||||
|
|
||||||
### MultiStore
|
|
||||||
|
|
||||||
MultiStore is like a root filesystem of an operating system, except
|
|
||||||
all the entries are fully Merkleized. You mount onto a MultiStore
|
|
||||||
any number of Stores. Currently only KVStores are supported, but in
|
|
||||||
the future we may support more kinds of stores, such as a HeapStore
|
|
||||||
or a NDStore for multidimensional storage.
|
|
||||||
|
|
||||||
The MultiStore as well as all mounted stores provide caching (aka
|
|
||||||
cache-wrapping) for intermediate state (aka software transactional
|
|
||||||
memory) during the execution of transactions. In the case of the
|
|
||||||
KVStore, this also works for iterators. For example, after running
|
|
||||||
the app's AnteHandler, the MultiStore is cache-wrapped (and each
|
|
||||||
store is also cache-wrapped) so that should processing of the
|
|
||||||
transaction fail, at least the transaction fees are paid and
|
|
||||||
sequence incremented.
|
|
||||||
|
|
||||||
The MultiStore as well as all stores support (or will support)
|
|
||||||
historical state pruning and snapshotting and various kinds of
|
|
||||||
queries with proofs.
|
|
||||||
|
|
||||||
### KVStore
|
|
||||||
|
|
||||||
Here we'll focus on the IAVLStore, which is a kind of KVStore.
|
|
||||||
|
|
||||||
IAVLStore is a fast balanced dynamic Merkle store that also supports
|
|
||||||
iteration, and of course cache-wrapping, state pruning, and various
|
|
||||||
queries with proofs, such as proofs of existence, absence, range,
|
|
||||||
and so on.
|
|
||||||
|
|
||||||
Here's how you mount them to a MultiStore.
|
|
||||||
|
|
||||||
```go
|
|
||||||
mainDB, catDB := dbm.NewMemDB(), dbm.NewMemDB()
|
|
||||||
fooKey := sdk.NewKVStoreKey("foo")
|
|
||||||
barKey := sdk.NewKVStoreKey("bar")
|
|
||||||
catKey := sdk.NewKVStoreKey("cat")
|
|
||||||
ms := NewCommitMultiStore(mainDB)
|
|
||||||
ms.MountStoreWithDB(fooKey, sdk.StoreTypeIAVL, nil)
|
|
||||||
ms.MountStoreWithDB(barKey, sdk.StoreTypeIAVL, nil)
|
|
||||||
ms.MountStoreWithDB(catKey, sdk.StoreTypeIAVL, catDB)
|
|
||||||
```
|
|
||||||
|
|
||||||
In the example above, all IAVL nodes (inner and leaf) will be stored
|
|
||||||
in mainDB with the prefix of "s/k:foo/" and "s/k:bar/" respectively,
|
|
||||||
thus sharing the mainDB. All IAVL nodes (inner and leaf) for the
|
|
||||||
cat KVStore are stored separately in catDB with the prefix of
|
|
||||||
"s/\_/". The "s/k:KEY/" and "s/\_/" prefixes are there to
|
|
||||||
disambiguate store items from other items of non-storage concern.
|
|
||||||
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
The SDK uses a `Context` to propogate common information across functions. The
|
|
||||||
`Context` is modeled 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
|
|
||||||
|
|
||||||
Message processing in the SDK is defined through `Handler` functions:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Handler func(ctx Context, msg Msg) Result
|
|
||||||
```
|
|
||||||
|
|
||||||
A handler takes a context and a message and returns a result. All
|
|
||||||
information necessary for processing a message 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.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 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
|
|
||||||
|
|
||||||
The AnteHandler is used to do all transaction-level processing (i.e. Fee payment, signature verification)
|
|
||||||
before passing the message to its respective handler.
|
|
||||||
|
|
||||||
```go
|
|
||||||
type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool)
|
|
||||||
```
|
|
||||||
|
|
||||||
The antehandler takes a Context and a transaction and returns a new Context, a Result, and the abort boolean.
|
|
||||||
As with the handler, all information necessary for processing a message should be available in the
|
|
||||||
context.
|
|
||||||
|
|
||||||
If the transaction fails, then the application should not waste time processing the message. Thus, the antehandler should
|
|
||||||
return an Error's Result method and set the abort boolean to `true` so that the application knows not to process the message in a handler.
|
|
||||||
|
|
||||||
Most applications can use the provided antehandler implementation in `x/auth` which handles signature verification
|
|
||||||
as well as collecting fees.
|
|
||||||
|
|
||||||
Note: Signatures must be over `auth.StdSignDoc` introduced above to use the provided antehandler.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// File: cosmos-sdk/examples/basecoin/app/app.go
|
|
||||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Handling Fee payment
|
|
||||||
### Handling Authentication
|
|
||||||
|
|
||||||
The antehandler is responsible for handling all authentication of a transaction before passing the message onto its handler.
|
|
||||||
This generally involves signature verification. The antehandler should check that all of the addresses that are returned in
|
|
||||||
`tx.GetMsg().GetSigners()` signed the message and that they signed over `tx.GetMsg().GetSignBytes()`.
|
|
||||||
|
|
||||||
## Accounts and x/auth
|
|
||||||
|
|
||||||
### auth.Account
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Account is a standard account using a sequence number for replay protection
|
|
||||||
// and a pubkey for authentication.
|
|
||||||
type Account interface {
|
|
||||||
GetAddress() sdk.Address
|
|
||||||
SetAddress(sdk.Address) error // errors if already set.
|
|
||||||
|
|
||||||
GetPubKey() crypto.PubKey // can return nil.
|
|
||||||
SetPubKey(crypto.PubKey) error
|
|
||||||
|
|
||||||
GetAccountNumber() int64
|
|
||||||
SetAccountNumber(int64) error
|
|
||||||
|
|
||||||
GetSequence() int64
|
|
||||||
SetSequence(int64) error
|
|
||||||
|
|
||||||
GetCoins() sdk.Coins
|
|
||||||
SetCoins(sdk.Coins) error
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Accounts are the standard way for an application to keep track of addresses and their associated balances.
|
|
||||||
|
|
||||||
### auth.BaseAccount
|
|
||||||
|
|
||||||
```go
|
|
||||||
// BaseAccount - base account structure.
|
|
||||||
// Extend this by embedding this in your AppAccount.
|
|
||||||
// See the examples/basecoin/types/account.go for an example.
|
|
||||||
type BaseAccount struct {
|
|
||||||
Address sdk.Address `json:"address"`
|
|
||||||
Coins sdk.Coins `json:"coins"`
|
|
||||||
PubKey crypto.PubKey `json:"public_key"`
|
|
||||||
AccountNumber int64 `json:"account_number"`
|
|
||||||
Sequence int64 `json:"sequence"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `auth.BaseAccount` struct provides a standard implementation of the Account interface with replay protection.
|
|
||||||
BaseAccount can be extended by embedding it in your own Account struct.
|
|
||||||
|
|
||||||
### auth.AccountMapper
|
|
||||||
|
|
||||||
```go
|
|
||||||
// This AccountMapper encodes/decodes accounts using the
|
|
||||||
// go-amino (binary) encoding/decoding library.
|
|
||||||
type AccountMapper struct {
|
|
||||||
|
|
||||||
// The (unexposed) key used to access the store from the Context.
|
|
||||||
key sdk.StoreKey
|
|
||||||
|
|
||||||
// The prototypical Account concrete type.
|
|
||||||
proto Account
|
|
||||||
|
|
||||||
// The wire codec for binary encoding/decoding of accounts.
|
|
||||||
cdc *wire.Codec
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The AccountMapper is responsible for managing and storing the state of all accounts in the application.
|
|
||||||
|
|
||||||
Example Initialization:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// File: examples/basecoin/app/app.go
|
|
||||||
// Define the accountMapper.
|
|
||||||
app.accountMapper = auth.NewAccountMapper(
|
|
||||||
cdc,
|
|
||||||
app.keyAccount, // target store
|
|
||||||
&types.AppAccount{}, // prototype
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
The accountMapper allows you to retrieve the current account state by `GetAccount(ctx Context, addr auth.Address)` and change the state by
|
|
||||||
`SetAccount(ctx Context, acc Account)`.
|
|
||||||
|
|
||||||
Note: To update an account you will first have to get the account, update the appropriate fields with its associated setter method, and then call
|
|
||||||
`SetAccount(ctx Context, acc updatedAccount)`.
|
|
||||||
|
|
||||||
Updating accounts is made easier by using the `Keeper` struct in the `x/bank` module.
|
|
||||||
|
|
||||||
Example Initialization:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// File: examples/basecoin/app/app.go
|
|
||||||
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
|
||||||
```
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Finds account with addr in accountmapper
|
|
||||||
// Adds coins to account's coin array
|
|
||||||
// Sets updated account in accountmapper
|
|
||||||
app.coinKeeper.AddCoins(ctx, addr, coins)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Wire codec
|
|
||||||
|
|
||||||
### Why another codec?
|
|
||||||
### vs encoding/json
|
|
||||||
### vs protobuf
|
|
||||||
|
|
||||||
## KVStore 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: MsgSend and MsgIssue.
|
|
||||||
MsgSend allows coins to be sent around, while MsgIssue allows a
|
|
||||||
set of predefined users to issue new coins.
|
|
||||||
|
|
||||||
## Conclusion
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
DEPRECATED
|
||||||
|
|
||||||
|
See the [docs](/docs/sdk)
|
|
@ -1,70 +1,2 @@
|
||||||
# Apps in the SDK
|
[Moved](/docs/sdk/overview/apps.md)
|
||||||
|
|
||||||
The SDK has multiple levels of "application": the ABCI app, the BaseApp, the BasecoinApp, and now your App.
|
|
||||||
|
|
||||||
## ABCI App
|
|
||||||
|
|
||||||
The basic ABCI interface allowing Tendermint to drive the applications state machine with transaction blocks.
|
|
||||||
|
|
||||||
## BaseApp
|
|
||||||
|
|
||||||
Implements an ABCI App using a MultiStore for persistence and a Router to handle transactions.
|
|
||||||
The goal is to provide a secure interface between the store and the extensible state machine
|
|
||||||
while defining as little about that state machine as possible (staying true to the ABCI).
|
|
||||||
|
|
||||||
BaseApp requires stores to be mounted via capabilities keys - handlers can only access
|
|
||||||
stores they're given the key for. The BaseApp ensures all stores are properly loaded, cached, and committed.
|
|
||||||
One mounted store is considered the "main" - it holds the latest block header, from which we can find and load the
|
|
||||||
most recent state ([TODO](https://github.com/cosmos/cosmos-sdk/issues/522)).
|
|
||||||
|
|
||||||
BaseApp distinguishes between two handler types - the `AnteHandler` and the `MsgHandler`.
|
|
||||||
The former is a global validity check (checking nonces, sigs and sufficient balances to pay fees,
|
|
||||||
e.g. things that apply to all transaction from all modules), the later is the full state transition function.
|
|
||||||
During CheckTx the state transition function is only applied to the checkTxState and should return
|
|
||||||
before any expensive state transitions are run (this is up to each developer). It also needs to return the estimated
|
|
||||||
gas cost.
|
|
||||||
During DeliverTx the state transition function is applied to the blockchain state and the transactions
|
|
||||||
need to be fully executed.
|
|
||||||
|
|
||||||
BaseApp is responsible for managing the context passed into handlers -
|
|
||||||
it makes the block header available and provides the right stores for CheckTx and DeliverTx.
|
|
||||||
|
|
||||||
BaseApp is completely agnostic to serialization formats.
|
|
||||||
|
|
||||||
## Basecoin
|
|
||||||
|
|
||||||
Basecoin is the first complete application in the stack.
|
|
||||||
Complete applications require extensions to the core modules of the SDK to actually implement handler functionality.
|
|
||||||
The native extensions of the SDK, useful for building Cosmos Zones, live under `x`.
|
|
||||||
Basecoin implements a `BaseApp` state machine using the `x/auth` and `x/bank` extensions,
|
|
||||||
which define how transaction signers are authenticated and how coins are transferred.
|
|
||||||
It should also use `x/ibc` and probably a simple staking extension.
|
|
||||||
|
|
||||||
Basecoin and the native `x` extensions use go-amino for all serialization needs,
|
|
||||||
including for transactions and accounts.
|
|
||||||
|
|
||||||
## Your Cosmos App
|
|
||||||
|
|
||||||
Your Cosmos App is a fork of Basecoin - copy the `examples/basecoin` directory and modify it to your needs.
|
|
||||||
You might want to:
|
|
||||||
|
|
||||||
- add fields to accounts
|
|
||||||
- copy and modify handlers
|
|
||||||
- add new handlers for new transaction types
|
|
||||||
- add new stores for better isolation across handlers
|
|
||||||
|
|
||||||
The Cosmos Hub takes Basecoin and adds more stores and extensions to handle additional
|
|
||||||
transaction types and logic, like the advanced staking logic and the governance process.
|
|
||||||
|
|
||||||
## Ethermint
|
|
||||||
|
|
||||||
Ethermint is a new implementation of `BaseApp` that does not depend on Basecoin.
|
|
||||||
Instead of `cosmos-sdk/x/` it has its own `ethermint/x` based on `go-ethereum`.
|
|
||||||
|
|
||||||
Ethermint uses a Patricia store for its accounts, and an IAVL store for IBC.
|
|
||||||
It has `x/ante`, which is quite similar to Basecoin's but uses RLP instead of go-amino.
|
|
||||||
Instead of `x/bank`, it has `x/eth`, which defines the single Ethereum transaction type
|
|
||||||
and all the semantics of the Ethereum state machine.
|
|
||||||
|
|
||||||
Within `x/eth`, transactions sent to particular addresses can be handled in unique ways,
|
|
||||||
for instance to handle IBC and staking.
|
|
||||||
|
|
|
@ -1,59 +1 @@
|
||||||
# Install
|
[Moved](/docs/sdk/install.md)
|
||||||
|
|
||||||
The fastest and easiest way to install the Cosmos SDK binaries
|
|
||||||
is to run [this script](https://github.com/cosmos/cosmos-sdk/blob/develop/scripts/install_sdk_ubuntu.sh) on a fresh Ubuntu instance. Similarly, you can run [this script](https://github.com/cosmos/cosmos-sdk/blob/develop/scripts/install_sdk_bsd.sh) on a fresh FreeBSD instance. Read the scripts before running them to ensure no untrusted connection is being made, for example we're making curl requests to download golang. Also read the comments / instructions carefully (i.e., reset your terminal after running the script).
|
|
||||||
|
|
||||||
Cosmos SDK can be installed to
|
|
||||||
`$GOPATH/src/github.com/cosmos/cosmos-sdk` like a normal Go program:
|
|
||||||
|
|
||||||
```
|
|
||||||
go get github.com/cosmos/cosmos-sdk
|
|
||||||
```
|
|
||||||
|
|
||||||
If the dependencies have been updated with breaking changes, or if
|
|
||||||
another branch is required, `dep` is used for dependency management.
|
|
||||||
Thus, assuming you've already run `go get` or otherwise cloned the repo,
|
|
||||||
the correct way to install is:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
|
|
||||||
make get_tools
|
|
||||||
make get_vendor_deps
|
|
||||||
make install
|
|
||||||
make install_examples
|
|
||||||
```
|
|
||||||
|
|
||||||
This will install `gaiad` and `gaiacli` and four example binaries:
|
|
||||||
`basecoind`, `basecli`, `democoind`, and `democli`.
|
|
||||||
|
|
||||||
Verify that everything is OK by running:
|
|
||||||
|
|
||||||
```
|
|
||||||
gaiad version
|
|
||||||
```
|
|
||||||
|
|
||||||
you should see:
|
|
||||||
|
|
||||||
```
|
|
||||||
0.17.3-a5a78eb
|
|
||||||
```
|
|
||||||
|
|
||||||
then with:
|
|
||||||
|
|
||||||
```
|
|
||||||
gaiacli version
|
|
||||||
```
|
|
||||||
you should see the same version (or a later one for both).
|
|
||||||
|
|
||||||
## Update
|
|
||||||
|
|
||||||
Get latest code (you can also `git fetch` only the version desired),
|
|
||||||
ensure the dependencies are up to date, then recompile.
|
|
||||||
|
|
||||||
```
|
|
||||||
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
|
|
||||||
git fetch -a origin
|
|
||||||
git checkout VERSION
|
|
||||||
make get_vendor_deps
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,7 +1 @@
|
||||||
# Key Management
|
[Moved](/docs/sdk/clients/key-management.md)
|
||||||
|
|
||||||
Here we cover many aspects of handling keys within the Cosmos SDK
|
|
||||||
framework.
|
|
||||||
|
|
||||||
// TODO add relevant key discussion
|
|
||||||
(related https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography)
|
|
||||||
|
|
|
@ -1,781 +1 @@
|
||||||
swagger: '2.0'
|
[Moved](/docs/sdk/clients/lcd-rest-api.yaml)
|
||||||
info:
|
|
||||||
version: '1.1.0'
|
|
||||||
title: Light client daemon to interface with Cosmos baseserver via REST
|
|
||||||
description: Specification for the LCD provided by `gaiacli advanced rest-server`
|
|
||||||
|
|
||||||
|
|
||||||
securityDefinitions:
|
|
||||||
kms:
|
|
||||||
type: basic
|
|
||||||
|
|
||||||
paths:
|
|
||||||
/version:
|
|
||||||
get:
|
|
||||||
summary: Version of the light client daemon
|
|
||||||
description: Get the version of the LCD running locally to compare against expected
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Plaintext version i.e. "v0.5.0"
|
|
||||||
/node_version:
|
|
||||||
get:
|
|
||||||
summary: Version of the connected node
|
|
||||||
description: Get the version of the SDK running on the connected node to compare against expected
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Plaintext version i.e. "v0.5.0"
|
|
||||||
/node_info:
|
|
||||||
get:
|
|
||||||
description: Only the node info. Block information can be queried via /block/latest
|
|
||||||
summary: The propertied of the connected node
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Node status
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
pub_key:
|
|
||||||
$ref: '#/definitions/PubKey'
|
|
||||||
moniker:
|
|
||||||
type: string
|
|
||||||
example: 159.89.198.221
|
|
||||||
network:
|
|
||||||
type: string
|
|
||||||
example: gaia-2
|
|
||||||
remote_addr:
|
|
||||||
type: string
|
|
||||||
listen_addr:
|
|
||||||
type: string
|
|
||||||
example: 192.168.56.1:26656
|
|
||||||
version:
|
|
||||||
description: Tendermint version
|
|
||||||
type: string
|
|
||||||
example: 0.15.0
|
|
||||||
other:
|
|
||||||
description: more information on versions
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
/syncing:
|
|
||||||
get:
|
|
||||||
summary: Syncing state of node
|
|
||||||
description: Get if the node is currently syning with other nodes
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: '"true" or "false"'
|
|
||||||
|
|
||||||
/keys:
|
|
||||||
get:
|
|
||||||
summary: List of accounts stored locally
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Array of accounts
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/Account'
|
|
||||||
post:
|
|
||||||
summary: Create a new account locally
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: account
|
|
||||||
description: The account to create
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- name
|
|
||||||
- password
|
|
||||||
- seed
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
seed:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Returns address of the account created
|
|
||||||
/keys/seed:
|
|
||||||
get:
|
|
||||||
summary: Create a new seed to create a new account with
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: 16 word Seed
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
/keys/{name}:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: name
|
|
||||||
description: Account name
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
get:
|
|
||||||
summary: Get a certain locally stored account
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Locally stored account
|
|
||||||
schema:
|
|
||||||
$ref: "#/definitions/Account"
|
|
||||||
404:
|
|
||||||
description: Account is not available
|
|
||||||
put:
|
|
||||||
summary: Update the password for this account in the KMS
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: account
|
|
||||||
description: The new and old password
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- new_password
|
|
||||||
- old_password
|
|
||||||
properties:
|
|
||||||
new_password:
|
|
||||||
type: string
|
|
||||||
old_password:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Updated password
|
|
||||||
401:
|
|
||||||
description: Password is wrong
|
|
||||||
404:
|
|
||||||
description: Account is not available
|
|
||||||
delete:
|
|
||||||
summary: Remove an account
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: account
|
|
||||||
description: The password of the account to remove from the KMS
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- password
|
|
||||||
properties:
|
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Removed account
|
|
||||||
401:
|
|
||||||
description: Password is wrong
|
|
||||||
404:
|
|
||||||
description: Account is not available
|
|
||||||
# /accounts/send:
|
|
||||||
# post:
|
|
||||||
# summary: Send coins (build -> sign -> send)
|
|
||||||
# security:
|
|
||||||
# - sign: []
|
|
||||||
# requestBody:
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# fees:
|
|
||||||
# $ref: "#/definitions/Coins"
|
|
||||||
# outputs:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# pub_key:
|
|
||||||
# $ref: "#/definitions/PubKey"
|
|
||||||
# amount:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# $ref: "#/definitions/Coins"
|
|
||||||
# responses:
|
|
||||||
# 202:
|
|
||||||
# description: Tx was send and will probably be added to the next block
|
|
||||||
# 400:
|
|
||||||
# description: The Tx was malformated
|
|
||||||
|
|
||||||
/accounts/{address}:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: address
|
|
||||||
description: Account address in bech32 format
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
get:
|
|
||||||
summary: Get the account balances
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Account balances
|
|
||||||
schema:
|
|
||||||
$ref: "#/definitions/Balance"
|
|
||||||
204:
|
|
||||||
description: There is no data for the requested account. This is not a 404 as the account might exist, just does not hold data.
|
|
||||||
/accounts/{address}/send:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: address
|
|
||||||
description: Account address in bech32 format
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
post:
|
|
||||||
summary: Send coins (build -> sign -> send)
|
|
||||||
security:
|
|
||||||
- kms: []
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: account
|
|
||||||
description: The password of the account to remove from the KMS
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
amount:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/Coins"
|
|
||||||
chain_id:
|
|
||||||
type: string
|
|
||||||
squence:
|
|
||||||
type: number
|
|
||||||
responses:
|
|
||||||
202:
|
|
||||||
description: Tx was send and will probably be added to the next block
|
|
||||||
400:
|
|
||||||
description: The Tx was malformated
|
|
||||||
/blocks/latest:
|
|
||||||
get:
|
|
||||||
summary: Get the latest block
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: The latest block
|
|
||||||
schema:
|
|
||||||
$ref: "#/definitions/Block"
|
|
||||||
/blocks/{height}:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: height
|
|
||||||
description: Block height
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
get:
|
|
||||||
summary: Get a block at a certain height
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: The block at a specific height
|
|
||||||
schema:
|
|
||||||
$ref: "#/definitions/Block"
|
|
||||||
404:
|
|
||||||
description: Block at height is not available
|
|
||||||
/validatorsets/latest:
|
|
||||||
get:
|
|
||||||
summary: Get the latest validator set
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: The validator set at the latest block height
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
block_height:
|
|
||||||
type: number
|
|
||||||
validators:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/Validator"
|
|
||||||
/validatorsets/{height}:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: height
|
|
||||||
description: Block height
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
get:
|
|
||||||
summary: Get a validator set a certain height
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: The validator set at a specific block height
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
block_height:
|
|
||||||
type: number
|
|
||||||
validators:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/Validator"
|
|
||||||
404:
|
|
||||||
description: Block at height not available
|
|
||||||
# /txs:
|
|
||||||
# parameters:
|
|
||||||
# - in: query
|
|
||||||
# name: tag
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# example: "coin.sender=EE5F3404034C524501629B56E0DDC38FAD651F04"
|
|
||||||
# required: true
|
|
||||||
# - in: query
|
|
||||||
# name: page
|
|
||||||
# description: Pagination page
|
|
||||||
# schema:
|
|
||||||
# type: number
|
|
||||||
# default: 0
|
|
||||||
# - in: query
|
|
||||||
# name: size
|
|
||||||
# description: Pagination size
|
|
||||||
# schema:
|
|
||||||
# type: number
|
|
||||||
# default: 50
|
|
||||||
# get:
|
|
||||||
# summary: Query Tx
|
|
||||||
# responses:
|
|
||||||
# 200:
|
|
||||||
# description: All Tx matching the provided tags
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# $ref: "#/definitions/Tx"
|
|
||||||
# 404:
|
|
||||||
# description: Pagination is out of bounds
|
|
||||||
# /txs/sign:
|
|
||||||
# post:
|
|
||||||
# summary: Sign a Tx
|
|
||||||
# description: Sign a Tx providing locally stored account and according password
|
|
||||||
# security:
|
|
||||||
# - sign: []
|
|
||||||
# requestBody:
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: "#/definitions/TxBuild"
|
|
||||||
# responses:
|
|
||||||
# 200:
|
|
||||||
# description: The signed Tx
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: "#/definitions/TxSigned"
|
|
||||||
# 401:
|
|
||||||
# description: Account name and/or password where wrong
|
|
||||||
# /txs/broadcast:
|
|
||||||
# post:
|
|
||||||
# summary: Send signed Tx
|
|
||||||
# requestBody:
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: "#/definitions/TxSigned"
|
|
||||||
# responses:
|
|
||||||
# 202:
|
|
||||||
# description: Tx was send and will probably be added to the next block
|
|
||||||
# 400:
|
|
||||||
# description: The Tx was malformated
|
|
||||||
/txs/{hash}:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: hash
|
|
||||||
description: Tx hash
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
get:
|
|
||||||
summary: Get a Tx by hash
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Tx with the provided hash
|
|
||||||
schema:
|
|
||||||
$ref: "#/definitions/Tx"
|
|
||||||
404:
|
|
||||||
description: Tx not available for provided hash
|
|
||||||
# /delegates:
|
|
||||||
# parameters:
|
|
||||||
# - in: query
|
|
||||||
# name: delegator
|
|
||||||
# description: Query for all delegates a delegator has stake with
|
|
||||||
# schema:
|
|
||||||
# $ref: "#/definitions/Address"
|
|
||||||
# get:
|
|
||||||
# summary: Get a list of canidates/delegates/validators (optionally filtered by delegator)
|
|
||||||
# responses:
|
|
||||||
# 200:
|
|
||||||
# description: List of delegates, filtered by provided delegator address
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# $ref: "#/definitions/Delegate"
|
|
||||||
# /delegates/bond:
|
|
||||||
# post:
|
|
||||||
# summary: Bond atoms (build -> sign -> send)
|
|
||||||
# security:
|
|
||||||
# - sign: []
|
|
||||||
# requestBody:
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# amount:
|
|
||||||
# $ref: "#/definitions/Coins"
|
|
||||||
# pub_key:
|
|
||||||
# $ref: "#/definitions/PubKey"
|
|
||||||
# responses:
|
|
||||||
# 202:
|
|
||||||
# description: Tx was send and will probably be added to the next block
|
|
||||||
# 400:
|
|
||||||
# description: The Tx was malformated
|
|
||||||
# /delegates/unbond:
|
|
||||||
# post:
|
|
||||||
# summary: Unbond atoms (build -> sign -> send)
|
|
||||||
# security:
|
|
||||||
# - sign: []
|
|
||||||
# requestBody:
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# amount:
|
|
||||||
# $ref: "#/definitions/Coins"
|
|
||||||
# pub_key:
|
|
||||||
# $ref: "#/definitions/PubKey"
|
|
||||||
# responses:
|
|
||||||
# 202:
|
|
||||||
# description: Tx was send and will probably be added to the next block
|
|
||||||
# 400:
|
|
||||||
# description: The Tx was malformated
|
|
||||||
# /delegates/{pubkey}:
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: pubkey
|
|
||||||
# description: Pubkey of a delegate
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
|
||||||
# get:
|
|
||||||
# summary: Get a certain canidate/delegate/validator
|
|
||||||
# responses:
|
|
||||||
# 200:
|
|
||||||
# description: Delegate for specified pub_key
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: "#/definitions/Delegate"
|
|
||||||
# 404:
|
|
||||||
# description: No delegate found for provided pub_key
|
|
||||||
# /delegates/{pubkey}/bond:
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: pubkey
|
|
||||||
# description: Pubkey of a delegate
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
|
||||||
# post:
|
|
||||||
# summary: Bond atoms (build -> sign -> send)
|
|
||||||
# security:
|
|
||||||
# - sign: []
|
|
||||||
# requestBody:
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# amount:
|
|
||||||
# $ref: "#/definitions/Coins"
|
|
||||||
# responses:
|
|
||||||
# 202:
|
|
||||||
# description: Tx was send and will probably be added to the next block
|
|
||||||
# 400:
|
|
||||||
# description: The Tx was malformated
|
|
||||||
# /delegates/{pubkey}/unbond:
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: pubkey
|
|
||||||
# description: Pubkey of a delegate
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
|
||||||
# post:
|
|
||||||
# summary: Unbond atoms (build -> sign -> send)
|
|
||||||
# security:
|
|
||||||
# - sign: []
|
|
||||||
# requestBody:
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# amount:
|
|
||||||
# $ref: "#/definitions/Coins"
|
|
||||||
# responses:
|
|
||||||
# 202:
|
|
||||||
# description: Tx was send and will probably be added to the next block
|
|
||||||
# 400:
|
|
||||||
# description: The Tx was malformated
|
|
||||||
|
|
||||||
definitions:
|
|
||||||
Address:
|
|
||||||
type: string
|
|
||||||
description: bech32 encoded addres
|
|
||||||
example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
|
||||||
ValidatorAddress:
|
|
||||||
type: string
|
|
||||||
description: bech32 encoded addres
|
|
||||||
example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
|
||||||
PubKey:
|
|
||||||
type: string
|
|
||||||
description: bech32 encoded public key
|
|
||||||
example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
|
||||||
ValidatorPubKey:
|
|
||||||
type: string
|
|
||||||
description: bech32 encoded public key
|
|
||||||
example: cosmosvalpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
|
||||||
Coins:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
denom:
|
|
||||||
type: string
|
|
||||||
example: steak
|
|
||||||
amount:
|
|
||||||
type: number
|
|
||||||
example: 50
|
|
||||||
Hash:
|
|
||||||
type: string
|
|
||||||
example: EE5F3404034C524501629B56E0DDC38FAD651F04
|
|
||||||
Tx:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- stake/delegate
|
|
||||||
data:
|
|
||||||
type: object
|
|
||||||
TxChain:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
default: chain/tx
|
|
||||||
data:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
chain_id:
|
|
||||||
type: string
|
|
||||||
example: gaia-2
|
|
||||||
expires_at:
|
|
||||||
type: number
|
|
||||||
example: 0
|
|
||||||
tx:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
default: nonce
|
|
||||||
data:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
sequence:
|
|
||||||
type: number
|
|
||||||
example: 0
|
|
||||||
signers:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
chain:
|
|
||||||
type: string
|
|
||||||
example: ''
|
|
||||||
app:
|
|
||||||
type: string
|
|
||||||
default: sigs
|
|
||||||
addr:
|
|
||||||
$ref: "#/definitions/Address"
|
|
||||||
tx:
|
|
||||||
$ref: "#/definitions/Tx"
|
|
||||||
TxBuild:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
default: sigs/one
|
|
||||||
data:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
tx:
|
|
||||||
$ref: "#/definitions/Tx"
|
|
||||||
signature:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
Sig:
|
|
||||||
type: string
|
|
||||||
default: ''
|
|
||||||
Pubkey:
|
|
||||||
type: string
|
|
||||||
default: ''
|
|
||||||
TxSigned:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
default: sigs/one
|
|
||||||
data:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
tx:
|
|
||||||
$ref: "#/definitions/Tx"
|
|
||||||
signature:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
Sig:
|
|
||||||
type: string
|
|
||||||
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
|
||||||
Pubkey:
|
|
||||||
$ref: "#/definitions/PubKey"
|
|
||||||
Account:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
example: Main Account
|
|
||||||
address:
|
|
||||||
$ref: "#/definitions/Address"
|
|
||||||
pub_key:
|
|
||||||
$ref: "#/definitions/PubKey"
|
|
||||||
Balance:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
height:
|
|
||||||
type: number
|
|
||||||
example: 123456
|
|
||||||
coins:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/Coins"
|
|
||||||
credit:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
BlockID:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
parts:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
total:
|
|
||||||
type: number
|
|
||||||
example: 0
|
|
||||||
hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
Block:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
header:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
chain_id:
|
|
||||||
type: string
|
|
||||||
example: gaia-2
|
|
||||||
height:
|
|
||||||
type: number
|
|
||||||
example: 1
|
|
||||||
time:
|
|
||||||
type: string
|
|
||||||
example: '2017-12-30T05:53:09.287+01:00'
|
|
||||||
num_txs:
|
|
||||||
type: number
|
|
||||||
example: 0
|
|
||||||
last_block_id:
|
|
||||||
$ref: "#/definitions/BlockID"
|
|
||||||
total_txs:
|
|
||||||
type: number
|
|
||||||
example: 35
|
|
||||||
last_commit_hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
data_hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
validators_hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
consensus_hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
app_hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
last_results_hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
evidence_hash:
|
|
||||||
$ref: "#/definitions/Hash"
|
|
||||||
txs:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/Tx"
|
|
||||||
evidence:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
last_commit:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
blockID:
|
|
||||||
$ref: "#/definitions/BlockID"
|
|
||||||
precommits:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
Validator:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
address:
|
|
||||||
$ref: '#/definitions/ValidatorAddress'
|
|
||||||
pub_key:
|
|
||||||
$ref: "#/definitions/ValidatorPubKey"
|
|
||||||
power:
|
|
||||||
type: number
|
|
||||||
example: 1000
|
|
||||||
accum:
|
|
||||||
type: number
|
|
||||||
example: 1000
|
|
||||||
# Added by API Auto Mocking Plugin
|
|
||||||
host: virtserver.swaggerhub.com
|
|
||||||
basePath: /faboweb1/Cosmos-LCD-2/1.0.0
|
|
||||||
schemes:
|
|
||||||
- https
|
|
||||||
|
|
|
@ -1,420 +1 @@
|
||||||
Overview
|
[Moved](/docs/sdk)
|
||||||
========
|
|
||||||
|
|
||||||
The SDK design optimizes flexibility and security. The
|
|
||||||
framework is designed around a modular execution stack which allows
|
|
||||||
applications to mix and match 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 assume that a thriving ecosystem of Cosmos-SDK modules that are easy to compose into a blockchain application will contain faulty or malicious modules.
|
|
||||||
|
|
||||||
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."
|
|
||||||
|
|
||||||
See the `wikipedia article <https://en.wikipedia.org/wiki/Object-capability_model>`__ for more information.
|
|
||||||
|
|
||||||
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 Dep. 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:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
var sumValue := externalModule.ComputeSumValue(*account)
|
|
||||||
|
|
||||||
In the Cosmos SDK, you can see the application of this principle in the basecoin examples folder.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
// 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
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
For examples, see the `examples <https://github.com/cosmos/cosmos-sdk/tree/develop/examples>`__ directory.
|
|
||||||
|
|
||||||
Design Goals
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The design of the Cosmos SDK is based on the principles of "capabilities systems".
|
|
||||||
|
|
||||||
Capabilities systems
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
TODO:
|
|
||||||
|
|
||||||
* Need for module isolation
|
|
||||||
* Capability is implied permission
|
|
||||||
* 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:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
type Msg interface {
|
|
||||||
|
|
||||||
// Return the message type.
|
|
||||||
// Must be alphanumeric or empty.
|
|
||||||
Type() string
|
|
||||||
|
|
||||||
// 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() []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.
|
|
||||||
|
|
||||||
For instance, the ``Basecoin`` message types are defined in ``x/bank/tx.go``:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
type SendMsg struct {
|
|
||||||
Inputs []Input `json:"inputs"`
|
|
||||||
Outputs []Output `json:"outputs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type IssueMsg struct {
|
|
||||||
Banker sdk.Address `json:"banker"`
|
|
||||||
Outputs []Output `json:"outputs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
Each specifies the addresses that must sign the message:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
func (msg SendMsg) GetSigners() []sdk.Address {
|
|
||||||
addrs := make([]sdk.Address, len(msg.Inputs))
|
|
||||||
for i, in := range msg.Inputs {
|
|
||||||
addrs[i] = in.Address
|
|
||||||
}
|
|
||||||
return addrs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg IssueMsg) GetSigners() []sdk.Address {
|
|
||||||
return []sdk.Address{msg.Banker}
|
|
||||||
}
|
|
||||||
|
|
||||||
Transactions
|
|
||||||
^^^^^^^^^^^^
|
|
||||||
|
|
||||||
A transaction is a message with additional information for authentication:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
type Tx interface {
|
|
||||||
|
|
||||||
GetMsg() Msg
|
|
||||||
|
|
||||||
// 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:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
type StdSignature struct {
|
|
||||||
crypto.PubKey // optional
|
|
||||||
crypto.Signature
|
|
||||||
AccountNumber int64
|
|
||||||
Sequence int64
|
|
||||||
}
|
|
||||||
|
|
||||||
It contains the signature itself, as well as the corresponding account's account and
|
|
||||||
sequence numbers. The sequence number is expected to increment every time a
|
|
||||||
message is signed by a given account. The account number stays the same and is assigned
|
|
||||||
when the account is first generated. These prevent "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.
|
|
||||||
|
|
||||||
The standard way to create a transaction from a message is to use the ``StdTx``:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
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``:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
type TxDecoder func(txBytes []byte) (Tx, error)
|
|
||||||
|
|
||||||
In ``Basecoin``, we use the Tendermint wire format and the ``go-amino`` library for
|
|
||||||
encoding and decoding all message types. The ``go-amino`` 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:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
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-amino documentation <https://github.com/tendermint/go-amino/tree/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:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
// 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
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
KVStore 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.
|
|
||||||
|
|
Loading…
Reference in New Issue