Merge pull request #1064 from cosmos/sunny/ante_fee_handle
Fee Collection in auth
This commit is contained in:
commit
cb1b6baa19
|
@ -41,6 +41,7 @@ type GaiaApp struct {
|
|||
|
||||
// Manage getting and setting accounts
|
||||
accountMapper auth.AccountMapper
|
||||
feeCollectionKeeper auth.FeeCollectionKeeper
|
||||
coinKeeper bank.Keeper
|
||||
ibcMapper ibc.Mapper
|
||||
stakeKeeper stake.Keeper
|
||||
|
@ -81,7 +82,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
|||
app.SetInitChainer(app.initChainer)
|
||||
app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper))
|
||||
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper))
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
||||
err := app.LoadLatestVersion(app.keyMain)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
|
|
|
@ -36,6 +36,7 @@ type BasecoinApp struct {
|
|||
|
||||
// Manage getting and setting accounts
|
||||
accountMapper auth.AccountMapper
|
||||
feeCollectionKeeper auth.FeeCollectionKeeper
|
||||
coinKeeper bank.Keeper
|
||||
ibcMapper ibc.Mapper
|
||||
stakeKeeper stake.Keeper
|
||||
|
@ -78,7 +79,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
|||
// Initialize BaseApp.
|
||||
app.SetInitChainer(app.initChainer)
|
||||
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper))
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
||||
err := app.LoadLatestVersion(app.keyMain)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
|
|
|
@ -39,6 +39,7 @@ type DemocoinApp struct {
|
|||
capKeyStakingStore *sdk.KVStoreKey
|
||||
|
||||
// keepers
|
||||
feeCollectionKeeper auth.FeeCollectionKeeper
|
||||
coinKeeper bank.Keeper
|
||||
coolKeeper cool.Keeper
|
||||
powKeeper pow.Keeper
|
||||
|
@ -89,7 +90,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
|
|||
// Initialize BaseApp.
|
||||
app.SetInitChainer(app.initChainerFn(app.coolKeeper, app.powKeeper))
|
||||
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper))
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
||||
err := app.LoadLatestVersion(app.capKeyMainStore)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
|
|
|
@ -9,13 +9,14 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
deductFeesCost sdk.Gas = 10
|
||||
verifyCost = 100
|
||||
)
|
||||
|
||||
// NewAnteHandler returns an AnteHandler that checks
|
||||
// and increments sequence numbers, checks signatures,
|
||||
// and deducts fees from the first signer.
|
||||
func NewAnteHandler(am AccountMapper) sdk.AnteHandler {
|
||||
func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||
|
||||
return func(
|
||||
ctx sdk.Context, tx sdk.Tx,
|
||||
|
@ -77,10 +78,12 @@ func NewAnteHandler(am AccountMapper) sdk.AnteHandler {
|
|||
if i == 0 {
|
||||
// TODO: min fee
|
||||
if !fee.Amount.IsZero() {
|
||||
ctx.GasMeter().ConsumeGas(deductFeesCost, "deductFees")
|
||||
signerAcc, res = deductFees(signerAcc, fee)
|
||||
if !res.IsOK() {
|
||||
return ctx, res, true
|
||||
}
|
||||
fck.addCollectedFees(ctx, fee.Amount)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,11 +69,12 @@ func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, f
|
|||
// Test various error cases in the AnteHandler control flow.
|
||||
func TestAnteHandlerSigErrors(t *testing.T) {
|
||||
// setup
|
||||
ms, capKey := setupMultiStore()
|
||||
ms, capKey, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
RegisterBaseAccount(cdc)
|
||||
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
|
||||
anteHandler := NewAnteHandler(mapper)
|
||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
|
||||
|
||||
// keys and addresses
|
||||
|
@ -110,11 +111,12 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
|||
// Test logic around sequence checking with one signer and many signers.
|
||||
func TestAnteHandlerSequences(t *testing.T) {
|
||||
// setup
|
||||
ms, capKey := setupMultiStore()
|
||||
ms, capKey, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
RegisterBaseAccount(cdc)
|
||||
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
|
||||
anteHandler := NewAnteHandler(mapper)
|
||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
|
||||
|
||||
// keys and addresses
|
||||
|
@ -176,11 +178,12 @@ func TestAnteHandlerSequences(t *testing.T) {
|
|||
// Test logic around fee deduction.
|
||||
func TestAnteHandlerFees(t *testing.T) {
|
||||
// setup
|
||||
ms, capKey := setupMultiStore()
|
||||
ms, capKey, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
RegisterBaseAccount(cdc)
|
||||
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
|
||||
anteHandler := NewAnteHandler(mapper)
|
||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
|
||||
|
||||
// keys and addresses
|
||||
|
@ -206,18 +209,23 @@ func TestAnteHandlerFees(t *testing.T) {
|
|||
mapper.SetAccount(ctx, acc1)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInsufficientFunds)
|
||||
|
||||
assert.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
||||
|
||||
acc1.SetCoins(sdk.Coins{{"atom", 150}})
|
||||
mapper.SetAccount(ctx, acc1)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
|
||||
assert.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(sdk.Coins{{"atom", 150}}))
|
||||
}
|
||||
|
||||
func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||
// setup
|
||||
ms, capKey := setupMultiStore()
|
||||
ms, capKey, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
RegisterBaseAccount(cdc)
|
||||
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
|
||||
anteHandler := NewAnteHandler(mapper)
|
||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
|
||||
|
||||
// keys and addresses
|
||||
|
@ -288,11 +296,12 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
|
||||
func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||
// setup
|
||||
ms, capKey := setupMultiStore()
|
||||
ms, capKey, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
RegisterBaseAccount(cdc)
|
||||
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
|
||||
anteHandler := NewAnteHandler(mapper)
|
||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
|
||||
|
||||
// keys and addresses
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
func TestContextWithSigners(t *testing.T) {
|
||||
ms, _ := setupMultiStore()
|
||||
ms, _, _ := setupMultiStore()
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
|
||||
|
||||
_, _, addr1 := keyPubAddr()
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
var (
|
||||
collectedFeesKey = []byte("collectedFees")
|
||||
)
|
||||
|
||||
// This FeeCollectionKeeper handles collection of fees in the anteHandler
|
||||
// and setting of MinFees for different fee tokens
|
||||
type FeeCollectionKeeper struct {
|
||||
|
||||
// The (unexposed) key used to access the fee store from the Context.
|
||||
key sdk.StoreKey
|
||||
|
||||
// The wire codec for binary encoding/decoding of accounts.
|
||||
cdc *wire.Codec
|
||||
}
|
||||
|
||||
// NewFeeKeeper returns a new FeeKeeper
|
||||
func NewFeeCollectionKeeper(cdc *wire.Codec, key sdk.StoreKey) FeeCollectionKeeper {
|
||||
return FeeCollectionKeeper{
|
||||
key: key,
|
||||
cdc: cdc,
|
||||
}
|
||||
}
|
||||
|
||||
// Adds to Collected Fee Pool
|
||||
func (fck FeeCollectionKeeper) GetCollectedFees(ctx sdk.Context) sdk.Coins {
|
||||
store := ctx.KVStore(fck.key)
|
||||
bz := store.Get(collectedFeesKey)
|
||||
if bz == nil {
|
||||
return sdk.Coins{}
|
||||
}
|
||||
|
||||
feePool := &(sdk.Coins{})
|
||||
fck.cdc.MustUnmarshalBinary(bz, feePool)
|
||||
return *feePool
|
||||
}
|
||||
|
||||
// Sets to Collected Fee Pool
|
||||
func (fck FeeCollectionKeeper) setCollectedFees(ctx sdk.Context, coins sdk.Coins) {
|
||||
bz := fck.cdc.MustMarshalBinary(coins)
|
||||
store := ctx.KVStore(fck.key)
|
||||
store.Set(collectedFeesKey, bz)
|
||||
}
|
||||
|
||||
// Adds to Collected Fee Pool
|
||||
func (fck FeeCollectionKeeper) addCollectedFees(ctx sdk.Context, coins sdk.Coins) sdk.Coins {
|
||||
newCoins := fck.GetCollectedFees(ctx).Plus(coins)
|
||||
fck.setCollectedFees(ctx, newCoins)
|
||||
|
||||
return newCoins
|
||||
}
|
||||
|
||||
// Clears the collected Fee Pool
|
||||
func (fck FeeCollectionKeeper) ClearCollectedFees(ctx sdk.Context) {
|
||||
fck.setCollectedFees(ctx, sdk.Coins{})
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
var (
|
||||
emptyCoins = sdk.Coins{}
|
||||
oneCoin = sdk.Coins{{"foocoin", 1}}
|
||||
twoCoins = sdk.Coins{{"foocoin", 2}}
|
||||
)
|
||||
|
||||
func TestFeeCollectionKeeperGetSet(t *testing.T) {
|
||||
ms, _, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
|
||||
// make context and keeper
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger())
|
||||
fck := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
|
||||
// no coins initially
|
||||
currFees := fck.GetCollectedFees(ctx)
|
||||
assert.True(t, currFees.IsEqual(emptyCoins))
|
||||
|
||||
// set feeCollection to oneCoin
|
||||
fck.setCollectedFees(ctx, oneCoin)
|
||||
|
||||
// check that it is equal to oneCoin
|
||||
assert.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin))
|
||||
}
|
||||
|
||||
func TestFeeCollectionKeeperAdd(t *testing.T) {
|
||||
ms, _, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
|
||||
// make context and keeper
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger())
|
||||
fck := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
|
||||
// no coins initially
|
||||
assert.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
||||
|
||||
// add oneCoin and check that pool is now oneCoin
|
||||
fck.addCollectedFees(ctx, oneCoin)
|
||||
assert.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin))
|
||||
|
||||
// add oneCoin again and check that pool is now twoCoins
|
||||
fck.addCollectedFees(ctx, oneCoin)
|
||||
assert.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins))
|
||||
}
|
||||
|
||||
func TestFeeCollectionKeeperClear(t *testing.T) {
|
||||
ms, _, capKey2 := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
|
||||
// make context and keeper
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger())
|
||||
fck := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
|
||||
// set coins initially
|
||||
fck.setCollectedFees(ctx, twoCoins)
|
||||
assert.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins))
|
||||
|
||||
// clear fees and see that pool is now empty
|
||||
fck.ClearCollectedFees(ctx)
|
||||
assert.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
||||
}
|
|
@ -14,17 +14,19 @@ import (
|
|||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) {
|
||||
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) {
|
||||
db := dbm.NewMemDB()
|
||||
capKey := sdk.NewKVStoreKey("capkey")
|
||||
capKey2 := sdk.NewKVStoreKey("capkey2")
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(capKey2, sdk.StoreTypeIAVL, db)
|
||||
ms.LoadLatestVersion()
|
||||
return ms, capKey
|
||||
return ms, capKey, capKey2
|
||||
}
|
||||
|
||||
func TestAccountMapperGetSet(t *testing.T) {
|
||||
ms, capKey := setupMultiStore()
|
||||
ms, capKey, _ := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
RegisterBaseAccount(cdc)
|
||||
|
||||
|
|
Loading…
Reference in New Issue