fill in app3 todos. simplify app3.go
This commit is contained in:
parent
778b102a52
commit
d0efeb1020
|
@ -21,7 +21,8 @@ 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).
|
||||
For more details, see the [x/auth](TODO) and [x/bank](TODO) API documentation.
|
||||
For more details, see the
|
||||
[x/auth](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth) and [x/bank](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) API documentation.
|
||||
|
||||
## Accounts
|
||||
|
||||
|
@ -102,8 +103,7 @@ the `BaseAccount` to store additional data without requiring another lookup from
|
|||
the store.
|
||||
|
||||
Creating an AccountMapper is easy - we just need to specify a codec, a
|
||||
capability key, and a prototype of the object being encoded (TODO: change to
|
||||
constructor):
|
||||
capability key, and a prototype of the object being encoded
|
||||
|
||||
```go
|
||||
accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{})
|
||||
|
@ -124,7 +124,8 @@ load the KVStore from there using the capability key it was granted on creation.
|
|||
Also note that you must explicitly call `SetAccount` after mutating an account
|
||||
for the change to persist!
|
||||
|
||||
See the [AccountMapper API docs](TODO) for more information.
|
||||
See the [AccountMapper API
|
||||
docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth#AccountMapper) for more information.
|
||||
|
||||
## StdTx
|
||||
|
||||
|
@ -200,7 +201,7 @@ transaction fee can be paid, and reject the transaction if not.
|
|||
The `StdTx` supports multiple messages and multiple signers.
|
||||
To sign the transaction, each signer must collect the following information:
|
||||
|
||||
- the ChainID (TODO haven't mentioned this yet)
|
||||
- the ChainID
|
||||
- the AccountNumber and Sequence for the given signer's account (from the
|
||||
blockchain)
|
||||
- the transaction fee
|
||||
|
@ -227,7 +228,6 @@ our own simple `AnteHandler`, the `x/auth` module provides a much more advanced
|
|||
one that uses `AccountMapper` and works with `StdTx`:
|
||||
|
||||
```go
|
||||
TODO: feekeeper :(
|
||||
app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper))
|
||||
```
|
||||
|
||||
|
@ -299,7 +299,8 @@ We can then use it within a handler, instead of working directly with the
|
|||
app.coinKeeper.AddCoins(ctx, addr, coins)
|
||||
```
|
||||
|
||||
See the [bank.Keeper API docs](TODO) for the full set of methods.
|
||||
See the [bank.Keeper API
|
||||
docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#Keeper) for the full set of methods.
|
||||
|
||||
Note we can refine the `bank.Keeper` by restricting it's method set. For
|
||||
instance, the `bank.ViewKeeper` is a read-only version, while the
|
||||
|
|
|
@ -35,8 +35,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
|||
// Set various mappers/keepers to interact easily with underlying stores
|
||||
// TODO: Need to register Account interface or use different Codec
|
||||
accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{})
|
||||
accountKeeper := bank.NewKeeper(accountMapper)
|
||||
metadataMapper := NewApp3MetaDataMapper(keyMain)
|
||||
coinKeeper := bank.NewKeeper(accountMapper)
|
||||
infoMapper := NewCoinInfoMapper(keyMain)
|
||||
feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees)
|
||||
|
||||
app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper))
|
||||
|
@ -44,8 +44,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
|||
// Register message routes.
|
||||
// Note the handler gets access to the account store.
|
||||
app.Router().
|
||||
AddRoute("send", betterHandleMsgSend(accountKeeper)).
|
||||
AddRoute("issue", betterHandleMsgIssue(metadataMapper, accountKeeper))
|
||||
AddRoute("send", handleMsgSendWithKeeper(coinKeeper)).
|
||||
AddRoute("issue", handleMsgIssueWithInfoMapper(infoMapper, coinKeeper))
|
||||
|
||||
// Mount stores and load the latest state.
|
||||
app.MountStoresIAVL(keyAccount, keyMain, keyFees)
|
||||
|
@ -56,7 +56,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
|||
return app
|
||||
}
|
||||
|
||||
func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler {
|
||||
func handleMsgSendWithKeeper(coinKeeper bank.Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
sendMsg, ok := msg.(MsgSend)
|
||||
if !ok {
|
||||
|
@ -64,14 +64,14 @@ func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler {
|
|||
}
|
||||
|
||||
// Subtract coins from sender account
|
||||
_, _, err := accountKeeper.SubtractCoins(ctx, sendMsg.From, sendMsg.Amount)
|
||||
_, _, err := coinKeeper.SubtractCoins(ctx, sendMsg.From, sendMsg.Amount)
|
||||
if err != nil {
|
||||
// if error, return its result
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
// Add coins to receiver account
|
||||
_, _, err = accountKeeper.AddCoins(ctx, sendMsg.To, sendMsg.Amount)
|
||||
_, _, err = coinKeeper.AddCoins(ctx, sendMsg.To, sendMsg.Amount)
|
||||
if err != nil {
|
||||
// if error, return its result
|
||||
return err.Result()
|
||||
|
@ -83,7 +83,7 @@ func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler {
|
|||
}
|
||||
}
|
||||
|
||||
func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler {
|
||||
func handleMsgIssueWithInfoMapper(infoMapper coinInfoMapper, coinKeeper bank.Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
issueMsg, ok := msg.(MsgIssue)
|
||||
if !ok {
|
||||
|
@ -91,107 +91,70 @@ func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keep
|
|||
}
|
||||
|
||||
// Handle updating metadata
|
||||
if res := betterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() {
|
||||
if res := handleCoinInfoWithMapper(ctx, infoMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() {
|
||||
return res
|
||||
}
|
||||
|
||||
// Add newly issued coins to output address
|
||||
_, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin})
|
||||
_, _, err := coinKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin})
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
return sdk.Result{
|
||||
// Return result with Issue msg tags
|
||||
Tags: issueMsg.Tags(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func betterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result {
|
||||
metadata := metadataMapper.GetMetaData(ctx, coin.Denom)
|
||||
func handleCoinInfoWithMapper(ctx sdk.Context, infoMapper CoinInfoMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result {
|
||||
coinInfo := infoMapper.GetInfo(ctx, coin.Denom)
|
||||
|
||||
// Metadata was created fresh, should set issuer to msg issuer
|
||||
if len(metadata.Issuer) == 0 {
|
||||
metadata.Issuer = issuer
|
||||
if len(coinInfo.Issuer) == 0 {
|
||||
coinInfo.Issuer = issuer
|
||||
}
|
||||
|
||||
// Msg Issuer is not authorized to issue these coins
|
||||
if !bytes.Equal(metadata.Issuer, issuer) {
|
||||
if !bytes.Equal(coinInfo.Issuer, issuer) {
|
||||
return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result()
|
||||
}
|
||||
|
||||
// Update current circulating supply
|
||||
metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount)
|
||||
|
||||
// Current supply cannot exceed total supply
|
||||
if metadata.TotalSupply.LT(metadata.CurrentSupply) {
|
||||
return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result()
|
||||
}
|
||||
|
||||
metadataMapper.SetMetaData(ctx, coin.Denom, metadata)
|
||||
return sdk.Result{}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Mapper for Coin Metadata
|
||||
// Mapper for CoinInfo
|
||||
|
||||
// Example of a very simple user-defined mapper interface
|
||||
type MetaDataMapper interface {
|
||||
GetMetaData(sdk.Context, string) CoinMetadata
|
||||
SetMetaData(sdk.Context, string, CoinMetadata)
|
||||
// Example of a very simple user-defined read-only mapper interface.
|
||||
type CoinInfoMapper interface {
|
||||
GetInfo(sdk.Context, string) coinInfo
|
||||
}
|
||||
|
||||
// Implements MetaDataMapper
|
||||
type App3MetaDataMapper struct {
|
||||
mainKey *sdk.KVStoreKey
|
||||
// Implements CoinInfoMapper.
|
||||
type coinInfoMapper struct {
|
||||
key *sdk.KVStoreKey
|
||||
}
|
||||
|
||||
// Construct new App3MetaDataMapper
|
||||
func NewApp3MetaDataMapper(key *sdk.KVStoreKey) App3MetaDataMapper {
|
||||
return App3MetaDataMapper{mainKey: key}
|
||||
// Construct new CoinInfoMapper.
|
||||
func NewCoinInfoMapper(key *sdk.KVStoreKey) coinInfoMapper {
|
||||
return coinInfoMapper{key: key}
|
||||
}
|
||||
|
||||
// Implements MetaDataMpper. Returns metadata for coin
|
||||
// If metadata does not exist in store, function creates default metadata and returns it
|
||||
// without adding it to the store.
|
||||
func (mdm App3MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata {
|
||||
store := ctx.KVStore(mdm.mainKey)
|
||||
// Implements CoinInfoMapper. Returns info for coin.
|
||||
func (cim coinInfoMapper) GetInfo(ctx sdk.Context, denom string) coinInfo {
|
||||
store := ctx.KVStore(cim.key)
|
||||
|
||||
bz := store.Get([]byte(denom))
|
||||
if bz == nil {
|
||||
// Coin metadata doesn't exist, create new metadata with default params
|
||||
return CoinMetadata{
|
||||
TotalSupply: sdk.NewInt(1000000),
|
||||
}
|
||||
infoBytes := store.Get([]byte(denom))
|
||||
if infoBytes == nil {
|
||||
// TODO
|
||||
}
|
||||
|
||||
var metadata CoinMetadata
|
||||
err := json.Unmarshal(bz, &metadata)
|
||||
var coinInfo coinInfo
|
||||
err := json.Unmarshal(infoBytes, &coinInfo)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return metadata
|
||||
return coinInfo
|
||||
}
|
||||
|
||||
// Implements MetaDataMapper. Sets metadata in store with key equal to denom.
|
||||
func (mdm App3MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) {
|
||||
store := ctx.KVStore(mdm.mainKey)
|
||||
|
||||
val, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
store.Set([]byte(denom), val)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// StdTx
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Account
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Ante Handler
|
||||
|
|
Loading…
Reference in New Issue