Rough draft of the new coins storage
This commit is contained in:
parent
673b51f3b0
commit
2fc4da1076
|
@ -1,6 +1,7 @@
|
|||
package basecoin
|
||||
|
||||
import (
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-wire/data"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
@ -20,6 +21,10 @@ func NewActor(app string, addr []byte) Actor {
|
|||
return Actor{App: app, Address: addr}
|
||||
}
|
||||
|
||||
func (a Actor) Bytes() []byte {
|
||||
return wire.BinaryBytes(a)
|
||||
}
|
||||
|
||||
// Context is an interface, so we can implement "secure" variants that
|
||||
// rely on private fields to control the actions
|
||||
type Context interface {
|
||||
|
|
|
@ -20,6 +20,7 @@ const (
|
|||
msgInvalidSequence = "Invalid Sequence"
|
||||
msgInvalidSignature = "Invalid Signature"
|
||||
msgInsufficientFees = "Insufficient Fees"
|
||||
msgInsufficientFunds = "Insufficient Funds"
|
||||
msgNoInputs = "No Input Coins"
|
||||
msgNoOutputs = "No Output Coins"
|
||||
msgTooLarge = "Input size too large"
|
||||
|
@ -88,6 +89,10 @@ func InsufficientFees() TMError {
|
|||
return New(msgInsufficientFees, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
||||
func InsufficientFunds() TMError {
|
||||
return New(msgInsufficientFunds, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
||||
func NoInputs() TMError {
|
||||
return New(msgNoInputs, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package coin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
type Accountant struct {
|
||||
Prefix []byte
|
||||
}
|
||||
|
||||
func (a Accountant) GetAccount(store types.KVStore, addr basecoin.Actor) (Account, error) {
|
||||
// TODO: how to handle empty accounts??
|
||||
return loadAccount(store, a.makeKey(addr))
|
||||
}
|
||||
|
||||
// CheckCoins makes sure there are funds, but doesn't change anything
|
||||
func (a Accountant) CheckCoins(store types.KVStore, addr basecoin.Actor, coins types.Coins, seq int) (types.Coins, error) {
|
||||
acct, err := a.updateCoins(store, addr, coins, seq)
|
||||
return acct.Coins, err
|
||||
}
|
||||
|
||||
// ChangeCoins changes the money, returns error if it would be negative
|
||||
func (a Accountant) ChangeCoins(store types.KVStore, addr basecoin.Actor, coins types.Coins, seq int) (types.Coins, error) {
|
||||
acct, err := a.updateCoins(store, addr, coins, seq)
|
||||
if err != nil {
|
||||
return acct.Coins, err
|
||||
}
|
||||
|
||||
err = storeAccount(store, a.makeKey(addr), acct)
|
||||
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)
|
||||
func (a Accountant) updateCoins(store types.KVStore, addr basecoin.Actor, coins types.Coins, seq int) (acct Account, err error) {
|
||||
acct, err = loadAccount(store, a.makeKey(addr))
|
||||
if err != nil {
|
||||
return acct, err
|
||||
}
|
||||
|
||||
// check sequence
|
||||
if seq != acct.Sequence+1 {
|
||||
return acct, errors.InvalidSequence()
|
||||
}
|
||||
acct.Sequence += 1
|
||||
|
||||
// check amount
|
||||
final := acct.Coins.Minus(coins)
|
||||
if !final.IsNonnegative() {
|
||||
return acct, errors.InsufficientFunds()
|
||||
}
|
||||
|
||||
acct.Coins = final
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
func (a Accountant) makeKey(addr basecoin.Actor) []byte {
|
||||
key := addr.Bytes()
|
||||
if len(a.Prefix) > 0 {
|
||||
key = append(a.Prefix, key...)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
Coins types.Coins `json:"coins"`
|
||||
Sequence int `json:"seq"`
|
||||
}
|
||||
|
||||
func loadAccount(store types.KVStore, key []byte) (acct Account, err error) {
|
||||
data := store.Get(key)
|
||||
if len(data) == 0 {
|
||||
// TODO: error or empty????
|
||||
return acct, errors.InternalError("No account found")
|
||||
}
|
||||
err = wire.ReadBinaryBytes(data, &acct)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error reading account %X", key)
|
||||
return acct, errors.InternalError(msg)
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
func storeAccount(store types.KVStore, key []byte, acct Account) error {
|
||||
bin := wire.BinaryBytes(acct)
|
||||
store.Set(key, bin)
|
||||
return nil // real stores can return error...
|
||||
}
|
Loading…
Reference in New Issue