129 lines
3.0 KiB
Go
129 lines
3.0 KiB
Go
package coin
|
|
|
|
import (
|
|
"github.com/tendermint/go-wire/data"
|
|
"github.com/tendermint/tmlibs/log"
|
|
|
|
"github.com/tendermint/basecoin"
|
|
"github.com/tendermint/basecoin/errors"
|
|
"github.com/tendermint/basecoin/modules/auth"
|
|
"github.com/tendermint/basecoin/state"
|
|
)
|
|
|
|
//NameCoin - name space of the coin module
|
|
const NameCoin = "coin"
|
|
|
|
// Handler includes an accountant
|
|
type Handler struct {
|
|
Accountant
|
|
}
|
|
|
|
var _ basecoin.Handler = Handler{}
|
|
|
|
// NewHandler - new accountant handler for the coin module
|
|
func NewHandler() Handler {
|
|
return Handler{
|
|
Accountant: NewAccountant(""),
|
|
}
|
|
}
|
|
|
|
// Name - return name space
|
|
func (Handler) Name() string {
|
|
return NameCoin
|
|
}
|
|
|
|
// CheckTx checks if there is enough money in the account
|
|
func (h Handler) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
|
send, err := checkTx(ctx, tx)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
// now make sure there is money
|
|
for _, in := range send.Inputs {
|
|
_, err = h.CheckCoins(store, in.Address, in.Coins.Negative(), in.Sequence)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
// otherwise, we are good
|
|
return res, nil
|
|
}
|
|
|
|
// DeliverTx moves the money
|
|
func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
|
send, err := checkTx(ctx, tx)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
// deduct from all input accounts
|
|
for _, in := range send.Inputs {
|
|
_, err = h.ChangeCoins(store, in.Address, in.Coins.Negative(), in.Sequence)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
// add to all output accounts
|
|
for _, out := range send.Outputs {
|
|
// note: sequence number is ignored when adding coins, only checked for subtracting
|
|
_, err = h.ChangeCoins(store, out.Address, out.Coins, 0)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
// a-ok!
|
|
return basecoin.Result{}, nil
|
|
}
|
|
|
|
// SetOption - sets the genesis account balance
|
|
func (h Handler) SetOption(l log.Logger, store state.KVStore, module, key, value string) (log string, err error) {
|
|
if module != NameCoin {
|
|
return "", errors.ErrUnknownModule(module)
|
|
}
|
|
if key == "account" {
|
|
var acc GenesisAccount
|
|
err = data.FromJSON([]byte(value), &acc)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
acc.Balance.Sort()
|
|
addr, err := acc.GetAddr()
|
|
if err != nil {
|
|
return "", ErrInvalidAddress()
|
|
}
|
|
// this sets the permission for a public key signature, use that app
|
|
actor := auth.SigPerm(addr)
|
|
err = storeAccount(store, h.MakeKey(actor), acc.ToAccount())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return "Success", nil
|
|
|
|
}
|
|
return "", errors.ErrUnknownKey(key)
|
|
}
|
|
|
|
func checkTx(ctx basecoin.Context, tx basecoin.Tx) (send SendTx, err error) {
|
|
// check if the tx is proper type and valid
|
|
send, ok := tx.Unwrap().(SendTx)
|
|
if !ok {
|
|
return send, errors.ErrInvalidFormat(tx)
|
|
}
|
|
err = send.ValidateBasic()
|
|
if err != nil {
|
|
return send, err
|
|
}
|
|
|
|
// check if all inputs have permission
|
|
for _, in := range send.Inputs {
|
|
if !ctx.HasPermission(in.Address) {
|
|
return send, errors.ErrUnauthorized()
|
|
}
|
|
}
|
|
return send, nil
|
|
}
|