diff --git a/modules/fee/errors.go b/modules/fee/errors.go index f29d3cbe1..cf2633039 100644 --- a/modules/fee/errors.go +++ b/modules/fee/errors.go @@ -2,14 +2,14 @@ package fee import ( - rawerr "errors" + "fmt" abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/errors" ) var ( - errInsufficientFees = rawerr.New("Insufficient Fees") + errInsufficientFees = fmt.Errorf("Insufficient Fees") ) func ErrInsufficientFees() errors.TMError { diff --git a/modules/fee/handler.go b/modules/fee/handler.go index d202ebab4..6980245bc 100644 --- a/modules/fee/handler.go +++ b/modules/fee/handler.go @@ -11,76 +11,62 @@ import ( // NameFee - namespace for the fee module const NameFee = "fee" -// AccountChecker - interface used by SimpleFeeHandler -type AccountChecker interface { - // Get amount checks the current amount - GetAmount(store state.KVStore, addr basecoin.Actor) (coin.Coins, error) - - // ChangeAmount modifies the balance by the given amount and returns the new balance - // always returns an error if leading to negative balance - ChangeAmount(store state.KVStore, addr basecoin.Actor, coins coin.Coins) (coin.Coins, error) -} - -// SimpleFeeHandler - checker object for fee checking -type SimpleFeeHandler struct { - AccountChecker - MinFee coin.Coins +// SimpleFeeMiddleware - middleware for fee checking, constant amount +// It used modules.coin to move the money +type SimpleFeeMiddleware struct { + MinFee coin.Coin // + Collector basecoin.Actor stack.PassOption } +var _ stack.Middleware = SimpleFeeMiddleware{} + +// NewSimpleFeeMiddleware returns a fee handler with a fixed minimum fee. +// +// If minFee is 0, then the FeeTx is optional +func NewSimpleFeeMiddleware(minFee coin.Coin) SimpleFeeMiddleware { + return SimpleFeeMiddleware{ + MinFee: minFee, + } +} + // Name - return the namespace for the fee module -func (SimpleFeeHandler) Name() string { +func (SimpleFeeMiddleware) Name() string { return NameFee } -var _ stack.Middleware = SimpleFeeHandler{} - -// Yes, I know refactor a bit... really too late already - // CheckTx - check the transaction -func (h SimpleFeeHandler) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) { - feeTx, ok := tx.Unwrap().(*Fee) - if !ok { - return res, errors.ErrInvalidFormat(tx) - } - - fees := coin.Coins{feeTx.Fee} - if !fees.IsGTE(h.MinFee) { - return res, ErrInsufficientFees() - } - - if !ctx.HasPermission(feeTx.Payer) { - return res, errors.ErrUnauthorized() - } - - _, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative()) - if err != nil { - return res, err - } - - return basecoin.Result{Log: "Valid tx"}, nil +func (h SimpleFeeMiddleware) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) { + return h.doTx(ctx, store, tx, next.CheckTx) } // DeliverTx - send the fee handler transaction -func (h SimpleFeeHandler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) { - feeTx, ok := tx.Unwrap().(*Fee) +func (h SimpleFeeMiddleware) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) { + return h.doTx(ctx, store, tx, next.DeliverTx) +} + +func (h SimpleFeeMiddleware) doTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.CheckerFunc) (res basecoin.Result, err error) { + feeTx, ok := tx.Unwrap().(Fee) if !ok { - return res, errors.ErrInvalidFormat(tx) + // the fee wrapper is not required if there is no minimum + if h.MinFee.IsZero() { + return next(ctx, store, tx) + } + return res, errors.ErrInvalidFormat(TypeFees, tx) } - fees := coin.Coins{feeTx.Fee} - if !fees.IsGTE(h.MinFee) { + // see if it is big enough... + fee := feeTx.Fee + if !fee.IsGTE(h.MinFee) { return res, ErrInsufficientFees() } - if !ctx.HasPermission(feeTx.Payer) { - return res, errors.ErrUnauthorized() - } - - _, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative()) + // now, try to make a IPC call to coins... + send := coin.NewSendOneTx(feeTx.Payer, h.Collector, coin.Coins{fee}) + _, err = next(ctx, store, send) if err != nil { return res, err } - return next.DeliverTx(ctx, store, feeTx.Next()) + return next(ctx, store, feeTx.Tx) } diff --git a/modules/fee/tx.go b/modules/fee/tx.go index c17de796c..d2f61f732 100644 --- a/modules/fee/tx.go +++ b/modules/fee/tx.go @@ -7,38 +7,38 @@ import ( // nolint const ( - ByteFees = 0x20 - TypeFees = "fee" + ByteFees = 0x21 + TypeFees = NameFee + "/tx" ) func init() { basecoin.TxMapper. - RegisterImplementation(&Fee{}, TypeFees, ByteFees) + RegisterImplementation(Fee{}, TypeFees, ByteFees) } /**** Fee ****/ -var _ basecoin.TxLayer = &Fee{} - // Fee attaches a fee payment to the embedded tx type Fee struct { - Tx basecoin.Tx `json:"tx"` + // Gas coin.Coin `json:"gas"` // ????? Fee coin.Coin `json:"fee"` Payer basecoin.Actor `json:"payer"` // the address who pays the fee - // Gas coin.Coin `json:"gas"` // ????? + Tx basecoin.Tx `json:"tx"` +} + +// NewFee wraps a tx with a promised fee from this actor +func NewFee(tx basecoin.Tx, fee coin.Coin, payer basecoin.Actor) basecoin.Tx { + return Fee{Tx: tx, Fee: fee, Payer: payer}.Wrap() } // nolint - TxInner Functions -func NewFee(tx basecoin.Tx, fee coin.Coin, payer basecoin.Actor) basecoin.Tx { - return (&Fee{Tx: tx, Fee: fee, Payer: payer}).Wrap() -} -func (f *Fee) ValidateBasic() error { +func (f Fee) ValidateBasic() error { // TODO: more checks return f.Tx.ValidateBasic() } -func (f *Fee) Wrap() basecoin.Tx { +func (f Fee) Wrap() basecoin.Tx { return basecoin.Tx{f} } -func (f *Fee) Next() basecoin.Tx { +func (f Fee) Next() basecoin.Tx { return f.Tx } diff --git a/modules/roles/handler.go b/modules/roles/handler.go index 2ade96ee1..0a31eb6eb 100644 --- a/modules/roles/handler.go +++ b/modules/roles/handler.go @@ -56,7 +56,7 @@ func checkTx(ctx basecoin.Context, tx basecoin.Tx) (create CreateRoleTx, err err // check if the tx is proper type and valid create, ok := tx.Unwrap().(CreateRoleTx) if !ok { - return create, errors.ErrInvalidFormat(tx) + return create, errors.ErrInvalidFormat(TypeCreateRoleTx, tx) } err = create.ValidateBasic() return create, err