From 778b102a52f9e6e805a5dd1eedbe75ef787ca123 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 28 Jun 2018 20:08:38 -0400 Subject: [PATCH] more app1/app2 cleanup --- docs/core/app1.md | 64 +++++++++++++++----------------------- docs/core/app2.md | 26 +++++++++++----- docs/core/examples/app2.go | 19 ++++++++--- 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 4242348cd..ef56b5081 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -229,41 +229,6 @@ us to easily lookup transactions that pertain to particular accounts or actions. Let's define our handler for App1: -```go -func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgSend: - return handleMsgSend(ctx, keyAcc, msg) - default: - errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} -``` - -We have only a single message type, so just one message-specific function to define, `handleMsgSend`. - -Note this handler has unrestricted access to the store specified by the capability key `keyAcc`, -so it must define what to store and how to encode it. Later, we'll introduce -higher-level abstractions so Handlers are restricted in what they can do. -For this first example, we use a simple account that is JSON encoded: - -```go -type appAccount struct { - Coins sdk.Coins `json:"coins"` -} -``` - -Coins is a useful type provided by the SDK for multi-asset accounts. -We could just use an integer here for a single coin type, but -it's worth [getting to know -Coins](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Coins). - - -Now we're ready to handle the MsgSend: - ```go // Handle MsgSend. // NOTE: msg.From, msg.To, and msg.Amount were already validated @@ -290,10 +255,26 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result } ``` -The handler is straight forward. We first load the KVStore from the context using the granted capability key. -Then we make two state transitions: one for the sender, one for the receiver. -Each one involves JSON unmarshalling the account bytes from the store, mutating -the `Coins`, and JSON marshalling back into the store: +We have only a single message type, so just one message-specific function to define, `handleMsgSend`. + +Note this handler has unrestricted access to the store specified by the capability key `keyAcc`, +so it must define what to store and how to encode it. Later, we'll introduce +higher-level abstractions so Handlers are restricted in what they can do. +For this first example, we use a simple account that is JSON encoded: + +```go +type appAccount struct { + Coins sdk.Coins `json:"coins"` +} +``` + +Coins is a useful type provided by the SDK for multi-asset accounts. +We could just use an integer here for a single coin type, but +it's worth [getting to know +Coins](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Coins). + + +Now we're ready to handle the two parts of the MsgSend: ```go func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { @@ -367,6 +348,11 @@ func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { } ``` +The handler is straight forward. We first load the KVStore from the context using the granted capability key. +Then we make two state transitions: one for the sender, one for the receiver. +Each one involves JSON unmarshalling the account bytes from the store, mutating +the `Coins`, and JSON marshalling back into the store. + And that's that! ## Tx diff --git a/docs/core/app2.md b/docs/core/app2.md index d245aea41..f87ff557f 100644 --- a/docs/core/app2.md +++ b/docs/core/app2.md @@ -74,24 +74,36 @@ func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handle func handleIssuer(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { // the issuer address is stored directly under the coin denomination denom := []byte(coin.Denom) - issuerAddress := store.Get(denom) - if issuerAddress == nil { + infoBytes := store.Get(denom) + if infoBytes == nil { return sdk.ErrInvalidCoins(fmt.Sprintf("Unknown coin type %s", coin.Denom)).Result() } + var coinInfo coinInfo + err := json.Unmarshal(infoBytes, &coinInfo) + if err != nil { + return sdk.ErrInternal("Error when deserializing coinInfo").Result() + } + // Msg Issuer is not authorized to issue these coins - if !bytes.Equal(issuerAddress, issuer) { + if !bytes.Equal(coinInfo.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } return sdk.Result{} } + +// coinInfo stores meta data about a coin +type coinInfo struct { + Issuer sdk.Address `json:"issuer"` +} ``` -Note we're just storing the issuer address for each coin directly under the -coin's denomination in the issuer store. We could of course use a struct with more -fields, like the current supply of coins in existence, and the maximum supply -allowed to be issued. +Note we've introduced the `coinInfo` type to store the issuer address for each coin. +We JSON serialize this type and store it directly under the denomination in the +issuer store. We could of course add more fields and logic around this, +like including the current supply of coins in existence, and enforcing a maximum supply, +but that's left as an excercise for the reader :). ## Amino diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index 2c10299c5..ff9baa7bc 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -117,7 +117,7 @@ func (msg MsgIssue) Tags() sdk.Tags { //------------------------------------------------------------------ // Handler for the message -// Handle MsgIssue +// Handle MsgIssue. func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { issueMsg, ok := msg.(MsgIssue) @@ -149,19 +149,30 @@ func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handle func handleIssuer(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { // the issuer address is stored directly under the coin denomination denom := []byte(coin.Denom) - issuerAddress := store.Get(denom) - if issuerAddress == nil { + infoBytes := store.Get(denom) + if infoBytes == nil { return sdk.ErrInvalidCoins(fmt.Sprintf("Unknown coin type %s", coin.Denom)).Result() } + var coinInfo coinInfo + err := json.Unmarshal(infoBytes, &coinInfo) + if err != nil { + return sdk.ErrInternal("Error when deserializing coinInfo").Result() + } + // Msg Issuer is not authorized to issue these coins - if !bytes.Equal(issuerAddress, issuer) { + if !bytes.Equal(coinInfo.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } return sdk.Result{} } +// coinInfo stores meta data about a coin +type coinInfo struct { + Issuer sdk.Address `json:"issuer"` +} + //------------------------------------------------------------------ // Tx