Merge branch 'aditya/guide' into develop
This commit is contained in:
commit
c4a70f683c
|
@ -99,18 +99,20 @@ 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 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:
|
||||
|
||||
|
@ -118,6 +120,7 @@ a standard form:
|
|||
type StdSignature struct {
|
||||
crypto.PubKey // optional
|
||||
crypto.Signature
|
||||
AccountNumber int64
|
||||
Sequence int64
|
||||
}
|
||||
```
|
||||
|
@ -138,12 +141,21 @@ 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 way to create a transaction from a message is to use the `StdTx`:
|
||||
The standard bytes for signers to sign over is provided by:
|
||||
|
||||
```go
|
||||
type StdTx struct {
|
||||
Msg
|
||||
Signatures []StdSignature
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -154,7 +166,7 @@ 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`
|
||||
When initializing an application, a developer can specify a `TxDecoder`
|
||||
function which determines how an arbitrary byte array should be unmarshalled
|
||||
into a `Tx`:
|
||||
|
||||
|
@ -162,8 +174,10 @@ 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
|
||||
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.
|
||||
|
@ -182,6 +196,14 @@ 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
|
||||
|
||||
|
@ -252,14 +274,14 @@ Many methods on SDK objects receive a context as the first argument.
|
|||
|
||||
## Handler
|
||||
|
||||
Transaction processing in the SDK is defined through `Handler` functions:
|
||||
Message processing in the SDK is defined through `Handler` functions:
|
||||
|
||||
```go
|
||||
type Handler func(ctx Context, tx Tx) Result
|
||||
type Handler func(ctx Context, msg Msg) 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
|
||||
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
|
||||
|
@ -291,15 +313,138 @@ func NewHandler(am sdk.AccountMapper) sdk.Handler {
|
|||
|
||||
## 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
|
||||
|
||||
### sdk.Account
|
||||
### 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?
|
||||
|
|
|
@ -105,11 +105,14 @@ type KVStore interface {
|
|||
|
||||
// Iterator over a domain of keys in ascending order. End is exclusive.
|
||||
// Start must be less than end, or the Iterator is invalid.
|
||||
// Iterator must be closed by caller.
|
||||
// To iterate over entire domain, use store.Iterator(nil, nil)
|
||||
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
|
||||
Iterator(start, end []byte) Iterator
|
||||
|
||||
// Iterator over a domain of keys in descending order. End is exclusive.
|
||||
// Start must be greater than end, or the Iterator is invalid.
|
||||
// Iterator must be closed by caller.
|
||||
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
|
||||
ReverseIterator(start, end []byte) Iterator
|
||||
|
||||
|
|
Loading…
Reference in New Issue