Fee middleware using IPC
This commit is contained in:
parent
5950ff34e3
commit
1cc671108e
|
@ -2,14 +2,14 @@
|
||||||
package fee
|
package fee
|
||||||
|
|
||||||
import (
|
import (
|
||||||
rawerr "errors"
|
"fmt"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
"github.com/tendermint/basecoin/errors"
|
"github.com/tendermint/basecoin/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errInsufficientFees = rawerr.New("Insufficient Fees")
|
errInsufficientFees = fmt.Errorf("Insufficient Fees")
|
||||||
)
|
)
|
||||||
|
|
||||||
func ErrInsufficientFees() errors.TMError {
|
func ErrInsufficientFees() errors.TMError {
|
||||||
|
|
|
@ -11,76 +11,62 @@ import (
|
||||||
// NameFee - namespace for the fee module
|
// NameFee - namespace for the fee module
|
||||||
const NameFee = "fee"
|
const NameFee = "fee"
|
||||||
|
|
||||||
// AccountChecker - interface used by SimpleFeeHandler
|
// SimpleFeeMiddleware - middleware for fee checking, constant amount
|
||||||
type AccountChecker interface {
|
// It used modules.coin to move the money
|
||||||
// Get amount checks the current amount
|
type SimpleFeeMiddleware struct {
|
||||||
GetAmount(store state.KVStore, addr basecoin.Actor) (coin.Coins, error)
|
MinFee coin.Coin //
|
||||||
|
Collector basecoin.Actor
|
||||||
// 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
|
|
||||||
stack.PassOption
|
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
|
// Name - return the namespace for the fee module
|
||||||
func (SimpleFeeHandler) Name() string {
|
func (SimpleFeeMiddleware) Name() string {
|
||||||
return NameFee
|
return NameFee
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ stack.Middleware = SimpleFeeHandler{}
|
|
||||||
|
|
||||||
// Yes, I know refactor a bit... really too late already
|
|
||||||
|
|
||||||
// CheckTx - check the transaction
|
// 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) {
|
func (h SimpleFeeMiddleware) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
||||||
feeTx, ok := tx.Unwrap().(*Fee)
|
return h.doTx(ctx, store, tx, next.CheckTx)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx - send the fee handler transaction
|
// 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) {
|
func (h SimpleFeeMiddleware) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
||||||
feeTx, ok := tx.Unwrap().(*Fee)
|
return h.doTx(ctx, store, tx, next.DeliverTx)
|
||||||
if !ok {
|
|
||||||
return res, errors.ErrInvalidFormat(tx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fees := coin.Coins{feeTx.Fee}
|
func (h SimpleFeeMiddleware) doTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.CheckerFunc) (res basecoin.Result, err error) {
|
||||||
if !fees.IsGTE(h.MinFee) {
|
feeTx, ok := tx.Unwrap().(Fee)
|
||||||
|
if !ok {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if it is big enough...
|
||||||
|
fee := feeTx.Fee
|
||||||
|
if !fee.IsGTE(h.MinFee) {
|
||||||
return res, ErrInsufficientFees()
|
return res, ErrInsufficientFees()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.HasPermission(feeTx.Payer) {
|
// now, try to make a IPC call to coins...
|
||||||
return res, errors.ErrUnauthorized()
|
send := coin.NewSendOneTx(feeTx.Payer, h.Collector, coin.Coins{fee})
|
||||||
}
|
_, err = next(ctx, store, send)
|
||||||
|
|
||||||
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return next.DeliverTx(ctx, store, feeTx.Next())
|
return next(ctx, store, feeTx.Tx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,38 +7,38 @@ import (
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
const (
|
const (
|
||||||
ByteFees = 0x20
|
ByteFees = 0x21
|
||||||
TypeFees = "fee"
|
TypeFees = NameFee + "/tx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
basecoin.TxMapper.
|
basecoin.TxMapper.
|
||||||
RegisterImplementation(&Fee{}, TypeFees, ByteFees)
|
RegisterImplementation(Fee{}, TypeFees, ByteFees)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**** Fee ****/
|
/**** Fee ****/
|
||||||
|
|
||||||
var _ basecoin.TxLayer = &Fee{}
|
|
||||||
|
|
||||||
// Fee attaches a fee payment to the embedded tx
|
// Fee attaches a fee payment to the embedded tx
|
||||||
type Fee struct {
|
type Fee struct {
|
||||||
Tx basecoin.Tx `json:"tx"`
|
// Gas coin.Coin `json:"gas"` // ?????
|
||||||
Fee coin.Coin `json:"fee"`
|
Fee coin.Coin `json:"fee"`
|
||||||
Payer basecoin.Actor `json:"payer"` // the address who pays the 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
|
// nolint - TxInner Functions
|
||||||
func NewFee(tx basecoin.Tx, fee coin.Coin, payer basecoin.Actor) basecoin.Tx {
|
func (f Fee) ValidateBasic() error {
|
||||||
return (&Fee{Tx: tx, Fee: fee, Payer: payer}).Wrap()
|
|
||||||
}
|
|
||||||
func (f *Fee) ValidateBasic() error {
|
|
||||||
// TODO: more checks
|
// TODO: more checks
|
||||||
return f.Tx.ValidateBasic()
|
return f.Tx.ValidateBasic()
|
||||||
}
|
}
|
||||||
func (f *Fee) Wrap() basecoin.Tx {
|
func (f Fee) Wrap() basecoin.Tx {
|
||||||
return basecoin.Tx{f}
|
return basecoin.Tx{f}
|
||||||
}
|
}
|
||||||
func (f *Fee) Next() basecoin.Tx {
|
func (f Fee) Next() basecoin.Tx {
|
||||||
return f.Tx
|
return f.Tx
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
// check if the tx is proper type and valid
|
||||||
create, ok := tx.Unwrap().(CreateRoleTx)
|
create, ok := tx.Unwrap().(CreateRoleTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return create, errors.ErrInvalidFormat(tx)
|
return create, errors.ErrInvalidFormat(TypeCreateRoleTx, tx)
|
||||||
}
|
}
|
||||||
err = create.ValidateBasic()
|
err = create.ValidateBasic()
|
||||||
return create, err
|
return create, err
|
||||||
|
|
Loading…
Reference in New Issue