Skip to content

Commit

Permalink
Merge pull request cosmos#1064 from cosmos/sunny/ante_fee_handle
Browse files Browse the repository at this point in the history
Fee Collection in auth
  • Loading branch information
rigelrozanski authored May 26, 2018
2 parents 5d7c3af + bf02cdc commit cb1b6ba
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 32 deletions.
11 changes: 6 additions & 5 deletions cmd/gaia/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ type GaiaApp struct {
keyStake *sdk.KVStoreKey

// Manage getting and setting accounts
accountMapper auth.AccountMapper
coinKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
accountMapper auth.AccountMapper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
}

func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
Expand Down Expand Up @@ -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())
Expand Down
11 changes: 6 additions & 5 deletions examples/basecoin/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ type BasecoinApp struct {
keyStake *sdk.KVStoreKey

// Manage getting and setting accounts
accountMapper auth.AccountMapper
coinKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
accountMapper auth.AccountMapper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
}

func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
Expand Down Expand Up @@ -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())
Expand Down
13 changes: 7 additions & 6 deletions examples/democoin/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ type DemocoinApp struct {
capKeyStakingStore *sdk.KVStoreKey

// keepers
coinKeeper bank.Keeper
coolKeeper cool.Keeper
powKeeper pow.Keeper
ibcMapper ibc.Mapper
stakeKeeper simplestake.Keeper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
coolKeeper cool.Keeper
powKeeper pow.Keeper
ibcMapper ibc.Mapper
stakeKeeper simplestake.Keeper

// Manage getting and setting accounts
accountMapper auth.AccountMapper
Expand Down Expand Up @@ -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())
Expand Down
7 changes: 5 additions & 2 deletions x/auth/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import (
)

const (
verifyCost = 100
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,
Expand Down Expand Up @@ -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)
}
}

Expand Down
29 changes: 19 additions & 10 deletions x/auth/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion x/auth/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
62 changes: 62 additions & 0 deletions x/auth/feekeeper.go
Original file line number Diff line number Diff line change
@@ -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{})
}
75 changes: 75 additions & 0 deletions x/auth/feekeeper_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
8 changes: 5 additions & 3 deletions x/auth/mapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down

0 comments on commit cb1b6ba

Please sign in to comment.