docs: more on txs, context, handlers
This commit is contained in:
parent
94999ad455
commit
b4e4881261
|
@ -64,9 +64,40 @@ to enforce that message contents are well formed before any actual logic begins.
|
|||
Finally, messages can provide generic access to their contents via `Get(key)`,
|
||||
but this is mostly for convenience and not type-safe.
|
||||
|
||||
For instance, the `Basecoin` message types are defined in `x/bank/tx.go`:
|
||||
|
||||
```
|
||||
type SendMsg struct {
|
||||
Inputs []Input `json:"inputs"`
|
||||
Outputs []Output `json:"outputs"`
|
||||
}
|
||||
|
||||
type IssueMsg struct {
|
||||
Banker crypto.Address `json:"banker"`
|
||||
Outputs []Output `json:"outputs"`
|
||||
}
|
||||
```
|
||||
|
||||
Each specifies the addresses that must sign the message:
|
||||
|
||||
```
|
||||
func (msg SendMsg) GetSigners() []crypto.Address {
|
||||
addrs := make([]crypto.Address, len(msg.Inputs))
|
||||
for i, in := range msg.Inputs {
|
||||
addrs[i] = in.Address
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
func (msg IssueMsg) GetSigners() []crypto.Address {
|
||||
return []crypto.Address{msg.Banker}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Transactions
|
||||
|
||||
For a message to actually be valid, it must be wrapped as a `Tx`, which includes information for authentication:
|
||||
A transaction is a message with additional information for authentication:
|
||||
|
||||
```
|
||||
type Tx interface {
|
||||
|
@ -114,10 +145,75 @@ is forever stored by the application and can be left out of transactions.
|
|||
|
||||
Transactions can also specify the address responsible for paying the transaction's fees using the `tx.GetFeePayer()` method.
|
||||
|
||||
The standard way to create a transaction from a message is to use the `StdTx`:
|
||||
|
||||
```
|
||||
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-wire` library for encoding and decoding all message types.
|
||||
The `go-wire` library has the nice property that it can unmarshal into interface types, but it requires the relevant types
|
||||
to be registered ahead of type. Registration happens on a `Codec` object, so as not to taint the global name space.
|
||||
|
||||
For instance, in `Basecoin`, we wish to register the `SendMsg` and `IssueMsg` types:
|
||||
|
||||
```
|
||||
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 determines the types unique "prefix bytes" during encoding.
|
||||
A registered type will always use the same prefix-bytes, regardless of what interface it is satisfying.
|
||||
For more details, see the [go-wire documentation]().
|
||||
|
||||
## Context
|
||||
|
||||
The SDK uses a `Context` to propogate common information across functions. The `Context` is modelled
|
||||
off of 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.
|
||||
|
||||
## Handlers
|
||||
|
||||
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 store, a particular handler may only need
|
||||
some subset of the store. Access to substores is managed using capabilities -
|
||||
when a handler is initialized, it is passed capability keys that determine which parts of the
|
||||
store it can access.
|
||||
|
||||
|
||||
TODO: example
|
||||
|
||||
## Store
|
||||
|
||||
## App
|
||||
|
|
Loading…
Reference in New Issue