2018-06-26 19:49:13 -07:00
|
|
|
# Modules
|
2018-06-16 19:24:48 -07:00
|
|
|
|
2018-06-26 15:05:12 -07:00
|
|
|
In the previous app, we introduced a new `Msg` type and used Amino to encode
|
2018-06-26 19:49:13 -07:00
|
|
|
transactions. We also introduced additional data to the `Tx`, and used a simple
|
|
|
|
`AnteHandler` to validate it.
|
2018-06-16 19:24:48 -07:00
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
Here, in `App3`, we introduce two built-in SDK modules to
|
|
|
|
replace the `Msg`, `Tx`, `Handler`, and `AnteHandler` implementations we've seen
|
|
|
|
so far.
|
2018-06-26 18:29:54 -07:00
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
The `x/auth` module implements `Tx` and `AnteHandler - it has everything we need to
|
|
|
|
authenticate transactions. It also includes a new `Account` type that simplifies
|
|
|
|
working with accounts in the store.
|
2018-06-26 18:29:54 -07:00
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
The `x/bank` module implements `Msg` and `Handler` - it has everything we need
|
|
|
|
to transfer coins between accounts.
|
|
|
|
|
|
|
|
Applications that use `x/auth` and `x/bank` thus significantly reduce the amount
|
|
|
|
of work they have to do so they can focus on their application specific logic in
|
|
|
|
their own modules.
|
|
|
|
|
|
|
|
Here, we'll introduce the important types from `x/auth` and `x/bank`, and show
|
|
|
|
how to make `App3` by using them. The complete code can be found in [app3.go](examples/app3.go).
|
|
|
|
|
|
|
|
## Accounts
|
|
|
|
|
|
|
|
The `x/auth` module defines a model of accounts much like Ethereum.
|
|
|
|
In this model, an account contains:
|
2018-06-26 18:29:54 -07:00
|
|
|
|
|
|
|
- Address for identification
|
|
|
|
- PubKey for authentication
|
|
|
|
- AccountNumber to prune empty accounts
|
|
|
|
- Sequence to prevent transaction replays
|
|
|
|
- Coins to carry a balance
|
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
### Account
|
|
|
|
|
|
|
|
The `Account` interface captures this account model with getters and setters:
|
2018-06-26 18:29:54 -07:00
|
|
|
|
|
|
|
```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
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
Note this is a low-level interface - it allows any of the fields to be over
|
|
|
|
written. As we'll soon see, access can be restricted using the `Keeper`
|
|
|
|
paradigm.
|
|
|
|
|
|
|
|
### BaseAccount
|
2018-06-26 18:29:54 -07:00
|
|
|
|
|
|
|
The default implementation of `Account` is the `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"`
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
It simply contains a field for each of the methods.
|
|
|
|
|
|
|
|
The `Address`, `PubKey`, and `AccountNumber` of the `BaseAccpunt` cannot be changed once they are set.
|
|
|
|
|
|
|
|
The `Sequence` increments by one with every transaction. This ensures that a
|
|
|
|
given transaction can only be executed once, as the `Sequence` contained in the
|
|
|
|
transaction must match that contained in the account.
|
|
|
|
|
|
|
|
The `Coins` will change according to the logic of each transaction type.
|
|
|
|
|
|
|
|
If the `Coins` are ever emptied, the account will be deleted from the store. If
|
|
|
|
coins are later sent to the same `Address`, the account will be recreated but
|
|
|
|
with a new `AccountNumber`. This allows us to prune empty accounts from the
|
|
|
|
store, while still preventing transaction replay if accounts become non-empty
|
|
|
|
again in the future.
|
|
|
|
|
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
### AccountMapper
|
|
|
|
|
|
|
|
TODO
|
|
|
|
|
|
|
|
## Transaction
|
2018-06-26 18:29:54 -07:00
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
|
|
|
|
### StdTx
|
2018-06-16 19:24:48 -07:00
|
|
|
|
2018-06-26 18:29:54 -07:00
|
|
|
The standard way to create a transaction from a message is to use the `StdTx` struct defined in the `x/auth` module:
|
2018-06-16 19:24:48 -07:00
|
|
|
|
|
|
|
```go
|
2018-06-26 18:29:54 -07:00
|
|
|
// StdTx is a standard way to wrap a Msg with Fee and Signatures.
|
|
|
|
// NOTE: the first signature is the FeePayer (Signatures must not be nil).
|
2018-06-16 19:24:48 -07:00
|
|
|
type StdTx struct {
|
2018-06-26 18:29:54 -07:00
|
|
|
Msgs []sdk.Msg `json:"msg"`
|
2018-06-16 19:24:48 -07:00
|
|
|
Fee StdFee `json:"fee"`
|
|
|
|
Signatures []StdSignature `json:"signatures"`
|
2018-06-26 18:29:54 -07:00
|
|
|
Memo string `json:"memo"`
|
2018-06-16 19:24:48 -07:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-06-26 18:29:54 -07:00
|
|
|
The `StdTx` includes a list of messages, information about the fee being paid,
|
|
|
|
and a list of signatures. It also includes an optional `Memo` for additional
|
|
|
|
data. Note that the list of signatures must match the result of `GetSigners()`
|
|
|
|
for each `Msg`!
|
|
|
|
|
|
|
|
The signatures are provided in a standard form as `StdSignature`:
|
2018-06-16 19:24:48 -07:00
|
|
|
|
|
|
|
```go
|
2018-06-26 18:29:54 -07:00
|
|
|
// StdSignature wraps the Signature and includes counters for replay protection.
|
|
|
|
// It also includes an optional public key, which must be provided at least in
|
|
|
|
// the first transaction made by the account.
|
2018-06-16 19:24:48 -07:00
|
|
|
type StdSignature struct {
|
2018-06-26 18:29:54 -07:00
|
|
|
crypto.PubKey `json:"pub_key"` // optional
|
|
|
|
crypto.Signature `json:"signature"`
|
|
|
|
AccountNumber int64 `json:"account_number"`
|
|
|
|
Sequence int64 `json:"sequence"`
|
2018-06-16 19:24:48 -07:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-06-26 18:29:54 -07:00
|
|
|
Recall that the `Sequence` is expected to increment every time a
|
|
|
|
message is signed by a given account in order to prevent "replay attacks" where
|
|
|
|
the same message could be executed over and over again. The `AccountNumber` is
|
|
|
|
assigned when the account is created or recreated after being emptied.
|
2018-06-16 19:24:48 -07:00
|
|
|
|
|
|
|
The `StdSignature` can also optionally include the public key for verifying the
|
2018-06-26 18:29:54 -07:00
|
|
|
signature. The public key only needs to be included the first time a transaction
|
|
|
|
is sent from a given account - from then on it will be stored in the `Account`
|
|
|
|
and can be left out of transactions.
|
2018-06-16 19:24:48 -07:00
|
|
|
|
2018-06-26 18:29:54 -07:00
|
|
|
The fee is provided in a standard form as `StdFee`:
|
2018-06-16 19:24:48 -07:00
|
|
|
|
|
|
|
```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"`
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-06-26 18:29:54 -07:00
|
|
|
Note that the address responsible for paying the transactions fee is the first address
|
|
|
|
returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx)` is provided
|
|
|
|
to return this.
|
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
### Signing
|
2018-06-26 18:29:54 -07:00
|
|
|
|
|
|
|
The standard bytes for signers to sign over is provided by:
|
|
|
|
|
|
|
|
```go
|
|
|
|
TODO
|
|
|
|
```
|
|
|
|
|
2018-06-16 19:24:48 -07:00
|
|
|
## AnteHandler
|
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
TODO
|
2018-06-26 14:21:46 -07:00
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
## App3
|
2018-06-26 14:21:46 -07:00
|
|
|
|
2018-06-26 19:49:13 -07:00
|
|
|
Putting it all together, we get:
|
2018-06-26 14:21:46 -07:00
|
|
|
|
|
|
|
```go
|
2018-06-26 19:49:13 -07:00
|
|
|
TODO
|
2018-06-26 14:21:46 -07:00
|
|
|
```
|