update/finish app1 go and md
This commit is contained in:
parent
354f9760f8
commit
fc81c14a16
|
@ -243,7 +243,7 @@ Note this handler has unfettered access to the store specified by the capability
|
||||||
For this first example, we will define a simple account that is JSON encoded:
|
For this first example, we will define a simple account that is JSON encoded:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type acc struct {
|
type app1Account struct {
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -256,35 +256,105 @@ Now we're ready to handle the MsgSend:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Handle MsgSend.
|
// Handle MsgSend.
|
||||||
|
// NOTE: msg.From, msg.To, and msg.Amount were already validated
|
||||||
func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result {
|
func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result {
|
||||||
// NOTE: from, to, and amount were already validated
|
// Load the store.
|
||||||
|
|
||||||
store := ctx.KVStore(key)
|
store := ctx.KVStore(key)
|
||||||
bz := store.Get(msg.From)
|
|
||||||
if bz == nil {
|
// Debit from the sender.
|
||||||
// TODO
|
if res := handleFrom(store, msg.From, msg.Amount); !res.IsOK() {
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
var acc acc
|
// Credit the receiver.
|
||||||
err := json.Unmarshal(bz, &acc)
|
if res := handleTo(store, msg.To, msg.Amount); !res.IsOK() {
|
||||||
if err != nil {
|
return res
|
||||||
// InternalError
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: finish the logic
|
// Return a success (Code 0).
|
||||||
|
// Add list of key-value pair descriptors ("tags").
|
||||||
return sdk.Result{
|
return sdk.Result{
|
||||||
// TODO: Tags
|
Tags: msg.Tags(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The handler is straight forward:
|
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:
|
||||||
|
|
||||||
- get the KVStore from the context using the granted capability key
|
```go
|
||||||
- lookup the From address in the KVStore, and JSON unmarshal it into an `acc`,
|
func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result {
|
||||||
- check that the account balance is greater than the `msg.Amount`
|
// Get sender account from the store.
|
||||||
- transfer the `msg.Amount`
|
accBytes := store.Get(from)
|
||||||
|
if accBytes == nil {
|
||||||
|
// Account was not added to store. Return the result of the error.
|
||||||
|
return sdk.NewError(2, 101, "Account not added to store").Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal the JSON account bytes.
|
||||||
|
var acc app1Account
|
||||||
|
err := json.Unmarshal(accBytes, &acc)
|
||||||
|
if err != nil {
|
||||||
|
// InternalError
|
||||||
|
return sdk.ErrInternal("Error when deserializing account").Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduct msg amount from sender account.
|
||||||
|
senderCoins := acc.Coins.Minus(amt)
|
||||||
|
|
||||||
|
// If any coin has negative amount, return insufficient coins error.
|
||||||
|
if !senderCoins.IsNotNegative() {
|
||||||
|
return sdk.ErrInsufficientCoins("Insufficient coins in account").Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set acc coins to new amount.
|
||||||
|
acc.Coins = senderCoins
|
||||||
|
|
||||||
|
// Encode sender account.
|
||||||
|
accBytes, err = json.Marshal(acc)
|
||||||
|
if err != nil {
|
||||||
|
return sdk.ErrInternal("Account encoding error").Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update store with updated sender account
|
||||||
|
store.Set(from, accBytes)
|
||||||
|
return sdk.Result{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result {
|
||||||
|
// Add msg amount to receiver account
|
||||||
|
accBytes := store.Get(to)
|
||||||
|
var acc app1Account
|
||||||
|
if accBytes == nil {
|
||||||
|
// Receiver account does not already exist, create a new one.
|
||||||
|
acc = app1Account{}
|
||||||
|
} else {
|
||||||
|
// Receiver account already exists. Retrieve and decode it.
|
||||||
|
err := json.Unmarshal(accBytes, &acc)
|
||||||
|
if err != nil {
|
||||||
|
return sdk.ErrInternal("Account decoding error").Result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add amount to receiver's old coins
|
||||||
|
receiverCoins := acc.Coins.Plus(amt)
|
||||||
|
|
||||||
|
// Update receiver account
|
||||||
|
acc.Coins = receiverCoins
|
||||||
|
|
||||||
|
// Encode receiver account
|
||||||
|
accBytes, err := json.Marshal(acc)
|
||||||
|
if err != nil {
|
||||||
|
return sdk.ErrInternal("Account encoding error").Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update store with updated receiver account
|
||||||
|
store.Set(to, accBytes)
|
||||||
|
return sdk.Result{}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
And that's that!
|
And that's that!
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,12 @@ func (msg MsgSend) GetSigners() []sdk.Address {
|
||||||
return []sdk.Address{msg.From}
|
return []sdk.Address{msg.From}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the sdk.Tags for the message
|
||||||
|
func (msg MsgSend) Tags() sdk.Tags {
|
||||||
|
return sdk.NewTags("sender", []byte(msg.From.String())).
|
||||||
|
AppendTag("receiver", []byte(msg.To.String()))
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
// Handler for the message
|
// Handler for the message
|
||||||
|
|
||||||
|
@ -112,78 +118,99 @@ func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle MsgSend.
|
// Handle MsgSend.
|
||||||
|
// NOTE: msg.From, msg.To, and msg.Amount were already validated
|
||||||
func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result {
|
func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result {
|
||||||
// NOTE: from, to, and amount were already validated
|
// Load the store.
|
||||||
store := ctx.KVStore(key)
|
store := ctx.KVStore(key)
|
||||||
|
|
||||||
// deduct msg amount from sender account
|
// Debit from the sender.
|
||||||
bz := store.Get(msg.From)
|
if res := handleFrom(store, msg.From, msg.Amount); !res.IsOK() {
|
||||||
if bz == nil {
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit the receiver.
|
||||||
|
if res := handleTo(store, msg.To, msg.Amount); !res.IsOK() {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a success (Code 0).
|
||||||
|
// Add list of key-value pair descriptors ("tags").
|
||||||
|
return sdk.Result{
|
||||||
|
Tags: msg.Tags(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result {
|
||||||
|
// Get sender account from the store.
|
||||||
|
accBytes := store.Get(from)
|
||||||
|
if accBytes == nil {
|
||||||
// Account was not added to store. Return the result of the error.
|
// Account was not added to store. Return the result of the error.
|
||||||
return sdk.NewError(2, 101, "Account not added to store").Result()
|
return sdk.NewError(2, 101, "Account not added to store").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
var acc account
|
// Unmarshal the JSON account bytes.
|
||||||
err := json.Unmarshal(bz, &acc)
|
var acc app1Account
|
||||||
|
err := json.Unmarshal(accBytes, &acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// InternalError
|
// InternalError
|
||||||
return sdk.ErrInternal("Error when deserializing account").Result()
|
return sdk.ErrInternal("Error when deserializing account").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: finish the logic
|
// Deduct msg amount from sender account.
|
||||||
senderCoins := acc.Coins.Minus(msg.Amount)
|
senderCoins := acc.Coins.Minus(amt)
|
||||||
|
|
||||||
// If any coin has negative amount, return insufficient coins error.
|
// If any coin has negative amount, return insufficient coins error.
|
||||||
if !senderCoins.IsNotNegative() {
|
if !senderCoins.IsNotNegative() {
|
||||||
return sdk.ErrInsufficientCoins("Insufficient coins in account").Result()
|
return sdk.ErrInsufficientCoins("Insufficient coins in account").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// set acc coins to new amount
|
// Set acc coins to new amount.
|
||||||
acc.Coins = senderCoins
|
acc.Coins = senderCoins
|
||||||
|
|
||||||
// Encode sender account
|
// Encode sender account.
|
||||||
val, err := json.Marshal(acc)
|
accBytes, err = json.Marshal(acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.ErrInternal("Account encoding error").Result()
|
return sdk.ErrInternal("Account encoding error").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update store with updated sender account
|
// Update store with updated sender account
|
||||||
store.Set(msg.From, val)
|
store.Set(from, accBytes)
|
||||||
|
return sdk.Result{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result {
|
||||||
// Add msg amount to receiver account
|
// Add msg amount to receiver account
|
||||||
bz = store.Get(msg.To)
|
accBytes := store.Get(to)
|
||||||
var acc2 account
|
var acc app1Account
|
||||||
if bz == nil {
|
if accBytes == nil {
|
||||||
// Receiver account does not already exist, create a new one.
|
// Receiver account does not already exist, create a new one.
|
||||||
acc2 = account{}
|
acc = app1Account{}
|
||||||
} else {
|
} else {
|
||||||
// Receiver account already exists. Retrieve and decode it.
|
// Receiver account already exists. Retrieve and decode it.
|
||||||
err = json.Unmarshal(bz, &acc2)
|
err := json.Unmarshal(accBytes, &acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.ErrInternal("Account decoding error").Result()
|
return sdk.ErrInternal("Account decoding error").Result()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add amount to receiver's old coins
|
// Add amount to receiver's old coins
|
||||||
receiverCoins := acc2.Coins.Plus(msg.Amount)
|
receiverCoins := acc.Coins.Plus(amt)
|
||||||
|
|
||||||
// Update receiver account
|
// Update receiver account
|
||||||
acc2.Coins = receiverCoins
|
acc.Coins = receiverCoins
|
||||||
|
|
||||||
// Encode receiver account
|
// Encode receiver account
|
||||||
val, err = json.Marshal(acc2)
|
accBytes, err := json.Marshal(acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.ErrInternal("Account encoding error").Result()
|
return sdk.ErrInternal("Account encoding error").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
store.Set(msg.To, val)
|
// Update store with updated receiver account
|
||||||
|
store.Set(to, accBytes)
|
||||||
return sdk.Result{
|
return sdk.Result{}
|
||||||
// TODO: Tags
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type account struct {
|
type app1Account struct {
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,11 +227,6 @@ func (tx app1Tx) GetMsgs() []sdk.Msg {
|
||||||
return []sdk.Msg{tx.MsgSend}
|
return []sdk.Msg{tx.MsgSend}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove the need for this
|
|
||||||
func (tx app1Tx) GetMemo() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON decode MsgSend.
|
// JSON decode MsgSend.
|
||||||
func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
|
func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||||
var tx app1Tx
|
var tx app1Tx
|
||||||
|
|
Loading…
Reference in New Issue