From c1a10ebe85a7789fcc56e6cb4ca879ade97d3f0e Mon Sep 17 00:00:00 2001 From: David Terpay <35130517+davidterpay@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:05:53 -0500 Subject: [PATCH 1/2] feat: Fuzz testing default + AIMD params (#42) * init * delta unit testing * nit * randomizing params * random num gen nit * delta modification * nit * lint * target to max ratio fixed --- x/feemarket/fuzz/aimd_eip1559_test.go | 146 ++++++++++++++++++++++++ x/feemarket/fuzz/eip1559_test.go | 98 ++++++++++++++++ x/feemarket/types/state_test.go | 154 ++++++++++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 x/feemarket/fuzz/aimd_eip1559_test.go create mode 100644 x/feemarket/fuzz/eip1559_test.go diff --git a/x/feemarket/fuzz/aimd_eip1559_test.go b/x/feemarket/fuzz/aimd_eip1559_test.go new file mode 100644 index 0000000..54e0b77 --- /dev/null +++ b/x/feemarket/fuzz/aimd_eip1559_test.go @@ -0,0 +1,146 @@ +package fuzz_test + +import ( + "testing" + + "cosmossdk.io/math" + "github.com/skip-mev/feemarket/x/feemarket/types" + "github.com/stretchr/testify/require" + "pgregory.net/rapid" +) + +// TestAIMDLearningRate ensure's that the additive increase +// multiplicative decrease learning rate algorithm correctly +// adjusts the learning rate. In particular, if the block +// utilization is greater than theta or less than 1 - theta, then +// the learning rate is increased by the additive increase +// parameter. Otherwise, the learning rate is decreased by +// the multiplicative decrease parameter. +func TestAIMDLearningRate(t *testing.T) { + rapid.Check(t, func(t *rapid.T) { + state := types.DefaultAIMDState() + window := rapid.Int64Range(1, 50).Draw(t, "window") + state.Window = make([]uint64, window) + + params := CreateRandomAIMDParams(t) + + // Randomly generate the block utilization. + numBlocks := rapid.Uint64Range(0, 1000).Draw(t, "num_blocks") + gasGen := rapid.Uint64Range(0, params.MaxBlockUtilization) + + // Update the fee market. + for i := uint64(0); i < numBlocks; i++ { + blockUtilization := gasGen.Draw(t, "gas") + prevLearningRate := state.LearningRate + + // Update the fee market. + if err := state.Update(blockUtilization, params); err != nil { + t.Fatalf("block update errors: %v", err) + } + + // Update the learning rate. + lr := state.UpdateLearningRate(params) + utilization := state.GetAverageUtilization(params) + + // Ensure that the learning rate is always bounded. + require.True(t, lr.GTE(params.MinLearningRate)) + require.True(t, lr.LTE(params.MaxLearningRate)) + + if utilization.LTE(params.Theta) || utilization.GTE(math.LegacyOneDec().Sub(params.Theta)) { + require.True(t, lr.GTE(prevLearningRate)) + } else { + require.True(t, lr.LTE(prevLearningRate)) + } + + // Update the current height. + state.IncrementHeight() + } + }) +} + +// TestAIMDBaseFee ensure's that the additive increase multiplicative +// decrease base fee adjustment algorithm correctly adjusts the base +// fee. In particular, the base fee should function the same as the +// default EIP-1559 base fee adjustment algorithm. +func TestAIMDBaseFee(t *testing.T) { + rapid.Check(t, func(t *rapid.T) { + state := types.DefaultAIMDState() + window := rapid.Int64Range(1, 50).Draw(t, "window") + state.Window = make([]uint64, window) + + params := CreateRandomAIMDParams(t) + + // Randomly generate the block utilization. + numBlocks := rapid.Uint64Range(0, uint64(window)*10).Draw(t, "num_blocks") + gasGen := rapid.Uint64Range(0, params.MaxBlockUtilization) + + // Update the fee market. + for i := uint64(0); i < numBlocks; i++ { + blockUtilization := gasGen.Draw(t, "gas") + prevBaseFee := state.BaseFee + + if err := state.Update(blockUtilization, params); err != nil { + t.Fatalf("block update errors: %v", err) + } + + // Update the learning rate. + state.UpdateLearningRate(params) + // Update the base fee. + state.UpdateBaseFee(params) + + // Ensure that the minimum base fee is always less than the base fee. + require.True(t, params.MinBaseFee.LTE(state.BaseFee)) + + switch { + case blockUtilization > params.TargetBlockUtilization: + require.True(t, state.BaseFee.GTE(prevBaseFee)) + case blockUtilization < params.TargetBlockUtilization: + require.True(t, state.BaseFee.LTE(prevBaseFee)) + default: + + // Account for the delta adjustment. + net := state.GetNetUtilization(params) + switch { + case net.GT(math.ZeroInt()): + require.True(t, state.BaseFee.GTE(prevBaseFee)) + case net.LT(math.ZeroInt()): + require.True(t, state.BaseFee.LTE(prevBaseFee)) + default: + require.True(t, state.BaseFee.Equal(prevBaseFee)) + } + } + + // Update the current height. + state.IncrementHeight() + } + }) +} + +// CreateRandomAIMDParams returns a random set of parameters for the AIMD +// EIP-1559 fee market implementation. +func CreateRandomAIMDParams(t *rapid.T) types.Params { + a := rapid.Uint64Range(1, 1000).Draw(t, "alpha") + alpha := math.LegacyNewDec(int64(a)).Quo(math.LegacyNewDec(1000)) + + b := rapid.Uint64Range(50, 99).Draw(t, "beta") + beta := math.LegacyNewDec(int64(b)).Quo(math.LegacyNewDec(100)) + + th := rapid.Uint64Range(10, 90).Draw(t, "theta") + theta := math.LegacyNewDec(int64(th)).Quo(math.LegacyNewDec(100)) + + d := rapid.Uint64Range(1, 1000).Draw(t, "delta") + delta := math.LegacyNewDec(int64(d)).Quo(math.LegacyNewDec(1000)) + + targetBlockUtilization := rapid.Uint64Range(1, 30_000_000).Draw(t, "target_block_utilization") + maxBlockUtilization := rapid.Uint64Range(targetBlockUtilization, targetBlockUtilization*5).Draw(t, "max_block_utilization") + + params := types.DefaultAIMDParams() + params.Alpha = alpha + params.Beta = beta + params.Theta = theta + params.Delta = delta + params.MaxBlockUtilization = maxBlockUtilization + params.TargetBlockUtilization = targetBlockUtilization + + return params +} diff --git a/x/feemarket/fuzz/eip1559_test.go b/x/feemarket/fuzz/eip1559_test.go new file mode 100644 index 0000000..36092d3 --- /dev/null +++ b/x/feemarket/fuzz/eip1559_test.go @@ -0,0 +1,98 @@ +package fuzz_test + +import ( + "testing" + + "cosmossdk.io/math" + "github.com/skip-mev/feemarket/x/feemarket/types" + "github.com/stretchr/testify/require" + "pgregory.net/rapid" +) + +// TestLearningRate ensure's that the learning rate is always +// constant for the default EIP-1559 implementation. +func TestLearningRate(t *testing.T) { + rapid.Check(t, func(t *rapid.T) { + state := types.DefaultState() + params := CreateRandomParams(t) + + // Randomly generate alpha and beta. + prevLearningRate := state.LearningRate + + // Randomly generate the block utilization. + blockUtilization := rapid.Uint64Range(0, params.MaxBlockUtilization).Draw(t, "gas") + + // Update the fee market. + if err := state.Update(blockUtilization, params); err != nil { + t.Fatalf("block update errors: %v", err) + } + + // Update the learning rate. + lr := state.UpdateLearningRate(params) + require.Equal(t, types.DefaultMinLearningRate, lr) + require.Equal(t, prevLearningRate, state.LearningRate) + }) +} + +// TestBaseFee ensure's that the base fee moves in the correct +// direction for the default EIP-1559 implementation. +func TestBaseFee(t *testing.T) { + rapid.Check(t, func(t *rapid.T) { + state := types.DefaultState() + params := CreateRandomParams(t) + + // Update the current base fee to be 10% higher than the minimum base fee. + prevBaseFee := state.BaseFee.Mul(math.NewInt(11)).Quo(math.NewInt(10)) + state.BaseFee = prevBaseFee + + // Randomly generate the block utilization. + blockUtilization := rapid.Uint64Range(0, params.MaxBlockUtilization).Draw(t, "gas") + + // Update the fee market. + if err := state.Update(blockUtilization, params); err != nil { + t.Fatalf("block update errors: %v", err) + } + + // Update the learning rate. + state.UpdateLearningRate(params) + // Update the base fee. + state.UpdateBaseFee(params) + + // Ensure that the minimum base fee is always less than the base fee. + require.True(t, params.MinBaseFee.LTE(state.BaseFee)) + + switch { + case blockUtilization > params.TargetBlockUtilization: + require.True(t, state.BaseFee.GTE(prevBaseFee)) + case blockUtilization < params.TargetBlockUtilization: + require.True(t, state.BaseFee.LTE(prevBaseFee)) + default: + require.Equal(t, state.BaseFee, prevBaseFee) + } + }) +} + +// CreateRandomParams returns a random set of parameters for the default +// EIP-1559 fee market implementation. +func CreateRandomParams(t *rapid.T) types.Params { + a := rapid.Uint64Range(1, 1000).Draw(t, "alpha") + alpha := math.LegacyNewDec(int64(a)).Quo(math.LegacyNewDec(1000)) + + b := rapid.Uint64Range(50, 99).Draw(t, "beta") + beta := math.LegacyNewDec(int64(b)).Quo(math.LegacyNewDec(100)) + + th := rapid.Uint64Range(10, 90).Draw(t, "theta") + theta := math.LegacyNewDec(int64(th)).Quo(math.LegacyNewDec(100)) + + targetBlockUtilization := rapid.Uint64Range(1, 30_000_000).Draw(t, "target_block_utilization") + maxBlockUtilization := rapid.Uint64Range(targetBlockUtilization, targetBlockUtilization*5).Draw(t, "max_block_utilization") + + params := types.DefaultParams() + params.Alpha = alpha + params.Beta = beta + params.Theta = theta + params.MaxBlockUtilization = maxBlockUtilization + params.TargetBlockUtilization = targetBlockUtilization + + return params +} diff --git a/x/feemarket/types/state_test.go b/x/feemarket/types/state_test.go index 6dcd6e5..758bc50 100644 --- a/x/feemarket/types/state_test.go +++ b/x/feemarket/types/state_test.go @@ -234,6 +234,160 @@ func TestState_UpdateBaseFee(t *testing.T) { expectedBaseFee := params.MinBaseFee require.True(t, expectedBaseFee.Equal(newBaseFee)) }) + + t.Run("empty blocks with aimd eip1559 with a delta", func(t *testing.T) { + // Instantiate the params with a delta. + params := types.DefaultAIMDParams() + + paramsWithDelta := types.DefaultAIMDParams() + delta := math.LegacyNewDec(10) + paramsWithDelta.Delta = delta + + // Empty blocks + state := types.DefaultAIMDState() + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + lr := state.UpdateLearningRate(params) + bf := state.UpdateBaseFee(params) + + state = types.DefaultAIMDState() + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + lrWithDelta := state.UpdateLearningRate(paramsWithDelta) + bfWithDelta := state.UpdateBaseFee(paramsWithDelta) + + // Ensure that the learning rate is the same. + require.Equal(t, lr, lrWithDelta) + + // Ensure that the base fee is less with the delta. + require.True(t, bfWithDelta.LT(bf)) + }) + + t.Run("full blocks with aimd eip1559 with a delta", func(t *testing.T) { + // Instantiate the params with a delta. + params := types.DefaultAIMDParams() + + paramsWithDelta := types.DefaultAIMDParams() + delta := math.LegacyNewDec(10) + paramsWithDelta.Delta = delta + + // Empty blocks + state := types.DefaultAIMDState() + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + for i := 0; i < len(state.Window); i++ { + state.Window[i] = params.MaxBlockUtilization + } + + lr := state.UpdateLearningRate(params) + bf := state.UpdateBaseFee(params) + + state = types.DefaultAIMDState() + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + for i := 0; i < len(state.Window); i++ { + state.Window[i] = params.MaxBlockUtilization + } + + lrWithDelta := state.UpdateLearningRate(paramsWithDelta) + bfWithDelta := state.UpdateBaseFee(paramsWithDelta) + + // Ensure that the learning rate is the same. + require.Equal(t, lr, lrWithDelta) + + // Ensure that the base fee is greater with the delta. + require.True(t, bfWithDelta.GT(bf)) + }) + + t.Run("target blocks with aimd eip1559 with a delta", func(t *testing.T) { + // Instantiate the params with a delta. + params := types.DefaultAIMDParams() + + paramsWithDelta := types.DefaultAIMDParams() + delta := math.LegacyNewDec(10) + paramsWithDelta.Delta = delta + + // Empty blocks + state := types.DefaultAIMDState() + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + for i := 0; i < len(state.Window); i++ { + state.Window[i] = params.TargetBlockUtilization + } + + lr := state.UpdateLearningRate(params) + bf := state.UpdateBaseFee(params) + + state = types.DefaultAIMDState() + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + for i := 0; i < len(state.Window); i++ { + state.Window[i] = params.TargetBlockUtilization + } + + lrWithDelta := state.UpdateLearningRate(paramsWithDelta) + bfWithDelta := state.UpdateBaseFee(paramsWithDelta) + + // Ensure that the learning rate is the same. + require.Equal(t, lr, lrWithDelta) + + // Ensure that the base fee's are equal. + require.Equal(t, bf, bfWithDelta) + }) + + t.Run("half target block size with aimd eip1559 with a delta", func(t *testing.T) { + state := types.DefaultAIMDState() + state.Window = make([]uint64, 1) + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + prevBF := state.BaseFee + + // Instantiate the params with a delta. + params := types.DefaultAIMDParams() + params.Window = 1 + params.Delta = math.LegacyNewDec(10) + + // 1/4th of the window is full. + state.Window[0] = params.TargetBlockUtilization / 2 + + prevLR := state.LearningRate + lr := state.UpdateLearningRate(params) + bf := state.UpdateBaseFee(params) + + expectedUtilization := math.LegacyMustNewDecFromStr("-0.5") + expectedLR := prevLR.Add(params.Alpha) + expectedLRAdjustment := (expectedLR.Mul(expectedUtilization)).Add(math.LegacyOneDec()) + + expectedNetUtilization := math.LegacyNewDec(-1 * int64(params.TargetBlockUtilization) / 2) + deltaDiff := expectedNetUtilization.Mul(params.Delta) + expectedFee := (math.LegacyNewDecFromInt(prevBF).Mul(expectedLRAdjustment)).Add(deltaDiff).TruncateInt() + + require.Equal(t, expectedLR, lr) + require.Equal(t, expectedFee, bf) + }) + + t.Run("3/4 max block size with aimd eip1559 with a delta", func(t *testing.T) { + state := types.DefaultAIMDState() + state.Window = make([]uint64, 1) + state.BaseFee = state.BaseFee.Mul(math.NewInt(10)) + prevBF := state.BaseFee + + // Instantiate the params with a delta. + params := types.DefaultAIMDParams() + params.Window = 1 + params.Delta = math.LegacyNewDec(10) + + // 1/4th of the window is full. + state.Window[0] = params.MaxBlockUtilization / 4 * 3 + + prevLR := state.LearningRate + lr := state.UpdateLearningRate(params) + bf := state.UpdateBaseFee(params) + + expectedUtilization := math.LegacyMustNewDecFromStr("0.5") + expectedLR := prevLR.Add(params.Alpha) + expectedLRAdjustment := (expectedLR.Mul(expectedUtilization)).Add(math.LegacyOneDec()) + + expectedNetUtilization := math.LegacyNewDec(int64(params.MaxBlockUtilization) / 4) + deltaDiff := expectedNetUtilization.Mul(params.Delta) + expectedFee := (math.LegacyNewDecFromInt(prevBF).Mul(expectedLRAdjustment)).Add(deltaDiff).TruncateInt() + + require.Equal(t, expectedLR, lr) + require.Equal(t, expectedFee, bf) + }) } func TestState_UpdateLearningRate(t *testing.T) { From bf2b1359f8961c857ed2226175e90ca5cc488cf3 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Tue, 5 Dec 2023 11:41:30 -0500 Subject: [PATCH 2/2] refactor: clean up posthandler logic and tests (#39) * clean * fix * state query * test: * wip * remove test * fix * fix * wip * wrong * working * fix * fix * refactor to use params * clean * wip * fix * refactor * fix * fix --------- Co-authored-by: David Terpay <35130517+davidterpay@users.noreply.github.com> --- tests/integration/setup.go | 1 + tests/integration/suite.go | 4 ++-- x/feemarket/ante/fee.go | 40 ++++++++++++++++++++++++++---------- x/feemarket/post/fee.go | 6 ++++-- x/feemarket/post/fee_test.go | 24 ++++++++++++++++++++-- x/feemarket/types/keys.go | 1 + 6 files changed, 59 insertions(+), 17 deletions(-) diff --git a/tests/integration/setup.go b/tests/integration/setup.go index a4482d6..c37efcb 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -453,6 +453,7 @@ func (s *TestSuite) GetAndFundTestUsers( return users } +// ExecTx executes a cli command on a node, waits a block and queries the Tx to verify it was included on chain. func (s *TestSuite) ExecTx(ctx context.Context, chain *cosmos.CosmosChain, keyName string, command ...string) (string, error) { node := chain.FullNodes[0] diff --git a/tests/integration/suite.go b/tests/integration/suite.go index 716ba54..06984a1 100644 --- a/tests/integration/suite.go +++ b/tests/integration/suite.go @@ -109,8 +109,7 @@ func (s *TestSuite) SetupSubTest() { state := s.QueryState() - s.T().Log("new test case at block height", height+1) - s.T().Log("state:", state.String()) + s.T().Log("state at block height", height+1, ":", state.String()) } func (s *TestSuite) TestQueryParams() { @@ -171,5 +170,6 @@ func (s *TestSuite) TestSendTxUpdating() { gas, ) s.Require().NoError(err, txResp) + s.T().Log(txResp) }) } diff --git a/x/feemarket/ante/fee.go b/x/feemarket/ante/fee.go index 170dc4b..307055a 100644 --- a/x/feemarket/ante/fee.go +++ b/x/feemarket/ante/fee.go @@ -56,7 +56,7 @@ func (dfd FeeMarketCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula ) if !simulate { - fee, _, err = CheckTxFees(minGasPrices, feeTx, gas) + fee, _, err = CheckTxFees(ctx, minGasPrices, feeTx, true) if err != nil { return ctx, errorsmod.Wrapf(err, "error checking fee") } @@ -69,30 +69,48 @@ func (dfd FeeMarketCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula // CheckTxFees implements the logic for the fee market to check if a Tx has provided sufficient // fees given the current state of the fee market. Returns an error if insufficient fees. -func CheckTxFees(minFees sdk.Coins, feeTx sdk.FeeTx, gas uint64) (feeCoins sdk.Coins, tip sdk.Coins, err error) { - feesDec := sdk.NewDecCoinsFromCoins(minFees...) - +func CheckTxFees(ctx sdk.Context, minFees sdk.Coins, feeTx sdk.FeeTx, isCheck bool) (feeCoins sdk.Coins, tip sdk.Coins, err error) { + minFeesDecCoins := sdk.NewDecCoinsFromCoins(minFees...) feeCoins = feeTx.GetFee() // Ensure that the provided fees meet the minimum - minGasPrices := feesDec + minGasPrices := minFeesDecCoins if !minGasPrices.IsZero() { requiredFees := make(sdk.Coins, len(minGasPrices)) + consumedFees := make(sdk.Coins, len(minGasPrices)) // Determine the required fees by multiplying each required minimum gas // price by the gas, where fee = ceil(minGasPrice * gas). - glDec := sdkmath.LegacyNewDec(int64(gas)) + gasConsumed := int64(ctx.GasMeter().GasConsumed()) + gcDec := sdkmath.LegacyNewDec(gasConsumed) + glDec := sdkmath.LegacyNewDec(int64(feeTx.GetGas())) + for i, gp := range minGasPrices { - fee := gp.Amount.Mul(glDec) - requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + consumedFee := gp.Amount.Mul(gcDec) + limitFee := gp.Amount.Mul(glDec) + consumedFees[i] = sdk.NewCoin(gp.Denom, consumedFee.Ceil().RoundInt()) + requiredFees[i] = sdk.NewCoin(gp.Denom, limitFee.Ceil().RoundInt()) } if !feeCoins.IsAnyGTE(requiredFees) { - return nil, nil, sdkerrors.ErrInsufficientFee.Wrapf("got: %s required: %s, minGasPrices: %s, gas: %d", feeCoins, requiredFees, minGasPrices, gas) + return nil, nil, sdkerrors.ErrInsufficientFee.Wrapf( + "got: %s required: %s, minGasPrices: %s, gas: %d", + feeCoins, + requiredFees, + minGasPrices, + gasConsumed, + ) } - tip = feeCoins.Sub(minFees...) // tip is the difference between feeCoins and the min fees - feeCoins = requiredFees // set fee coins to be ONLY the required amount + if isCheck { + // set fee coins to be required amount if checking + feeCoins = requiredFees + } else { + // tip is the difference between feeCoins and the required fees + tip = feeCoins.Sub(requiredFees...) + // set fee coins to be ONLY the consumed amount if we are calculated consumed fee to deduct + feeCoins = consumedFees + } } return feeCoins, tip, nil diff --git a/x/feemarket/post/fee.go b/x/feemarket/post/fee.go index 9486f5b..505b0e3 100644 --- a/x/feemarket/post/fee.go +++ b/x/feemarket/post/fee.go @@ -84,7 +84,7 @@ func (dfd FeeMarketDeductDecorator) PostHandle(ctx sdk.Context, tx sdk.Tx, simul ) if !simulate { - fee, tip, err = ante.CheckTxFees(minGasPrices, feeTx, gas) + fee, tip, err = ante.CheckTxFees(ctx, minGasPrices, feeTx, false) if err != nil { return ctx, err } @@ -156,8 +156,9 @@ func (dfd FeeMarketDeductDecorator) DeductFeeAndTip(ctx sdk.Context, sdkTx sdk.T } } + proposer := sdk.AccAddress(ctx.BlockHeader().ProposerAddress) if !tip.IsZero() { - err := SendTip(dfd.bankKeeper, ctx, deductFeesFromAcc.GetAddress(), ctx.BlockHeader().ProposerAddress, tip) + err := SendTip(dfd.bankKeeper, ctx, deductFeesFromAcc.GetAddress(), proposer, tip) if err != nil { return err } @@ -170,6 +171,7 @@ func (dfd FeeMarketDeductDecorator) DeductFeeAndTip(ctx sdk.Context, sdkTx sdk.T sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), sdk.NewAttribute(feemarkettypes.AttributeKeyTip, tip.String()), sdk.NewAttribute(feemarkettypes.AttributeKeyTipPayer, deductFeesFrom.String()), + sdk.NewAttribute(feemarkettypes.AttributeKeyTipPayee, proposer.String()), ), } ctx.EventManager().EmitEvents(events) diff --git a/x/feemarket/post/fee_test.go b/x/feemarket/post/fee_test.go index d221ed9..10d7b8a 100644 --- a/x/feemarket/post/fee_test.go +++ b/x/feemarket/post/fee_test.go @@ -103,7 +103,9 @@ func TestPostHandle(t *testing.T) { // Same data for every test case gasLimit := antesuite.NewTestGasLimit() validFeeAmount := types.DefaultMinBaseFee.MulRaw(int64(gasLimit)) + validFeeAmountWithTip := validFeeAmount.Add(sdk.NewInt(100)) validFee := sdk.NewCoins(sdk.NewCoin("stake", validFeeAmount)) + validFeeWithTip := sdk.NewCoins(sdk.NewCoin("stake", validFeeAmountWithTip)) testCases := []antesuite.TestCase{ { @@ -142,11 +144,10 @@ func TestPostHandle(t *testing.T) { ExpErr: sdkerrors.ErrInvalidGasLimit, }, { - Name: "signer has enough funds, should pass", + Name: "signer has enough funds, should pass, no tip", Malleate: func(suite *antesuite.TestSuite) antesuite.TestCaseArgs { accs := suite.CreateTestAccounts(1) suite.BankKeeper.On("SendCoinsFromAccountToModule", mock.Anything, accs[0].Account.GetAddress(), types.FeeCollectorName, mock.Anything).Return(nil) - suite.BankKeeper.On("SendCoins", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() return antesuite.TestCaseArgs{ Msgs: []sdk.Msg{testdata.NewTestMsg(accs[0].Account.GetAddress())}, @@ -160,6 +161,25 @@ func TestPostHandle(t *testing.T) { ExpPass: true, ExpErr: nil, }, + { + Name: "signer has enough funds, should pass with tip", + Malleate: func(suite *antesuite.TestSuite) antesuite.TestCaseArgs { + accs := suite.CreateTestAccounts(1) + suite.BankKeeper.On("SendCoinsFromAccountToModule", mock.Anything, accs[0].Account.GetAddress(), types.FeeCollectorName, mock.Anything).Return(nil) + suite.BankKeeper.On("SendCoins", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + + return antesuite.TestCaseArgs{ + Msgs: []sdk.Msg{testdata.NewTestMsg(accs[0].Account.GetAddress())}, + GasLimit: gasLimit, + FeeAmount: validFeeWithTip, + } + }, + RunAnte: true, + RunPost: true, + Simulate: false, + ExpPass: true, + ExpErr: nil, + }, } for _, tc := range testCases { diff --git a/x/feemarket/types/keys.go b/x/feemarket/types/keys.go index c2aaf09..49927dc 100644 --- a/x/feemarket/types/keys.go +++ b/x/feemarket/types/keys.go @@ -24,4 +24,5 @@ var ( AttributeKeyTip = "tip" AttributeKeyTipPayer = "tip_payer" + AttributeKeyTipPayee = "tip_payee" )