Skip to content

Commit

Permalink
Merge pull request #257 from persistenceOne/ajeet/fee-denom-fixes
Browse files Browse the repository at this point in the history
feat: fee denoms whiltelist decorator
  • Loading branch information
Max Kupriianov authored Nov 29, 2023
2 parents f32cbe3 + d64177b commit 6aba7c9
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 1 deletion.
3 changes: 3 additions & 0 deletions app/ante_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type HandlerOptions struct {
TxDecoder sdk.TxDecoder
TxEncoder sdk.TxEncoder
BuilderKeeper *builderkeeper.Keeper

FeeDenomsWhitelist []string
}

func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
Expand Down Expand Up @@ -57,6 +59,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
NewFeeDenomWhitelistDecorator(options.FeeDenomsWhitelist),
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
// SetPubKeyDecorator must be called before all signature verification decorators
ante.NewSetPubKeyDecorator(options.AccountKeeper),
Expand Down
14 changes: 14 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ func (app *Application) setupPOBAndAnteHandler(wasmConfig wasmtypes.WasmConfig)
Mempool: mempool,
TxDecoder: app.txConfig.TxDecoder(),
TxEncoder: app.txConfig.TxEncoder(),

FeeDenomsWhitelist: app.GetFeeDenomsWhitelist(),
}
anteHandler, err := NewAnteHandler(anteOptions)
if err != nil {
Expand Down Expand Up @@ -330,6 +332,18 @@ func (app *Application) GetChainBondDenom() string {
return "stake"
}

func (app *Application) GetFeeDenomsWhitelist() []string {
chainID := app.ChainID()

if strings.HasPrefix(chainID, "core-") {
return FeeDenomsWhitelistMainnet
} else if strings.HasPrefix(chainID, "test-core-") {
return FeeDenomsWhitelistTestnet
}

return []string{"stake"}
}

// CheckTx will check the transaction with the provided checkTxHandler. We override the default
// handler so that we can verify bid transactions before they are inserted into the mempool.
// With the POB CheckTx, we can verify the bid transaction and all of the bundled transactions
Expand Down
12 changes: 12 additions & 0 deletions app/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,15 @@ const (
Bech32PrefixConsAddr = Bech32MainPrefix + sdk.PrefixValidator + sdk.PrefixConsensus
Bech32PrefixConsPub = Bech32MainPrefix + sdk.PrefixValidator + sdk.PrefixConsensus + sdk.PrefixPublic
)

var (
FeeDenomsWhitelistMainnet = []string{
BondDenom, // XPRT
"ibc/C8A74ABBE2AF892E15680D916A7C22130585CE5704F9B17A10F184A90D53BECA", // ATOM
}

FeeDenomsWhitelistTestnet = []string{
BondDenom, // XPRT
"ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9", // ATOM
}
)
53 changes: 53 additions & 0 deletions app/fee_denom_whitelist_decorator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package app

import (
"fmt"
"strings"

errorsmod "cosmossdk.io/errors"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

type FeeDenomWhitelistDecorator struct {
whitelistMap map[string]struct{}
whitelistStr string // this is used for err msg only
}

func NewFeeDenomWhitelistDecorator(denomsWhitelist []string) *FeeDenomWhitelistDecorator {
if len(denomsWhitelist) == 0 {
panic("at least one fee denom must be whitelisted")
}

whitelistMap := map[string]struct{}{}
for _, denom := range denomsWhitelist {
// must be valid denom
if err := sdk.ValidateDenom(denom); err != nil {
panic(fmt.Sprintf("invalid denoms whiltelist; err: %v", err))
}
whitelistMap[denom] = struct{}{}
}

return &FeeDenomWhitelistDecorator{
whitelistMap: whitelistMap,
whitelistStr: strings.Join(denomsWhitelist, ","),
}
}

func (fdd *FeeDenomWhitelistDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}

feeCoins := feeTx.GetFee()
for _, coin := range feeCoins {
if _, found := fdd.whitelistMap[coin.Denom]; !found {
return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidCoins,
"fee denom is not allowed; got: %v, allowed: %v",
coin.Denom, fdd.whitelistStr)
}
}
return next(ctx, tx, simulate)
}
112 changes: 112 additions & 0 deletions app/fee_denom_whitelist_decorator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package app

