Complete error package overhaul
This commit is contained in:
parent
5fa77bf647
commit
995452ea02
|
@ -16,21 +16,14 @@ import (
|
||||||
var (
|
var (
|
||||||
errDecoding = rawerr.New("Error decoding input")
|
errDecoding = rawerr.New("Error decoding input")
|
||||||
errUnauthorized = rawerr.New("Unauthorized")
|
errUnauthorized = rawerr.New("Unauthorized")
|
||||||
errInvalidAddress = rawerr.New("Invalid Address")
|
|
||||||
errInvalidCoins = rawerr.New("Invalid Coins")
|
|
||||||
errInvalidFormat = rawerr.New("Invalid Format")
|
|
||||||
errInvalidSequence = rawerr.New("Invalid Sequence")
|
|
||||||
errInvalidSignature = rawerr.New("Invalid Signature")
|
errInvalidSignature = rawerr.New("Invalid Signature")
|
||||||
errInsufficientFees = rawerr.New("Insufficient Fees")
|
|
||||||
errInsufficientFunds = rawerr.New("Insufficient Funds")
|
|
||||||
errNoInputs = rawerr.New("No Input Coins")
|
|
||||||
errNoOutputs = rawerr.New("No Output Coins")
|
|
||||||
errTooLarge = rawerr.New("Input size too large")
|
errTooLarge = rawerr.New("Input size too large")
|
||||||
errMissingSignature = rawerr.New("Signature missing")
|
errMissingSignature = rawerr.New("Signature missing")
|
||||||
errTooManySignatures = rawerr.New("Too many signatures")
|
errTooManySignatures = rawerr.New("Too many signatures")
|
||||||
errNoChain = rawerr.New("No chain id provided")
|
errNoChain = rawerr.New("No chain id provided")
|
||||||
errWrongChain = rawerr.New("Wrong chain for tx")
|
errWrongChain = rawerr.New("Wrong chain for tx")
|
||||||
errUnknownTxType = rawerr.New("Tx type unknown")
|
errUnknownTxType = rawerr.New("Tx type unknown")
|
||||||
|
errInvalidFormat = rawerr.New("Invalid format")
|
||||||
)
|
)
|
||||||
|
|
||||||
func ErrUnknownTxType(tx basecoin.Tx) TMError {
|
func ErrUnknownTxType(tx basecoin.Tx) TMError {
|
||||||
|
@ -38,11 +31,19 @@ func ErrUnknownTxType(tx basecoin.Tx) TMError {
|
||||||
w := errors.Wrap(errUnknownTxType, msg)
|
w := errors.Wrap(errUnknownTxType, msg)
|
||||||
return WithCode(w, abci.CodeType_UnknownRequest)
|
return WithCode(w, abci.CodeType_UnknownRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsUnknownTxTypeErr(err error) bool {
|
func IsUnknownTxTypeErr(err error) bool {
|
||||||
return IsSameError(errUnknownTxType, err)
|
return IsSameError(errUnknownTxType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ErrInvalidFormat(tx basecoin.Tx) TMError {
|
||||||
|
msg := fmt.Sprintf("%T", tx.Unwrap())
|
||||||
|
w := errors.Wrap(errInvalidFormat, msg)
|
||||||
|
return WithCode(w, abci.CodeType_UnknownRequest)
|
||||||
|
}
|
||||||
|
func IsInvalidFormatErr(err error) bool {
|
||||||
|
return IsSameError(errInvalidFormat, err)
|
||||||
|
}
|
||||||
|
|
||||||
func ErrInternal(msg string) TMError {
|
func ErrInternal(msg string) TMError {
|
||||||
return New(msg, abci.CodeType_InternalError)
|
return New(msg, abci.CodeType_InternalError)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +56,6 @@ func IsInternalErr(err error) bool {
|
||||||
func ErrDecoding() TMError {
|
func ErrDecoding() TMError {
|
||||||
return WithCode(errDecoding, abci.CodeType_EncodingError)
|
return WithCode(errDecoding, abci.CodeType_EncodingError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsDecodingErr(err error) bool {
|
func IsDecodingErr(err error) bool {
|
||||||
return IsSameError(errDecoding, err)
|
return IsSameError(errDecoding, err)
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,6 @@ func IsUnauthorizedErr(err error) bool {
|
||||||
func ErrMissingSignature() TMError {
|
func ErrMissingSignature() TMError {
|
||||||
return WithCode(errMissingSignature, abci.CodeType_Unauthorized)
|
return WithCode(errMissingSignature, abci.CodeType_Unauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsMissingSignatureErr(err error) bool {
|
func IsMissingSignatureErr(err error) bool {
|
||||||
return IsSameError(errMissingSignature, err)
|
return IsSameError(errMissingSignature, err)
|
||||||
}
|
}
|
||||||
|
@ -81,7 +80,6 @@ func IsMissingSignatureErr(err error) bool {
|
||||||
func ErrTooManySignatures() TMError {
|
func ErrTooManySignatures() TMError {
|
||||||
return WithCode(errTooManySignatures, abci.CodeType_Unauthorized)
|
return WithCode(errTooManySignatures, abci.CodeType_Unauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsTooManySignaturesErr(err error) bool {
|
func IsTooManySignaturesErr(err error) bool {
|
||||||
return IsSameError(errTooManySignatures, err)
|
return IsSameError(errTooManySignatures, err)
|
||||||
}
|
}
|
||||||
|
@ -89,7 +87,6 @@ func IsTooManySignaturesErr(err error) bool {
|
||||||
func ErrInvalidSignature() TMError {
|
func ErrInvalidSignature() TMError {
|
||||||
return WithCode(errInvalidSignature, abci.CodeType_Unauthorized)
|
return WithCode(errInvalidSignature, abci.CodeType_Unauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsInvalidSignatureErr(err error) bool {
|
func IsInvalidSignatureErr(err error) bool {
|
||||||
return IsSameError(errInvalidSignature, err)
|
return IsSameError(errInvalidSignature, err)
|
||||||
}
|
}
|
||||||
|
@ -97,7 +94,6 @@ func IsInvalidSignatureErr(err error) bool {
|
||||||
func ErrNoChain() TMError {
|
func ErrNoChain() TMError {
|
||||||
return WithCode(errNoChain, abci.CodeType_Unauthorized)
|
return WithCode(errNoChain, abci.CodeType_Unauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsNoChainErr(err error) bool {
|
func IsNoChainErr(err error) bool {
|
||||||
return IsSameError(errNoChain, err)
|
return IsSameError(errNoChain, err)
|
||||||
}
|
}
|
||||||
|
@ -106,47 +102,13 @@ func ErrWrongChain(chain string) TMError {
|
||||||
msg := errors.Wrap(errWrongChain, chain)
|
msg := errors.Wrap(errWrongChain, chain)
|
||||||
return WithCode(msg, abci.CodeType_Unauthorized)
|
return WithCode(msg, abci.CodeType_Unauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsWrongChainErr(err error) bool {
|
func IsWrongChainErr(err error) bool {
|
||||||
return IsSameError(errWrongChain, err)
|
return IsSameError(errWrongChain, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InvalidAddress() TMError {
|
|
||||||
return WithCode(errInvalidAddress, abci.CodeType_BaseInvalidInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func InvalidCoins() TMError {
|
|
||||||
return WithCode(errInvalidCoins, abci.CodeType_BaseInvalidInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func InvalidFormat() TMError {
|
|
||||||
return WithCode(errInvalidFormat, abci.CodeType_BaseInvalidInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func InvalidSequence() TMError {
|
|
||||||
return WithCode(errInvalidSequence, abci.CodeType_BaseInvalidInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func InsufficientFees() TMError {
|
|
||||||
return WithCode(errInsufficientFees, abci.CodeType_BaseInvalidInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func InsufficientFunds() TMError {
|
|
||||||
return WithCode(errInsufficientFunds, abci.CodeType_BaseInvalidInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NoInputs() TMError {
|
|
||||||
return WithCode(errNoInputs, abci.CodeType_BaseInvalidInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NoOutputs() TMError {
|
|
||||||
return WithCode(errNoOutputs, abci.CodeType_BaseInvalidOutput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ErrTooLarge() TMError {
|
func ErrTooLarge() TMError {
|
||||||
return WithCode(errTooLarge, abci.CodeType_EncodingError)
|
return WithCode(errTooLarge, abci.CodeType_EncodingError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsTooLargeErr(err error) bool {
|
func IsTooLargeErr(err error) bool {
|
||||||
return IsSameError(errTooLarge, err)
|
return IsSameError(errTooLarge, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,10 +11,18 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler writes
|
// Handler writes
|
||||||
type Handler struct{}
|
type Handler struct {
|
||||||
|
Accountant
|
||||||
|
}
|
||||||
|
|
||||||
var _ basecoin.Handler = Handler{}
|
var _ basecoin.Handler = Handler{}
|
||||||
|
|
||||||
|
func NewHandler() Handler {
|
||||||
|
return Handler{
|
||||||
|
Accountant: Accountant{Prefix: []byte(NameCoin + "/")},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (_ Handler) Name() string {
|
func (_ Handler) Name() string {
|
||||||
return NameCoin
|
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
|
// check if the tx is proper type and valid
|
||||||
send, ok := tx.Unwrap().(SendTx)
|
send, ok := tx.Unwrap().(SendTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return send, errors.UnknownTxType(tx)
|
return send, errors.ErrInvalidFormat(tx)
|
||||||
}
|
}
|
||||||
err = send.ValidateBasic()
|
err = send.ValidateBasic()
|
||||||
if err != nil {
|
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
|
// check if all inputs have permission
|
||||||
for _, in := range send.Inputs {
|
for _, in := range send.Inputs {
|
||||||
if !ctx.HasPermission(in.Address) {
|
if !ctx.HasPermission(in.Address) {
|
||||||
return send, errors.Unauthorized()
|
return send, errors.ErrUnauthorized()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return send, nil
|
return send, nil
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func TestHandlerPermissions(t *testing.T) {
|
func TestHandlerPermissions(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
// TODO: need to update this when we actually have token store
|
// TODO: need to update this when we actually have token store
|
||||||
h := Handler{}
|
h := NewHandler()
|
||||||
|
|
||||||
// these are all valid, except for minusCoins
|
// these are all valid, except for minusCoins
|
||||||
addr1 := basecoin.Actor{App: "coin", Address: []byte{1, 2}}
|
addr1 := basecoin.Actor{App: "coin", Address: []byte{1, 2}}
|
||||||
|
|
|
@ -15,8 +15,12 @@ type Accountant struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Accountant) GetAccount(store types.KVStore, addr basecoin.Actor) (Account, error) {
|
func (a Accountant) GetAccount(store types.KVStore, addr basecoin.Actor) (Account, error) {
|
||||||
// TODO: how to handle empty accounts??
|
acct, err := loadAccount(store, a.makeKey(addr))
|
||||||
return 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
|
// 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
|
// check sequence
|
||||||
if seq != acct.Sequence+1 {
|
if seq != acct.Sequence+1 {
|
||||||
return acct, errors.InvalidSequence()
|
return acct, ErrInvalidSequence()
|
||||||
}
|
}
|
||||||
acct.Sequence += 1
|
acct.Sequence += 1
|
||||||
|
|
||||||
// check amount
|
// check amount
|
||||||
final := acct.Coins.Minus(coins)
|
final := acct.Coins.Minus(coins)
|
||||||
if !final.IsNonnegative() {
|
if !final.IsNonnegative() {
|
||||||
return acct, errors.InsufficientFunds()
|
return acct, ErrInsufficientFunds()
|
||||||
}
|
}
|
||||||
|
|
||||||
acct.Coins = final
|
acct.Coins = final
|
||||||
|
@ -77,13 +81,12 @@ type Account struct {
|
||||||
func loadAccount(store types.KVStore, key []byte) (acct Account, err error) {
|
func loadAccount(store types.KVStore, key []byte) (acct Account, err error) {
|
||||||
data := store.Get(key)
|
data := store.Get(key)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
// TODO: error or empty????
|
return acct, ErrNoAccount()
|
||||||
return acct, errors.InternalError("No account found")
|
|
||||||
}
|
}
|
||||||
err = wire.ReadBinaryBytes(data, &acct)
|
err = wire.ReadBinaryBytes(data, &acct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("Error reading account %X", key)
|
msg := fmt.Sprintf("Error reading account %X", key)
|
||||||
return acct, errors.InternalError(msg)
|
return acct, errors.ErrInternal(msg)
|
||||||
}
|
}
|
||||||
return acct, nil
|
return acct, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"github.com/tendermint/basecoin"
|
"github.com/tendermint/basecoin"
|
||||||
|
|
||||||
"github.com/tendermint/basecoin/errors"
|
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,20 +28,20 @@ type TxInput struct {
|
||||||
|
|
||||||
func (txIn TxInput) ValidateBasic() error {
|
func (txIn TxInput) ValidateBasic() error {
|
||||||
if txIn.Address.App == "" {
|
if txIn.Address.App == "" {
|
||||||
return errors.InvalidAddress()
|
return ErrInvalidAddress()
|
||||||
}
|
}
|
||||||
// TODO: knowledge of app-specific codings?
|
// TODO: knowledge of app-specific codings?
|
||||||
if len(txIn.Address.Address) == 0 {
|
if len(txIn.Address.Address) == 0 {
|
||||||
return errors.InvalidAddress()
|
return ErrInvalidAddress()
|
||||||
}
|
}
|
||||||
if !txIn.Coins.IsValid() {
|
if !txIn.Coins.IsValid() {
|
||||||
return errors.InvalidCoins()
|
return ErrInvalidCoins()
|
||||||
}
|
}
|
||||||
if !txIn.Coins.IsPositive() {
|
if !txIn.Coins.IsPositive() {
|
||||||
return errors.InvalidCoins()
|
return ErrInvalidCoins()
|
||||||
}
|
}
|
||||||
if txIn.Sequence <= 0 {
|
if txIn.Sequence <= 0 {
|
||||||
return errors.InvalidSequence()
|
return ErrInvalidSequence()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -69,17 +68,17 @@ type TxOutput struct {
|
||||||
|
|
||||||
func (txOut TxOutput) ValidateBasic() error {
|
func (txOut TxOutput) ValidateBasic() error {
|
||||||
if txOut.Address.App == "" {
|
if txOut.Address.App == "" {
|
||||||
return errors.InvalidAddress()
|
return ErrInvalidAddress()
|
||||||
}
|
}
|
||||||
// TODO: knowledge of app-specific codings?
|
// TODO: knowledge of app-specific codings?
|
||||||
if len(txOut.Address.Address) == 0 {
|
if len(txOut.Address.Address) == 0 {
|
||||||
return errors.InvalidAddress()
|
return ErrInvalidAddress()
|
||||||
}
|
}
|
||||||
if !txOut.Coins.IsValid() {
|
if !txOut.Coins.IsValid() {
|
||||||
return errors.InvalidCoins()
|
return ErrInvalidCoins()
|
||||||
}
|
}
|
||||||
if !txOut.Coins.IsPositive() {
|
if !txOut.Coins.IsPositive() {
|
||||||
return errors.InvalidCoins()
|
return ErrInvalidCoins()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -109,10 +108,10 @@ func (tx SendTx) ValidateBasic() error {
|
||||||
// this just makes sure all the inputs and outputs are properly formatted,
|
// this just makes sure all the inputs and outputs are properly formatted,
|
||||||
// not that they actually have the money inside
|
// not that they actually have the money inside
|
||||||
if len(tx.Inputs) == 0 {
|
if len(tx.Inputs) == 0 {
|
||||||
return errors.NoInputs()
|
return ErrNoInputs()
|
||||||
}
|
}
|
||||||
if len(tx.Outputs) == 0 {
|
if len(tx.Outputs) == 0 {
|
||||||
return errors.NoOutputs()
|
return ErrNoOutputs()
|
||||||
}
|
}
|
||||||
// make sure all inputs and outputs are individually valid
|
// make sure all inputs and outputs are individually valid
|
||||||
var totalIn, totalOut types.Coins
|
var totalIn, totalOut types.Coins
|
||||||
|
@ -130,7 +129,7 @@ func (tx SendTx) ValidateBasic() error {
|
||||||
}
|
}
|
||||||
// make sure inputs and outputs match
|
// make sure inputs and outputs match
|
||||||
if !totalIn.IsEqual(totalOut) {
|
if !totalIn.IsEqual(totalOut) {
|
||||||
return errors.InvalidCoins()
|
return ErrInvalidCoins()
|
||||||
}
|
}
|
||||||
return nil
|
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) {
|
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)
|
feeTx, ok := tx.Unwrap().(*Fee)
|
||||||
if !ok {
|
if !ok {
|
||||||
return res, errors.InvalidFormat()
|
return res, errors.ErrInvalidFormat(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fees := types.Coins{feeTx.Fee}
|
fees := types.Coins{feeTx.Fee}
|
||||||
if !fees.IsGTE(h.MinFee) {
|
if !fees.IsGTE(h.MinFee) {
|
||||||
return res, errors.InsufficientFees()
|
return res, ErrInsufficientFees()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.HasPermission(feeTx.Payer) {
|
if !ctx.HasPermission(feeTx.Payer) {
|
||||||
return res, errors.Unauthorized()
|
return res, errors.ErrUnauthorized()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
_, 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) {
|
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)
|
feeTx, ok := tx.Unwrap().(*Fee)
|
||||||
if !ok {
|
if !ok {
|
||||||
return res, errors.InvalidFormat()
|
return res, errors.ErrInvalidFormat(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fees := types.Coins{feeTx.Fee}
|
fees := types.Coins{feeTx.Fee}
|
||||||
if !fees.IsGTE(h.MinFee) {
|
if !fees.IsGTE(h.MinFee) {
|
||||||
return res, errors.InsufficientFees()
|
return res, ErrInsufficientFees()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.HasPermission(feeTx.Payer) {
|
if !ctx.HasPermission(feeTx.Payer) {
|
||||||
return res, errors.Unauthorized()
|
return res, errors.ErrUnauthorized()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
||||||
|
|
|
@ -42,10 +42,10 @@ func (c Chain) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.
|
||||||
func (c Chain) checkChain(tx basecoin.Tx) (basecoin.Tx, error) {
|
func (c Chain) checkChain(tx basecoin.Tx) (basecoin.Tx, error) {
|
||||||
ctx, ok := tx.Unwrap().(*txs.Chain)
|
ctx, ok := tx.Unwrap().(*txs.Chain)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx, errors.NoChain()
|
return tx, errors.ErrNoChain()
|
||||||
}
|
}
|
||||||
if ctx.ChainID != c.ChainID {
|
if ctx.ChainID != c.ChainID {
|
||||||
return tx, errors.WrongChain(ctx.ChainID)
|
return tx, errors.ErrWrongChain(ctx.ChainID)
|
||||||
}
|
}
|
||||||
return ctx.Tx, nil
|
return ctx.Tx, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestChain(t *testing.T) {
|
||||||
errorMsg string
|
errorMsg string
|
||||||
}{
|
}{
|
||||||
{txs.NewChain(chainID, raw).Wrap(), true, ""},
|
{txs.NewChain(chainID, raw).Wrap(), true, ""},
|
||||||
{txs.NewChain("someone-else", raw).Wrap(), false, "Tx belongs to different chain - someone-else"},
|
{txs.NewChain("someone-else", raw).Wrap(), false, "someone-else"},
|
||||||
{raw, false, "No chain id provided"},
|
{raw, false, "No chain id provided"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ func TestChain(t *testing.T) {
|
||||||
assert.Equal(msg, res.Log, i)
|
assert.Equal(msg, res.Log, i)
|
||||||
} else {
|
} else {
|
||||||
if assert.NotNil(err, i) {
|
if assert.NotNil(err, i) {
|
||||||
assert.Equal(tc.errorMsg, err.Error(), i)
|
assert.Contains(err.Error(), tc.errorMsg, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ func TestChain(t *testing.T) {
|
||||||
assert.Equal(msg, res.Log, i)
|
assert.Equal(msg, res.Log, i)
|
||||||
} else {
|
} else {
|
||||||
if assert.NotNil(err, i) {
|
if assert.NotNil(err, i) {
|
||||||
assert.Equal(tc.errorMsg, err.Error(), i)
|
assert.Contains(err.Error(), tc.errorMsg, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,14 @@ func (_ CheckMiddleware) Name() string {
|
||||||
|
|
||||||
func (p CheckMiddleware) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
func (p CheckMiddleware) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
||||||
if !ctx.HasPermission(p.Required) {
|
if !ctx.HasPermission(p.Required) {
|
||||||
return res, errors.Unauthorized()
|
return res, errors.ErrUnauthorized()
|
||||||
}
|
}
|
||||||
return next.CheckTx(ctx, store, tx)
|
return next.CheckTx(ctx, store, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p CheckMiddleware) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
func (p CheckMiddleware) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
||||||
if !ctx.HasPermission(p.Required) {
|
if !ctx.HasPermission(p.Required) {
|
||||||
return res, errors.Unauthorized()
|
return res, errors.ErrUnauthorized()
|
||||||
}
|
}
|
||||||
return next.DeliverTx(ctx, store, tx)
|
return next.DeliverTx(ctx, store, tx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,12 @@ func TestPermissionSandbox(t *testing.T) {
|
||||||
grant basecoin.Actor
|
grant basecoin.Actor
|
||||||
require basecoin.Actor
|
require basecoin.Actor
|
||||||
expectedRes data.Bytes
|
expectedRes data.Bytes
|
||||||
expectedErr error
|
expected func(error) bool
|
||||||
}{
|
}{
|
||||||
{grantee, grantee, rawBytes, nil},
|
{grantee, grantee, rawBytes, nil},
|
||||||
{grantee, grantee2, nil, errors.Unauthorized()},
|
{grantee, grantee2, nil, errors.IsUnauthorizedErr},
|
||||||
{grantee, signer, nil, errors.Unauthorized()},
|
{grantee, signer, nil, errors.IsUnauthorizedErr},
|
||||||
{signer, signer, nil, errors.InternalError("panic")},
|
{signer, signer, nil, errors.IsInternalErr},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
@ -47,24 +47,22 @@ func TestPermissionSandbox(t *testing.T) {
|
||||||
).Use(EchoHandler{})
|
).Use(EchoHandler{})
|
||||||
|
|
||||||
res, err := app.CheckTx(ctx, store, raw)
|
res, err := app.CheckTx(ctx, store, raw)
|
||||||
checkPerm(t, i, tc.expectedRes, tc.expectedErr, res, err)
|
checkPerm(t, i, tc.expectedRes, tc.expected, res, err)
|
||||||
|
|
||||||
res, err = app.DeliverTx(ctx, store, raw)
|
res, err = app.DeliverTx(ctx, store, raw)
|
||||||
checkPerm(t, i, tc.expectedRes, tc.expectedErr, res, err)
|
checkPerm(t, i, tc.expectedRes, tc.expected, res, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPerm(t *testing.T, idx int, data []byte, expected error, res basecoin.Result, err error) {
|
func checkPerm(t *testing.T, idx int, data []byte, check func(error) bool, res basecoin.Result, err error) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
if expected == nil {
|
if len(data) > 0 {
|
||||||
assert.Nil(err, "%d: %+v", idx, err)
|
assert.Nil(err, "%d: %+v", idx, err)
|
||||||
assert.EqualValues(data, res.Data)
|
assert.EqualValues(data, res.Data)
|
||||||
} else {
|
} else {
|
||||||
assert.NotNil(err, "%d", idx)
|
assert.NotNil(err, "%d", idx)
|
||||||
// check error code!
|
// check error code!
|
||||||
shouldCode := errors.Wrap(expected).ErrorCode()
|
assert.True(check(err), "%d: %+v", idx, err)
|
||||||
isCode := errors.Wrap(err).ErrorCode()
|
|
||||||
assert.Equal(shouldCode, isCode, "%d: %+v", idx, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,5 +45,5 @@ func normalizePanic(p interface{}) error {
|
||||||
return errors.Wrap(err)
|
return errors.Wrap(err)
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("%v", p)
|
msg := fmt.Sprintf("%v", p)
|
||||||
return errors.InternalError(msg)
|
return errors.ErrInternal(msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ func addSigners(ctx basecoin.Context, sigs []crypto.PubKey) basecoin.Context {
|
||||||
func getSigners(tx basecoin.Tx) ([]crypto.PubKey, basecoin.Tx, error) {
|
func getSigners(tx basecoin.Tx) ([]crypto.PubKey, basecoin.Tx, error) {
|
||||||
stx, ok := tx.Unwrap().(Signed)
|
stx, ok := tx.Unwrap().(Signed)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, basecoin.Tx{}, errors.Unauthorized()
|
return nil, basecoin.Tx{}, errors.ErrUnauthorized()
|
||||||
}
|
}
|
||||||
sig, err := stx.Signers()
|
sig, err := stx.Signers()
|
||||||
return sig, stx.Next(), err
|
return sig, stx.Next(), err
|
||||||
|
|
|
@ -50,7 +50,7 @@ func (r Raw) Wrap() basecoin.Tx {
|
||||||
|
|
||||||
func (r Raw) ValidateBasic() error {
|
func (r Raw) ValidateBasic() error {
|
||||||
if len(r.Bytes) > rawMaxSize {
|
if len(r.Bytes) > rawMaxSize {
|
||||||
return errors.TooLarge()
|
return errors.ErrTooLarge()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
16
txs/sigs.go
16
txs/sigs.go
|
@ -66,7 +66,7 @@ func (s *OneSig) Next() basecoin.Tx {
|
||||||
func (s *OneSig) ValidateBasic() error {
|
func (s *OneSig) ValidateBasic() error {
|
||||||
// TODO: VerifyBytes here, we do it in Signers?
|
// TODO: VerifyBytes here, we do it in Signers?
|
||||||
if s.Empty() || !s.Pubkey.VerifyBytes(s.SignBytes(), s.Sig) {
|
if s.Empty() || !s.Pubkey.VerifyBytes(s.SignBytes(), s.Sig) {
|
||||||
return errors.Unauthorized()
|
return errors.ErrUnauthorized()
|
||||||
}
|
}
|
||||||
return s.Tx.ValidateBasic()
|
return s.Tx.ValidateBasic()
|
||||||
}
|
}
|
||||||
|
@ -92,10 +92,10 @@ func (s *OneSig) SignBytes() []byte {
|
||||||
func (s *OneSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
|
func (s *OneSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
|
||||||
signed := Signed{sig, pubkey}
|
signed := Signed{sig, pubkey}
|
||||||
if signed.Empty() {
|
if signed.Empty() {
|
||||||
return errors.MissingSignature()
|
return errors.ErrMissingSignature()
|
||||||
}
|
}
|
||||||
if !s.Empty() {
|
if !s.Empty() {
|
||||||
return errors.TooManySignatures()
|
return errors.ErrTooManySignatures()
|
||||||
}
|
}
|
||||||
// set the value once we are happy
|
// set the value once we are happy
|
||||||
s.Signed = signed
|
s.Signed = signed
|
||||||
|
@ -107,10 +107,10 @@ func (s *OneSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
|
||||||
// including if there are no signatures
|
// including if there are no signatures
|
||||||
func (s *OneSig) Signers() ([]crypto.PubKey, error) {
|
func (s *OneSig) Signers() ([]crypto.PubKey, error) {
|
||||||
if s.Empty() {
|
if s.Empty() {
|
||||||
return nil, errors.MissingSignature()
|
return nil, errors.ErrMissingSignature()
|
||||||
}
|
}
|
||||||
if !s.Pubkey.VerifyBytes(s.SignBytes(), s.Sig) {
|
if !s.Pubkey.VerifyBytes(s.SignBytes(), s.Sig) {
|
||||||
return nil, errors.InvalidSignature()
|
return nil, errors.ErrInvalidSignature()
|
||||||
}
|
}
|
||||||
return []crypto.PubKey{s.Pubkey}, nil
|
return []crypto.PubKey{s.Pubkey}, nil
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ func (s *MultiSig) SignBytes() []byte {
|
||||||
func (s *MultiSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
|
func (s *MultiSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
|
||||||
signed := Signed{sig, pubkey}
|
signed := Signed{sig, pubkey}
|
||||||
if signed.Empty() {
|
if signed.Empty() {
|
||||||
return errors.MissingSignature()
|
return errors.ErrMissingSignature()
|
||||||
}
|
}
|
||||||
// set the value once we are happy
|
// set the value once we are happy
|
||||||
s.Sigs = append(s.Sigs, signed)
|
s.Sigs = append(s.Sigs, signed)
|
||||||
|
@ -180,7 +180,7 @@ func (s *MultiSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
|
||||||
// including if there are no signatures
|
// including if there are no signatures
|
||||||
func (s *MultiSig) Signers() ([]crypto.PubKey, error) {
|
func (s *MultiSig) Signers() ([]crypto.PubKey, error) {
|
||||||
if len(s.Sigs) == 0 {
|
if len(s.Sigs) == 0 {
|
||||||
return nil, errors.MissingSignature()
|
return nil, errors.ErrMissingSignature()
|
||||||
}
|
}
|
||||||
// verify all the signatures before returning them
|
// verify all the signatures before returning them
|
||||||
keys := make([]crypto.PubKey, len(s.Sigs))
|
keys := make([]crypto.PubKey, len(s.Sigs))
|
||||||
|
@ -188,7 +188,7 @@ func (s *MultiSig) Signers() ([]crypto.PubKey, error) {
|
||||||
for i := range s.Sigs {
|
for i := range s.Sigs {
|
||||||
ms := s.Sigs[i]
|
ms := s.Sigs[i]
|
||||||
if !ms.Pubkey.VerifyBytes(data, ms.Sig) {
|
if !ms.Pubkey.VerifyBytes(data, ms.Sig) {
|
||||||
return nil, errors.InvalidSignature()
|
return nil, errors.ErrInvalidSignature()
|
||||||
}
|
}
|
||||||
keys[i] = ms.Pubkey
|
keys[i] = ms.Pubkey
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue