Complete error package overhaul
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
package coin
|
||||
|
||||
import (
|
||||
rawerr "errors"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoAccount = rawerr.New("No such account")
|
||||
errInsufficientFunds = rawerr.New("Insufficient Funds")
|
||||
errNoInputs = rawerr.New("No Input Coins")
|
||||
errNoOutputs = rawerr.New("No Output Coins")
|
||||
errInvalidAddress = rawerr.New("Invalid Address")
|
||||
errInvalidCoins = rawerr.New("Invalid Coins")
|
||||
errInvalidSequence = rawerr.New("Invalid Sequence")
|
||||
)
|
||||
|
||||
var (
|
||||
invalidInput = abci.CodeType_BaseInvalidInput
|
||||
invalidOutput = abci.CodeType_BaseInvalidOutput
|
||||
unknownAddress = abci.CodeType_BaseUnknownAddress
|
||||
)
|
||||
|
||||
// here are some generic handlers to grab classes of errors based on code
|
||||
func IsInputErr(err error) bool {
|
||||
return errors.HasErrorCode(err, invalidInput)
|
||||
}
|
||||
func IsOutputErr(err error) bool {
|
||||
return errors.HasErrorCode(err, invalidOutput)
|
||||
}
|
||||
func IsAddressErr(err error) bool {
|
||||
return errors.HasErrorCode(err, unknownAddress)
|
||||
}
|
||||
func IsCoinErr(err error) bool {
|
||||
return err != nil && (IsInputErr(err) || IsOutputErr(err) || IsAddressErr(err))
|
||||
}
|
||||
|
||||
func ErrNoAccount() errors.TMError {
|
||||
return errors.WithCode(errNoAccount, unknownAddress)
|
||||
}
|
||||
|
||||
func IsNoAccountErr(err error) bool {
|
||||
return errors.IsSameError(errNoAccount, err)
|
||||
}
|
||||
|
||||
func ErrInvalidAddress() errors.TMError {
|
||||
return errors.WithCode(errInvalidAddress, invalidInput)
|
||||
}
|
||||
func IsInvalidAddressErr(err error) bool {
|
||||
return errors.IsSameError(errInvalidAddress, err)
|
||||
}
|
||||
|
||||
func ErrInvalidCoins() errors.TMError {
|
||||
return errors.WithCode(errInvalidCoins, invalidInput)
|
||||
}
|
||||
func IsInvalidCoinsErr(err error) bool {
|
||||
return errors.IsSameError(errInvalidCoins, err)
|
||||
}
|
||||
|
||||
func ErrInvalidSequence() errors.TMError {
|
||||
return errors.WithCode(errInvalidSequence, invalidInput)
|
||||
}
|
||||
func IsInvalidSequenceErr(err error) bool {
|
||||
return errors.IsSameError(errInvalidSequence, err)
|
||||
}
|
||||
|
||||
func ErrInsufficientFunds() errors.TMError {
|
||||
return errors.WithCode(errInsufficientFunds, invalidInput)
|
||||
}
|
||||
func IsInsufficientFundsErr(err error) bool {
|
||||
return errors.IsSameError(errInsufficientFunds, err)
|
||||
}
|
||||
|
||||
func ErrNoInputs() errors.TMError {
|
||||
return errors.WithCode(errNoInputs, invalidInput)
|
||||
}
|
||||
func IsNoInputsErr(err error) bool {
|
||||
return errors.IsSameError(errNoInputs, err)
|
||||
}
|
||||
|
||||
func ErrNoOutputs() errors.TMError {
|
||||
return errors.WithCode(errNoOutputs, invalidOutput)
|
||||
}
|
||||
func IsNoOutputsErr(err error) bool {
|
||||
return errors.IsSameError(errNoOutputs, err)
|
||||
}
|
||||
+11
-3
@@ -11,10 +11,18 @@ const (
|
||||
)
|
||||
|
||||
// Handler writes
|
||||
type Handler struct{}
|
||||
type Handler struct {
|
||||
Accountant
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = Handler{}
|
||||
|
||||
func NewHandler() Handler {
|
||||
return Handler{
|
||||
Accountant: Accountant{Prefix: []byte(NameCoin + "/")},
|
||||
}
|
||||
}
|
||||
|
||||
func (_ Handler) Name() string {
|
||||
return NameCoin
|
||||
}
|
||||
@@ -47,7 +55,7 @@ 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.UnknownTxType(tx)
|
||||
return send, errors.ErrInvalidFormat(tx)
|
||||
}
|
||||
err = send.ValidateBasic()
|
||||
if err != nil {
|
||||
@@ -57,7 +65,7 @@ func checkTx(ctx basecoin.Context, tx basecoin.Tx) (send SendTx, err error) {
|
||||
// check if all inputs have permission
|
||||
for _, in := range send.Inputs {
|
||||
if !ctx.HasPermission(in.Address) {
|
||||
return send, errors.Unauthorized()
|
||||
return send, errors.ErrUnauthorized()
|
||||
}
|
||||
}
|
||||
return send, nil
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func TestHandlerPermissions(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
// TODO: need to update this when we actually have token store
|
||||
h := Handler{}
|
||||
h := NewHandler()
|
||||
|
||||
// these are all valid, except for minusCoins
|
||||
addr1 := basecoin.Actor{App: "coin", Address: []byte{1, 2}}
|
||||
|
||||
+10
-7
@@ -15,8 +15,12 @@ type Accountant struct {
|
||||
}
|
||||
|
||||
func (a Accountant) GetAccount(store types.KVStore, addr basecoin.Actor) (Account, error) {
|
||||
// TODO: how to handle empty accounts??
|
||||
return loadAccount(store, a.makeKey(addr))
|
||||
acct, err := loadAccount(store, a.makeKey(addr))
|
||||
// for empty accounts, don't return an error, but rather an empty account
|
||||
if IsNoAccountErr(err) {
|
||||
err = nil
|
||||
}
|
||||
return acct, err
|
||||
}
|
||||
|
||||
// CheckCoins makes sure there are funds, but doesn't change anything
|
||||
@@ -47,14 +51,14 @@ func (a Accountant) updateCoins(store types.KVStore, addr basecoin.Actor, coins
|
||||
|
||||
// check sequence
|
||||
if seq != acct.Sequence+1 {
|
||||
return acct, errors.InvalidSequence()
|
||||
return acct, ErrInvalidSequence()
|
||||
}
|
||||
acct.Sequence += 1
|
||||
|
||||
// check amount
|
||||
final := acct.Coins.Minus(coins)
|
||||
if !final.IsNonnegative() {
|
||||
return acct, errors.InsufficientFunds()
|
||||
return acct, ErrInsufficientFunds()
|
||||
}
|
||||
|
||||
acct.Coins = final
|
||||
@@ -77,13 +81,12 @@ type Account struct {
|
||||
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")
|
||||
return acct, ErrNoAccount()
|
||||
}
|
||||
err = wire.ReadBinaryBytes(data, &acct)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error reading account %X", key)
|
||||
return acct, errors.InternalError(msg)
|
||||
return acct, errors.ErrInternal(msg)
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
+12
-13
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
@@ -29,20 +28,20 @@ type TxInput struct {
|
||||
|
||||
func (txIn TxInput) ValidateBasic() error {
|
||||
if txIn.Address.App == "" {
|
||||
return errors.InvalidAddress()
|
||||
return ErrInvalidAddress()
|
||||
}
|
||||
// TODO: knowledge of app-specific codings?
|
||||
if len(txIn.Address.Address) == 0 {
|
||||
return errors.InvalidAddress()
|
||||
return ErrInvalidAddress()
|
||||
}
|
||||
if !txIn.Coins.IsValid() {
|
||||
return errors.InvalidCoins()
|
||||
return ErrInvalidCoins()
|
||||
}
|
||||
if !txIn.Coins.IsPositive() {
|
||||
return errors.InvalidCoins()
|
||||
return ErrInvalidCoins()
|
||||
}
|
||||
if txIn.Sequence <= 0 {
|
||||
return errors.InvalidSequence()
|
||||
return ErrInvalidSequence()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -69,17 +68,17 @@ type TxOutput struct {
|
||||
|
||||
func (txOut TxOutput) ValidateBasic() error {
|
||||
if txOut.Address.App == "" {
|
||||
return errors.InvalidAddress()
|
||||
return ErrInvalidAddress()
|
||||
}
|
||||
// TODO: knowledge of app-specific codings?
|
||||
if len(txOut.Address.Address) == 0 {
|
||||
return errors.InvalidAddress()
|
||||
return ErrInvalidAddress()
|
||||
}
|
||||
if !txOut.Coins.IsValid() {
|
||||
return errors.InvalidCoins()
|
||||
return ErrInvalidCoins()
|
||||
}
|
||||
if !txOut.Coins.IsPositive() {
|
||||
return errors.InvalidCoins()
|
||||
return ErrInvalidCoins()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -109,10 +108,10 @@ func (tx SendTx) ValidateBasic() error {
|
||||
// this just makes sure all the inputs and outputs are properly formatted,
|
||||
// not that they actually have the money inside
|
||||
if len(tx.Inputs) == 0 {
|
||||
return errors.NoInputs()
|
||||
return ErrNoInputs()
|
||||
}
|
||||
if len(tx.Outputs) == 0 {
|
||||
return errors.NoOutputs()
|
||||
return ErrNoOutputs()
|
||||
}
|
||||
// make sure all inputs and outputs are individually valid
|
||||
var totalIn, totalOut types.Coins
|
||||
@@ -130,7 +129,7 @@ func (tx SendTx) ValidateBasic() error {
|
||||
}
|
||||
// make sure inputs and outputs match
|
||||
if !totalIn.IsEqual(totalOut) {
|
||||
return errors.InvalidCoins()
|
||||
return ErrInvalidCoins()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package fee
|
||||
|
||||
import (
|
||||
rawerr "errors"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
errInsufficientFees = rawerr.New("Insufficient Fees")
|
||||
)
|
||||
|
||||
func ErrInsufficientFees() errors.TMError {
|
||||
return errors.WithCode(errInsufficientFees, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
func IsInsufficientFeesErr(err error) bool {
|
||||
return errors.IsSameError(errInsufficientFees, err)
|
||||
}
|
||||
@@ -36,16 +36,16 @@ var _ stack.Middleware = SimpleFeeHandler{}
|
||||
func (h SimpleFeeHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
||||
feeTx, ok := tx.Unwrap().(*Fee)
|
||||
if !ok {
|
||||
return res, errors.InvalidFormat()
|
||||
return res, errors.ErrInvalidFormat(tx)
|
||||
}
|
||||
|
||||
fees := types.Coins{feeTx.Fee}
|
||||
if !fees.IsGTE(h.MinFee) {
|
||||
return res, errors.InsufficientFees()
|
||||
return res, ErrInsufficientFees()
|
||||
}
|
||||
|
||||
if !ctx.HasPermission(feeTx.Payer) {
|
||||
return res, errors.Unauthorized()
|
||||
return res, errors.ErrUnauthorized()
|
||||
}
|
||||
|
||||
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
||||
@@ -59,16 +59,16 @@ func (h SimpleFeeHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx
|
||||
func (h SimpleFeeHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
||||
feeTx, ok := tx.Unwrap().(*Fee)
|
||||
if !ok {
|
||||
return res, errors.InvalidFormat()
|
||||
return res, errors.ErrInvalidFormat(tx)
|
||||
}
|
||||
|
||||
fees := types.Coins{feeTx.Fee}
|
||||
if !fees.IsGTE(h.MinFee) {
|
||||
return res, errors.InsufficientFees()
|
||||
return res, ErrInsufficientFees()
|
||||
}
|
||||
|
||||
if !ctx.HasPermission(feeTx.Payer) {
|
||||
return res, errors.Unauthorized()
|
||||
return res, errors.ErrUnauthorized()
|
||||
}
|
||||
|
||||
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
||||
|
||||
Reference in New Issue
Block a user