import (
"testing"

"cosmossdk.io/math"
"github.com/stretchr/testify/require"

"github.com/cometbft/cometbft/libs/log"
tmtypes "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

func TestFeeDenomWhiltelistDecorator(t *testing.T) {
testcases := []struct {
name string
txFee sdk.Coins
denomsWhitelist []string
expectedErr string
panics bool
}{
{
name: "empty denoms list",
txFee: coins(),
denomsWhitelist: []string{},
expectedErr: "at least one fee denom must be whitelisted",
panics: true,
},
{
name: "invalid denoms list",
txFee: coins(),
denomsWhitelist: []string{"a"},
expectedErr: "invalid denoms whiltelist; err: invalid denom: a",
panics: true,
},
{
name: "valid denoms - valid fee",
txFee: coins(10, "uxprt"),
denomsWhitelist: FeeDenomsWhitelistMainnet,
expectedErr: "",
},
{
name: "valid denoms - multiple valid fees",
txFee: coins(10, FeeDenomsWhitelistMainnet[1], 10, "uxprt"),
denomsWhitelist: FeeDenomsWhitelistMainnet,
expectedErr: "",
},
{
name: "valid denoms - invalid fee",
txFee: coins(10, "abcd"),
denomsWhitelist: FeeDenomsWhitelistMainnet,
expectedErr: "fee denom is not allowed; got: abcd, allowed: uxprt,ibc/C8A74ABBE2AF892E15680D916A7C22130585CE5704F9B17A10F184A90D53BECA: invalid coins",
},
{
name: "valid denoms - multiple invalid fee",
txFee: coins(10, "uxprt", 10, "xyz"),
denomsWhitelist: FeeDenomsWhitelistMainnet,
expectedErr: "fee denom is not allowed; got: xyz, allowed: uxprt,ibc/C8A74ABBE2AF892E15680D916A7C22130585CE5704F9B17A10F184A90D53BECA: invalid coins",
},
}

isCheckTx := false
ctx := sdk.NewContext(nil, tmtypes.Header{}, isCheckTx, log.NewNopLogger())
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
defer func() {
r := recover()
if tc.panics {
require.Equal(t, r, tc.expectedErr)
} else {
require.Nil(t, r, "Test did not panic")
}
}()

fdd := NewFeeDenomWhitelistDecorator(tc.denomsWhitelist)
antehandlerFFD := sdk.ChainAnteDecorators(fdd)
tx := &mockFeeTx{fee: tc.txFee}

_, err := antehandlerFFD(ctx, tx, false)

if tc.expectedErr == "" {
require.NoError(t, err)
} else {
require.EqualError(t, err, tc.expectedErr)
}
})
}
}

func coins(amountDenomPairs ...interface{}) sdk.Coins {
coins := sdk.Coins{}
for i := 0; i < len(amountDenomPairs); i += 2 {
coins = append(coins, sdk.Coin{
Amount: math.NewInt(int64(amountDenomPairs[i].(int))),
Denom: amountDenomPairs[i+1].(string),
})
}
return coins
}

var _ sdk.Tx = (*mockFeeTx)(nil)
var _ sdk.FeeTx = (*mockFeeTx)(nil)

type mockFeeTx struct{ fee sdk.Coins }

func (m *mockFeeTx) GetFee() sdk.Coins { return m.fee }
func (m *mockFeeTx) GetGas() uint64 { return 1 }

func (*mockFeeTx) FeeGranter() sdk.AccAddress { return nil }
func (*mockFeeTx) FeePayer() sdk.AccAddress { return nil }
func (*mockFeeTx) GetMsgs() []sdk.Msg { return nil }
func (*mockFeeTx) ValidateBasic() error { return nil }
2 changes: 1 addition & 1 deletion docker/persistencecore/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ WORKDIR /usr/local/app
COPY . .

# Force it to use static lib (from above) not standard libgo_cosmwasm.so file
RUN LEDGER_ENABLED=false BUILD_TAGS="muslc linkstatic" make build
RUN LEDGER_ENABLED=true BUILD_TAGS="muslc linkstatic" LDFLAGS='-linkmode external -extldflags "-static"' make build
RUN echo "Ensuring binary is statically linked ..." \
&& (file /usr/local/app/bin/persistenceCore | grep "statically linked")

Expand Down

0 comments on commit 6aba7c9

Please sign in to comment.