2017-06-30 11:55:23 -07:00
|
|
|
package coin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
wire "github.com/tendermint/go-wire"
|
|
|
|
|
|
|
|
"github.com/tendermint/basecoin"
|
|
|
|
"github.com/tendermint/basecoin/errors"
|
2017-07-06 05:23:38 -07:00
|
|
|
"github.com/tendermint/basecoin/state"
|
2017-06-30 11:55:23 -07:00
|
|
|
)
|
|
|
|
|
2017-07-06 02:30:03 -07:00
|
|
|
// GetAccount - Get account from store and address
|
2017-07-11 06:11:10 -07:00
|
|
|
func GetAccount(store state.KVStore, addr basecoin.Actor) (Account, error) {
|
|
|
|
acct, err := loadAccount(store, addr.Bytes())
|
2017-07-04 20:28:27 -07:00
|
|
|
|
2017-07-03 05:50:33 -07:00
|
|
|
// for empty accounts, don't return an error, but rather an empty account
|
|
|
|
if IsNoAccountErr(err) {
|
|
|
|
err = nil
|
|
|
|
}
|
|
|
|
return acct, err
|
2017-06-30 11:55:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// CheckCoins makes sure there are funds, but doesn't change anything
|
2017-07-12 09:54:07 -07:00
|
|
|
func CheckCoins(store state.KVStore, addr basecoin.Actor, coins Coins) (Coins, error) {
|
|
|
|
acct, err := updateCoins(store, addr, coins)
|
2017-06-30 11:55:23 -07:00
|
|
|
return acct.Coins, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChangeCoins changes the money, returns error if it would be negative
|
2017-07-12 09:54:07 -07:00
|
|
|
func ChangeCoins(store state.KVStore, addr basecoin.Actor, coins Coins) (Coins, error) {
|
|
|
|
acct, err := updateCoins(store, addr, coins)
|
2017-06-30 11:55:23 -07:00
|
|
|
if err != nil {
|
|
|
|
return acct.Coins, err
|
|
|
|
}
|
|
|
|
|
2017-07-11 06:11:10 -07:00
|
|
|
err = storeAccount(store, addr.Bytes(), acct)
|
2017-06-30 11:55:23 -07:00
|
|
|
return acct.Coins, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// updateCoins will load the account, make all checks, and return the updated account.
|
|
|
|
//
|
|
|
|
// it doesn't save anything, that is up to you to decide (Check/Change Coins)
|
2017-07-12 09:54:07 -07:00
|
|
|
func updateCoins(store state.KVStore, addr basecoin.Actor, coins Coins) (acct Account, err error) {
|
2017-07-11 06:11:10 -07:00
|
|
|
acct, err = loadAccount(store, addr.Bytes())
|
2017-07-03 06:33:59 -07:00
|
|
|
// we can increase an empty account...
|
|
|
|
if IsNoAccountErr(err) && coins.IsPositive() {
|
|
|
|
err = nil
|
|
|
|
}
|
2017-06-30 11:55:23 -07:00
|
|
|
if err != nil {
|
|
|
|
return acct, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// check amount
|
2017-07-03 06:33:59 -07:00
|
|
|
final := acct.Coins.Plus(coins)
|
2017-06-30 11:55:23 -07:00
|
|
|
if !final.IsNonnegative() {
|
2017-07-03 05:50:33 -07:00
|
|
|
return acct, ErrInsufficientFunds()
|
2017-06-30 11:55:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
acct.Coins = final
|
|
|
|
return acct, nil
|
|
|
|
}
|
|
|
|
|
2017-07-06 02:30:03 -07:00
|
|
|
// Account - coin account structure
|
2017-06-30 11:55:23 -07:00
|
|
|
type Account struct {
|
2017-07-06 05:59:45 -07:00
|
|
|
Coins Coins `json:"coins"`
|
|
|
|
Sequence int `json:"sequence"`
|
2017-06-30 11:55:23 -07:00
|
|
|
}
|
|
|
|
|
2017-07-06 05:23:38 -07:00
|
|
|
func loadAccount(store state.KVStore, key []byte) (acct Account, err error) {
|
2017-07-04 03:22:06 -07:00
|
|
|
// fmt.Printf("load: %X\n", key)
|
2017-06-30 11:55:23 -07:00
|
|
|
data := store.Get(key)
|
|
|
|
if len(data) == 0 {
|
2017-07-03 05:50:33 -07:00
|
|
|
return acct, ErrNoAccount()
|
2017-06-30 11:55:23 -07:00
|
|
|
}
|
|
|
|
err = wire.ReadBinaryBytes(data, &acct)
|
|
|
|
if err != nil {
|
|
|
|
msg := fmt.Sprintf("Error reading account %X", key)
|
2017-07-03 05:50:33 -07:00
|
|
|
return acct, errors.ErrInternal(msg)
|
2017-06-30 11:55:23 -07:00
|
|
|
}
|
|
|
|
return acct, nil
|
|
|
|
}
|
|
|
|
|
2017-07-06 05:23:38 -07:00
|
|
|
func storeAccount(store state.KVStore, key []byte, acct Account) error {
|
2017-07-04 03:22:06 -07:00
|
|
|
// fmt.Printf("store: %X\n", key)
|
2017-06-30 11:55:23 -07:00
|
|
|
bin := wire.BinaryBytes(acct)
|
|
|
|
store.Set(key, bin)
|
|
|
|
return nil // real stores can return error...
|
|
|
|
}
|