update fork

This commit is contained in:
0xmuralik
2022-10-10 16:08:33 +05:30
parent 632d53e34a
commit 56d59feaa0
383 changed files with 36784 additions and 21462 deletions
+21 -4
View File
@@ -6,6 +6,7 @@ import (
"github.com/cerc-io/laconicd/x/feemarket/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@@ -20,6 +21,10 @@ func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
k.SetBaseFee(ctx, baseFee)
defer func() {
telemetry.SetGauge(float32(baseFee.Int64()), "feemarket", "base_fee")
}()
// Store current base fee in event
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
@@ -29,22 +34,34 @@ func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
})
}
// EndBlock update block gas used.
// EndBlock update block gas wanted.
// The EVM end block logic doesn't update the validator set, thus it returns
// an empty slice.
func (k *Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) {
if ctx.BlockGasMeter() == nil {
k.Logger(ctx).Error("block gas meter is nil when setting block gas used")
k.Logger(ctx).Error("block gas meter is nil when setting block gas wanted")
return
}
gasWanted := k.GetTransientGasWanted(ctx)
gasUsed := ctx.BlockGasMeter().GasConsumedToLimit()
k.SetBlockGasUsed(ctx, gasUsed)
// to prevent BaseFee manipulation we limit the gasWanted so that
// gasWanted = max(gasWanted * MinGasMultiplier, gasUsed)
// this will be keep BaseFee protected from un-penalized manipulation
// more info here https://github.com/cerc-io/laconicd/pull/1105#discussion_r888798925
minGasMultiplier := k.GetParams(ctx).MinGasMultiplier
limitedGasWanted := sdk.NewDec(int64(gasWanted)).Mul(minGasMultiplier)
gasWanted = sdk.MaxDec(limitedGasWanted, sdk.NewDec(int64(gasUsed))).TruncateInt().Uint64()
k.SetBlockGasWanted(ctx, gasWanted)
defer func() {
telemetry.SetGauge(float32(gasWanted), "feemarket", "block_gas")
}()
ctx.EventManager().EmitEvent(sdk.NewEvent(
"block_gas",
sdk.NewAttribute("height", fmt.Sprintf("%d", ctx.BlockHeight())),
sdk.NewAttribute("amount", fmt.Sprintf("%d", ctx.BlockGasMeter().GasConsumedToLimit())),
sdk.NewAttribute("amount", fmt.Sprintf("%d", gasWanted)),
))
}
+11 -19
View File
@@ -4,37 +4,31 @@ import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/abci/types"
)
func (suite *KeeperTestSuite) TestEndBlock() {
testCases := []struct {
name string
NoBaseFee bool
malleate func()
expGasUsed uint64
name string
NoBaseFee bool
malleate func()
expGasWanted uint64
}{
{
"basFee nil",
"baseFee nil",
true,
func() {},
uint64(0),
},
{
"Block gas meter is nil",
false,
func() {},
uint64(0),
},
{
"pass",
false,
func() {
meter := sdk.NewGasMeter(uint64(1000000000))
suite.ctx = suite.ctx.WithBlockGasMeter(meter)
suite.ctx.BlockGasMeter().ConsumeGas(uint64(5000000), "consume gas")
suite.app.FeeMarketKeeper.SetTransientBlockGasWanted(suite.ctx, 5000000)
},
uint64(5000000),
uint64(2500000),
},
}
for _, tc := range testCases {
@@ -45,11 +39,9 @@ func (suite *KeeperTestSuite) TestEndBlock() {
suite.app.FeeMarketKeeper.SetParams(suite.ctx, params)
tc.malleate()
req := abci.RequestEndBlock{Height: 1}
suite.app.FeeMarketKeeper.EndBlock(suite.ctx, req)
gasUsed := suite.app.FeeMarketKeeper.GetBlockGasUsed(suite.ctx)
suite.Require().Equal(tc.expGasUsed, gasUsed, tc.name)
suite.app.FeeMarketKeeper.EndBlock(suite.ctx, types.RequestEndBlock{Height: 1})
gasWanted := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx)
suite.Require().Equal(tc.expGasWanted, gasWanted, tc.name)
})
}
}
+22 -10
View File
@@ -16,31 +16,40 @@ import (
func (k Keeper) CalculateBaseFee(ctx sdk.Context) *big.Int {
params := k.GetParams(ctx)
// Ignore the calculation if not enable
// Ignore the calculation if not enabled
if !params.IsBaseFeeEnabled(ctx.BlockHeight()) {
return nil
}
consParams := ctx.ConsensusParams()
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
// If the current block is the first EIP-1559 block, return the base fee
// defined in the parameters (DefaultBaseFee if it hasn't been changed by
// governance).
if ctx.BlockHeight() == params.EnableHeight {
return params.BaseFee.BigInt()
}
// get the block gas used and the base fee values for the parent block.
// NOTE: this is not the parent's base fee but the current block's base fee,
// as it is retrieved from the transient store, which is committed to the
// persistent KVStore after EndBlock (ABCI Commit).
parentBaseFee := params.BaseFee.BigInt()
if parentBaseFee == nil {
return nil
}
parentGasUsed := k.GetBlockGasUsed(ctx)
parentGasUsed := k.GetBlockGasWanted(ctx)
gasLimit := new(big.Int).SetUint64(math.MaxUint64)
// NOTE: a MaxGas equal to -1 means that block gas is unlimited
if consParams != nil && consParams.Block.MaxGas > -1 {
gasLimit = big.NewInt(consParams.Block.MaxGas)
}
// CONTRACT: ElasticityMultiplier cannot be 0 as it's checked in the params
// validation
parentGasTargetBig := new(big.Int).Div(gasLimit, new(big.Int).SetUint64(uint64(params.ElasticityMultiplier)))
if !parentGasTargetBig.IsUint64() {
return nil
@@ -49,13 +58,15 @@ func (k Keeper) CalculateBaseFee(ctx sdk.Context) *big.Int {
parentGasTarget := parentGasTargetBig.Uint64()
baseFeeChangeDenominator := new(big.Int).SetUint64(uint64(params.BaseFeeChangeDenominator))
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
// If the parent gasUsed is the same as the target, the baseFee remains
// unchanged.
if parentGasUsed == parentGasTarget {
return new(big.Int).Set(parentBaseFee)
}
if parentGasUsed > parentGasTarget {
// If the parent block used more gas than its target, the baseFee should increase.
// If the parent block used more gas than its target, the baseFee should
// increase.
gasUsedDelta := new(big.Int).SetUint64(parentGasUsed - parentGasTarget)
x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
@@ -67,14 +78,15 @@ func (k Keeper) CalculateBaseFee(ctx sdk.Context) *big.Int {
return x.Add(parentBaseFee, baseFeeDelta)
}
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
// Otherwise if the parent block used less gas than its target, the baseFee
// should decrease.
gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parentGasUsed)
x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
baseFeeDelta := x.Div(y, baseFeeChangeDenominator)
return math.BigMax(
x.Sub(parentBaseFee, baseFeeDelta),
common.Big0,
)
// Set global min gas price as lower bound of the base fee, transactions below
// the min gas price don't even reach the mempool.
minGasPrice := params.MinGasPrice.TruncateInt().BigInt()
return math.BigMax(x.Sub(parentBaseFee, baseFeeDelta), minGasPrice)
}
+64 -64
View File
@@ -4,106 +4,106 @@ import (
"fmt"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)
func (suite *KeeperTestSuite) TestCalculateBaseFee() {
testCases := []struct {
name string
NoBaseFee bool
malleate func()
expFee *big.Int
name string
NoBaseFee bool
blockHeight int64
parentBlockGasWanted uint64
minGasPrice sdk.Dec
expFee *big.Int
}{
{
"without BaseFee",
true,
func() {},
0,
0,
sdk.ZeroDec(),
nil,
},
{
"with BaseFee - initial EIP-1559 block",
false,
func() {
suite.ctx = suite.ctx.WithBlockHeight(0)
},
0,
0,
sdk.ZeroDec(),
suite.app.FeeMarketKeeper.GetParams(suite.ctx).BaseFee.BigInt(),
},
{
"with BaseFee - parent block used the same gas as its target",
"with BaseFee - parent block wanted the same gas as its target (ElasticityMultiplier = 2)",
false,
func() {
// non initial block
suite.ctx = suite.ctx.WithBlockHeight(1)
// Set gas used
suite.app.FeeMarketKeeper.SetBlockGasUsed(suite.ctx, 100)
// Set target/gasLimit through Consensus Param MaxGas
blockParams := abci.BlockParams{
MaxGas: 100,
MaxBytes: 10,
}
consParams := abci.ConsensusParams{Block: &blockParams}
suite.ctx = suite.ctx.WithConsensusParams(&consParams)
// set ElasticityMultiplier
params := suite.app.FeeMarketKeeper.GetParams(suite.ctx)
params.ElasticityMultiplier = 1
suite.app.FeeMarketKeeper.SetParams(suite.ctx, params)
},
1,
50,
sdk.ZeroDec(),
suite.app.FeeMarketKeeper.GetParams(suite.ctx).BaseFee.BigInt(),
},
{
"with BaseFee - parent block used more gas than its target",
"with BaseFee - parent block wanted the same gas as its target, with higher min gas price (ElasticityMultiplier = 2)",
false,
func() {
suite.ctx = suite.ctx.WithBlockHeight(1)
suite.app.FeeMarketKeeper.SetBlockGasUsed(suite.ctx, 200)
blockParams := abci.BlockParams{
MaxGas: 100,
MaxBytes: 10,
}
consParams := abci.ConsensusParams{Block: &blockParams}
suite.ctx = suite.ctx.WithConsensusParams(&consParams)
params := suite.app.FeeMarketKeeper.GetParams(suite.ctx)
params.ElasticityMultiplier = 1
suite.app.FeeMarketKeeper.SetParams(suite.ctx, params)
},
1,
50,
sdk.NewDec(1500000000),
suite.app.FeeMarketKeeper.GetParams(suite.ctx).BaseFee.BigInt(),
},
{
"with BaseFee - parent block wanted more gas than its target (ElasticityMultiplier = 2)",
false,
1,
100,
sdk.ZeroDec(),
big.NewInt(1125000000),
},
{
"with BaseFee - Parent gas used smaller than parent gas target",
"with BaseFee - parent block wanted more gas than its target, with higher min gas price (ElasticityMultiplier = 2)",
false,
func() {
suite.ctx = suite.ctx.WithBlockHeight(1)
suite.app.FeeMarketKeeper.SetBlockGasUsed(suite.ctx, 50)
blockParams := abci.BlockParams{
MaxGas: 100,
MaxBytes: 10,
}
consParams := abci.ConsensusParams{Block: &blockParams}
suite.ctx = suite.ctx.WithConsensusParams(&consParams)
params := suite.app.FeeMarketKeeper.GetParams(suite.ctx)
params.ElasticityMultiplier = 1
suite.app.FeeMarketKeeper.SetParams(suite.ctx, params)
},
1,
100,
sdk.NewDec(1500000000),
big.NewInt(1125000000),
},
{
"with BaseFee - Parent gas wanted smaller than parent gas target (ElasticityMultiplier = 2)",
false,
1,
25,
sdk.ZeroDec(),
big.NewInt(937500000),
},
{
"with BaseFee - Parent gas wanted smaller than parent gas target, with higher min gas price (ElasticityMultiplier = 2)",
false,
1,
25,
sdk.NewDec(1500000000),
big.NewInt(1500000000),
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest() // reset
params := suite.app.FeeMarketKeeper.GetParams(suite.ctx)
params.NoBaseFee = tc.NoBaseFee
params.MinGasPrice = tc.minGasPrice
suite.app.FeeMarketKeeper.SetParams(suite.ctx, params)
tc.malleate()
// Set block height
suite.ctx = suite.ctx.WithBlockHeight(tc.blockHeight)
// Set parent block gas
suite.app.FeeMarketKeeper.SetBlockGasWanted(suite.ctx, tc.parentBlockGasWanted)
// Set next block target/gasLimit through Consensus Param MaxGas
blockParams := abci.BlockParams{
MaxGas: 100,
MaxBytes: 10,
}
consParams := abci.ConsensusParams{Block: &blockParams}
suite.ctx = suite.ctx.WithConsensusParams(&consParams)
fee := suite.app.FeeMarketKeeper.CalculateBaseFee(suite.ctx)
if tc.NoBaseFee {
+3 -2
View File
@@ -3,6 +3,7 @@ package keeper
import (
"context"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cerc-io/laconicd/x/feemarket/types"
@@ -28,7 +29,7 @@ func (k Keeper) BaseFee(c context.Context, _ *types.QueryBaseFeeRequest) (*types
baseFee := k.GetBaseFee(ctx)
if baseFee != nil {
aux := sdk.NewIntFromBigInt(baseFee)
aux := sdkmath.NewIntFromBigInt(baseFee)
res.BaseFee = &aux
}
@@ -38,7 +39,7 @@ func (k Keeper) BaseFee(c context.Context, _ *types.QueryBaseFeeRequest) (*types
// BlockGas implements the Query/BlockGas gRPC method
func (k Keeper) BlockGas(c context.Context, _ *types.QueryBlockGasRequest) (*types.QueryBlockGasResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
gas := k.GetBlockGasUsed(ctx)
gas := k.GetBlockGasWanted(ctx)
return &types.QueryBlockGasResponse{
Gas: int64(gas),
+5 -4
View File
@@ -1,6 +1,7 @@
package keeper_test
import (
sdkmath "cosmossdk.io/math"
"github.com/cerc-io/laconicd/x/feemarket/types"
sdk "github.com/cosmos/cosmos-sdk/types"
ethparams "github.com/ethereum/go-ethereum/params"
@@ -32,7 +33,7 @@ func (suite *KeeperTestSuite) TestQueryParams() {
func (suite *KeeperTestSuite) TestQueryBaseFee() {
var (
aux sdk.Int
aux sdkmath.Int
expRes *types.QueryBaseFeeResponse
)
@@ -44,7 +45,7 @@ func (suite *KeeperTestSuite) TestQueryBaseFee() {
{
"pass - default Base Fee",
func() {
initialBaseFee := sdk.NewInt(ethparams.InitialBaseFee)
initialBaseFee := sdkmath.NewInt(ethparams.InitialBaseFee)
expRes = &types.QueryBaseFeeResponse{BaseFee: &initialBaseFee}
},
true,
@@ -55,7 +56,7 @@ func (suite *KeeperTestSuite) TestQueryBaseFee() {
baseFee := sdk.OneInt().BigInt()
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, baseFee)
aux = sdk.NewIntFromBigInt(baseFee)
aux = sdkmath.NewIntFromBigInt(baseFee)
expRes = &types.QueryBaseFeeResponse{BaseFee: &aux}
},
true,
@@ -86,7 +87,7 @@ func (suite *KeeperTestSuite) TestQueryBlockGas() {
},
}
for _, tc := range testCases {
gas := suite.app.FeeMarketKeeper.GetBlockGasUsed(suite.ctx)
gas := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx)
exp := &types.QueryBlockGasResponse{Gas: int64(gas)}
res, err := suite.queryClient.BlockGas(suite.ctx.Context(), &types.QueryBlockGasRequest{})
+677
View File
@@ -0,0 +1,677 @@
package keeper_test
import (
"encoding/json"
"math/big"
"strings"
sdkmath "cosmossdk.io/math"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/tests"
"github.com/cerc-io/laconicd/testutil"
"github.com/cerc-io/laconicd/x/feemarket/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client/tx"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/simapp"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
)
var _ = Describe("Feemarket", func() {
var (
privKey *ethsecp256k1.PrivKey
msg banktypes.MsgSend
)
Describe("Performing Cosmos transactions", func() {
Context("with min-gas-prices (local) < MinGasPrices (feemarket param)", func() {
BeforeEach(func() {
privKey, msg = setupTestWithContext("1", sdk.NewDec(3), sdk.ZeroInt())
})
Context("during CheckTx", func() {
It("should reject transactions with gasPrice < MinGasPrices", func() {
gasPrice := sdkmath.NewInt(2)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
})
It("should accept transactions with gasPrice >= MinGasPrices", func() {
gasPrice := sdkmath.NewInt(3)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
})
})
Context("during DeliverTx", func() {
It("should reject transactions with gasPrice < MinGasPrices", func() {
gasPrice := sdkmath.NewInt(2)
res := deliverTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
})
It("should accept transactions with gasPrice >= MinGasPrices", func() {
gasPrice := sdkmath.NewInt(3)
res := deliverTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
})
})
})
Context("with min-gas-prices (local) == MinGasPrices (feemarket param)", func() {
BeforeEach(func() {
privKey, msg = setupTestWithContext("3", sdk.NewDec(3), sdk.ZeroInt())
})
Context("during CheckTx", func() {
It("should reject transactions with gasPrice < min-gas-prices", func() {
gasPrice := sdkmath.NewInt(2)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"insufficient fee"),
).To(BeTrue(), res.GetLog())
})
It("should accept transactions with gasPrice >= MinGasPrices", func() {
gasPrice := sdkmath.NewInt(3)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
})
})
Context("during DeliverTx", func() {
It("should reject transactions with gasPrice < MinGasPrices", func() {
gasPrice := sdkmath.NewInt(2)
res := deliverTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
})
It("should accept transactions with gasPrice >= MinGasPrices", func() {
gasPrice := sdkmath.NewInt(3)
res := deliverTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
})
})
})
Context("with MinGasPrices (feemarket param) < min-gas-prices (local)", func() {
BeforeEach(func() {
privKey, msg = setupTestWithContext("5", sdk.NewDec(3), sdk.NewInt(5))
})
Context("during CheckTx", func() {
It("should reject transactions with gasPrice < MinGasPrices", func() {
gasPrice := sdkmath.NewInt(2)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"insufficient fee"),
).To(BeTrue(), res.GetLog())
})
It("should reject transactions with MinGasPrices < gasPrice < baseFee", func() {
gasPrice := sdkmath.NewInt(4)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"insufficient fee"),
).To(BeTrue(), res.GetLog())
})
It("should accept transactions with gasPrice >= baseFee", func() {
gasPrice := sdkmath.NewInt(5)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
})
})
Context("during DeliverTx", func() {
It("should reject transactions with gasPrice < MinGasPrices", func() {
gasPrice := sdkmath.NewInt(2)
res := deliverTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
})
It("should reject transactions with MinGasPrices < gasPrice < baseFee", func() {
gasPrice := sdkmath.NewInt(4)
res := checkTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"insufficient fee"),
).To(BeTrue(), res.GetLog())
})
It("should accept transactions with gasPrice >= baseFee", func() {
gasPrice := sdkmath.NewInt(5)
res := deliverTx(privKey, &gasPrice, &msg)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
})
})
})
})
Describe("Performing EVM transactions", func() {
type txParams struct {
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
accesses *ethtypes.AccessList
}
type getprices func() txParams
Context("with BaseFee (feemarket) < MinGasPrices (feemarket param)", func() {
var (
baseFee int64
minGasPrices int64
)
BeforeEach(func() {
baseFee = 10_000_000_000
minGasPrices = baseFee + 30_000_000_000
// Note that the tests run the same transactions with `gasLimit =
// 100000`. With the fee calculation `Fee = (baseFee + tip) * gasLimit`,
// a `minGasPrices = 40_000_000_000` results in `minGlobalFee =
// 4000000000000000`
privKey, _ = setupTestWithContext("1", sdk.NewDec(minGasPrices), sdkmath.NewInt(baseFee))
})
Context("during CheckTx", func() {
DescribeTable("should reject transactions with EffectivePrice < MinGasPrices",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(minGasPrices - 10_000_000_000), nil, nil, nil}
}),
Entry("dynamic tx with GasFeeCap < MinGasPrices, no gasTipCap", func() txParams {
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(0), &ethtypes.AccessList{}}
}),
Entry("dynamic tx with GasFeeCap < MinGasPrices, max gasTipCap", func() txParams {
// Note that max priority fee per gas can't be higher than the max fee per gas (gasFeeCap), i.e. 30_000_000_000)
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(30_000_000_000), &ethtypes.AccessList{}}
}),
Entry("dynamic tx with GasFeeCap > MinGasPrices, EffectivePrice < MinGasPrices", func() txParams {
return txParams{nil, big.NewInt(minGasPrices + 10_000_000_000), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
DescribeTable("should accept transactions with gasPrice >= MinGasPrices",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(minGasPrices), nil, nil, nil}
}),
// Note that this tx is not rejected on CheckTx, but not on DeliverTx,
// as the baseFee is set to minGasPrices during DeliverTx when baseFee
// < minGasPrices
Entry("dynamic tx with GasFeeCap > MinGasPrices, EffectivePrice > MinGasPrices", func() txParams {
return txParams{nil, big.NewInt(minGasPrices), big.NewInt(30_000_000_000), &ethtypes.AccessList{}}
}),
)
})
Context("during DeliverTx", func() {
DescribeTable("should reject transactions with gasPrice < MinGasPrices",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := deliverEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(minGasPrices - 10_000_000_000), nil, nil, nil}
}),
Entry("dynamic tx with GasFeeCap < MinGasPrices, no gasTipCap", func() txParams {
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(0), &ethtypes.AccessList{}}
}),
Entry("dynamic tx with GasFeeCap < MinGasPrices, max gasTipCap", func() txParams {
// Note that max priority fee per gas can't be higher than the max fee per gas (gasFeeCap), i.e. 30_000_000_000)
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(30_000_000_000), &ethtypes.AccessList{}}
}),
)
DescribeTable("should accept transactions with gasPrice >= MinGasPrices",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := deliverEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(minGasPrices + 1), nil, nil, nil}
}),
Entry("dynamic tx, EffectivePrice > MinGasPrices", func() txParams {
return txParams{nil, big.NewInt(minGasPrices + 10_000_000_000), big.NewInt(30_000_000_000), &ethtypes.AccessList{}}
}),
)
})
})
Context("with MinGasPrices (feemarket param) < BaseFee (feemarket)", func() {
var (
baseFee int64
minGasPrices int64
)
BeforeEach(func() {
baseFee = 10_000_000_000
minGasPrices = baseFee - 5_000_000_000
// Note that the tests run the same transactions with `gasLimit =
// 100_000`. With the fee calculation `Fee = (baseFee + tip) * gasLimit`,
// a `minGasPrices = 5_000_000_000` results in `minGlobalFee =
// 500_000_000_000_000`
privKey, _ = setupTestWithContext("1", sdk.NewDec(minGasPrices), sdkmath.NewInt(baseFee))
})
Context("during CheckTx", func() {
DescribeTable("should reject transactions with gasPrice < MinGasPrices",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(minGasPrices - 1_000_000_000), nil, nil, nil}
}),
Entry("dynamic tx with GasFeeCap < MinGasPrices, no gasTipCap", func() txParams {
return txParams{nil, big.NewInt(minGasPrices - 1_000_000_000), big.NewInt(0), &ethtypes.AccessList{}}
}),
Entry("dynamic tx with GasFeeCap < MinGasPrices, max gasTipCap", func() txParams {
return txParams{nil, big.NewInt(minGasPrices - 1_000_000_000), big.NewInt(minGasPrices - 1_000_000_000), &ethtypes.AccessList{}}
}),
)
DescribeTable("should reject transactions with MinGasPrices < tx gasPrice < EffectivePrice",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"insufficient fee"),
).To(BeTrue(), res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(baseFee - 1_000_000_000), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{nil, big.NewInt(baseFee - 1_000_000_000), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
DescribeTable("should accept transactions with gasPrice >= EffectivePrice",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
})
Context("during DeliverTx", func() {
DescribeTable("should reject transactions with gasPrice < MinGasPrices",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := deliverEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"provided fee < minimum global fee"),
).To(BeTrue(), res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(minGasPrices - 1_000_000_000), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{nil, big.NewInt(minGasPrices - 1_000_000_000), nil, &ethtypes.AccessList{}}
}),
)
DescribeTable("should reject transactions with MinGasPrices < gasPrice < EffectivePrice",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := deliverEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
Expect(
strings.Contains(res.GetLog(),
"insufficient fee"),
).To(BeTrue(), res.GetLog())
},
// Note that the baseFee is not 10_000_000_000 anymore but updates to 8_750_000_000 because of the s.Commit
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(baseFee - 2_000_000_000), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{nil, big.NewInt(baseFee - 2_000_000_000), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
DescribeTable("should accept transactions with gasPrice >= EffectivePrice",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := deliverEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
})
})
})
})
// setupTestWithContext sets up a test chain with an example Cosmos send msg,
// given a local (validator config) and a gloabl (feemarket param) minGasPrice
func setupTestWithContext(valMinGasPrice string, minGasPrice sdk.Dec, baseFee sdkmath.Int) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
privKey, msg := setupTest(valMinGasPrice + s.denom)
params := types.DefaultParams()
params.MinGasPrice = minGasPrice
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
s.app.FeeMarketKeeper.SetBaseFee(s.ctx, baseFee.BigInt())
s.Commit()
return privKey, msg
}
func setupTest(localMinGasPrices string) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
setupChain(localMinGasPrices)
privKey, address := generateKey()
amount, ok := sdkmath.NewIntFromString("10000000000000000000")
s.Require().True(ok)
initBalance := sdk.Coins{sdk.Coin{
Denom: s.denom,
Amount: amount,
}}
testutil.FundAccount(s.app.BankKeeper, s.ctx, address, initBalance)
msg := banktypes.MsgSend{
FromAddress: address.String(),
ToAddress: address.String(),
Amount: sdk.Coins{sdk.Coin{
Denom: s.denom,
Amount: sdkmath.NewInt(10000),
}},
}
s.Commit()
return privKey, msg
}
func setupChain(localMinGasPricesStr string) {
// Initialize the app, so we can use SetMinGasPrices to set the
// validator-specific min-gas-prices setting
db := dbm.NewMemDB()
newapp := app.NewEthermintApp(
log.NewNopLogger(),
db,
nil,
true,
map[int64]bool{},
app.DefaultNodeHome,
5,
encoding.MakeConfig(app.ModuleBasics),
simapp.EmptyAppOptions{},
baseapp.SetMinGasPrices(localMinGasPricesStr),
)
genesisState := app.NewTestGenesisState(newapp.AppCodec())
genesisState[types.ModuleName] = newapp.AppCodec().MustMarshalJSON(types.DefaultGenesisState())
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
s.Require().NoError(err)
// Initialize the chain
newapp.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
ConsensusParams: app.DefaultConsensusParams,
},
)
s.app = newapp
s.SetupApp(false)
}
func generateKey() (*ethsecp256k1.PrivKey, sdk.AccAddress) {
address, priv := tests.NewAddrKey()
return priv.(*ethsecp256k1.PrivKey), sdk.AccAddress(address.Bytes())
}
func getNonce(addressBytes []byte) uint64 {
return s.app.EvmKeeper.GetNonce(
s.ctx,
common.BytesToAddress(addressBytes),
)
}
func buildEthTx(
priv *ethsecp256k1.PrivKey,
to *common.Address,
gasPrice *big.Int,
gasFeeCap *big.Int,
gasTipCap *big.Int,
accesses *ethtypes.AccessList,
) *evmtypes.MsgEthereumTx {
chainID := s.app.EvmKeeper.ChainID()
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
nonce := getNonce(from.Bytes())
data := make([]byte, 0)
gasLimit := uint64(100000)
msgEthereumTx := evmtypes.NewTx(
chainID,
nonce,
to,
nil,
gasLimit,
gasPrice,
gasFeeCap,
gasTipCap,
data,
accesses,
)
msgEthereumTx.From = from.String()
return msgEthereumTx
}
func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) []byte {
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
s.Require().NoError(err)
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
s.Require().True(ok)
builder.SetExtensionOptions(option)
err = msgEthereumTx.Sign(s.ethSigner, tests.NewSigner(priv))
s.Require().NoError(err)
msgEthereumTx.From = ""
err = txBuilder.SetMsgs(msgEthereumTx)
s.Require().NoError(err)
txData, err := evmtypes.UnpackTxData(msgEthereumTx.Data)
s.Require().NoError(err)
evmDenom := s.app.EvmKeeper.GetParams(s.ctx).EvmDenom
fees := sdk.Coins{{Denom: evmDenom, Amount: sdkmath.NewIntFromBigInt(txData.Fee())}}
builder.SetFeeAmount(fees)
builder.SetGasLimit(msgEthereumTx.GetGas())
// bz are bytes to be broadcasted over the network
bz, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
return bz
}
func checkEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseCheckTx {
bz := prepareEthTx(priv, msgEthereumTx)
req := abci.RequestCheckTx{Tx: bz}
res := s.app.BaseApp.CheckTx(req)
return res
}
func deliverEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseDeliverTx {
bz := prepareEthTx(priv, msgEthereumTx)
req := abci.RequestDeliverTx{Tx: bz}
res := s.app.BaseApp.DeliverTx(req)
return res
}
func prepareCosmosTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ...sdk.Msg) []byte {
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
accountAddress := sdk.AccAddress(priv.PubKey().Address().Bytes())
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
txBuilder.SetGasLimit(1000000)
if gasPrice == nil {
_gasPrice := sdkmath.NewInt(1)
gasPrice = &_gasPrice
}
fees := &sdk.Coins{{Denom: s.denom, Amount: gasPrice.MulRaw(1000000)}}
txBuilder.SetFeeAmount(*fees)
err := txBuilder.SetMsgs(msgs...)
s.Require().NoError(err)
seq, err := s.app.AccountKeeper.GetSequence(s.ctx, accountAddress)
s.Require().NoError(err)
// First round: we gather all the signer infos. We use the "set empty
// signature" hack to do that.
sigV2 := signing.SignatureV2{
PubKey: priv.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: encodingConfig.TxConfig.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: seq,
}
sigsV2 := []signing.SignatureV2{sigV2}
err = txBuilder.SetSignatures(sigsV2...)
s.Require().NoError(err)
// Second round: all signer infos are set, so each signer can sign.
accNumber := s.app.AccountKeeper.GetAccount(s.ctx, accountAddress).GetAccountNumber()
signerData := authsigning.SignerData{
ChainID: s.ctx.ChainID(),
AccountNumber: accNumber,
Sequence: seq,
}
sigV2, err = tx.SignWithPrivKey(
encodingConfig.TxConfig.SignModeHandler().DefaultMode(), signerData,
txBuilder, priv, encodingConfig.TxConfig,
seq,
)
s.Require().NoError(err)
sigsV2 = []signing.SignatureV2{sigV2}
err = txBuilder.SetSignatures(sigsV2...)
s.Require().NoError(err)
// bz are bytes to be broadcasted over the network
bz, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
return bz
}
func checkTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ...sdk.Msg) abci.ResponseCheckTx {
bz := prepareCosmosTx(priv, gasPrice, msgs...)
req := abci.RequestCheckTx{Tx: bz}
res := s.app.BaseApp.CheckTx(req)
return res
}
func deliverTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ...sdk.Msg) abci.ResponseDeliverTx {
bz := prepareCosmosTx(priv, gasPrice, msgs...)
req := abci.RequestDeliverTx{Tx: bz}
res := s.app.BaseApp.DeliverTx(req)
return res
}
+54 -14
View File
@@ -1,13 +1,16 @@
package keeper
import (
"math/big"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/tendermint/tendermint/libs/log"
v010 "github.com/cerc-io/laconicd/x/feemarket/migrations/v010"
"github.com/cerc-io/laconicd/x/feemarket/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
)
// Keeper grants access to the Fee Market module state.
@@ -15,14 +18,15 @@ type Keeper struct {
// Protobuf codec
cdc codec.BinaryCodec
// Store key required for the Fee Market Prefix KVStore.
storeKey storetypes.StoreKey
storeKey storetypes.StoreKey
transientKey storetypes.StoreKey
// module specific parameter space that can be configured through governance
paramSpace paramtypes.Subspace
}
// NewKeeper generates new fee market module keeper
func NewKeeper(
cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace,
cdc codec.BinaryCodec, paramSpace paramtypes.Subspace, storeKey, transientKey storetypes.StoreKey,
) Keeper {
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
@@ -30,9 +34,10 @@ func NewKeeper(
}
return Keeper{
cdc: cdc,
storeKey: storeKey,
paramSpace: paramSpace,
cdc: cdc,
storeKey: storeKey,
paramSpace: paramSpace,
transientKey: transientKey,
}
}
@@ -46,10 +51,18 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
// Required by EIP1559 base fee calculation.
// ----------------------------------------------------------------------------
// GetBlockGasUsed returns the last block gas used value from the store.
func (k Keeper) GetBlockGasUsed(ctx sdk.Context) uint64 {
// SetBlockGasWanted sets the block gas wanted to the store.
// CONTRACT: this should be only called during EndBlock.
func (k Keeper) SetBlockGasWanted(ctx sdk.Context, gas uint64) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyPrefixBlockGasUsed)
gasBz := sdk.Uint64ToBigEndian(gas)
store.Set(types.KeyPrefixBlockGasWanted, gasBz)
}
// GetBlockGasWanted returns the last block gas wanted value from the store.
func (k Keeper) GetBlockGasWanted(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyPrefixBlockGasWanted)
if len(bz) == 0 {
return 0
}
@@ -57,10 +70,37 @@ func (k Keeper) GetBlockGasUsed(ctx sdk.Context) uint64 {
return sdk.BigEndianToUint64(bz)
}
// SetBlockGasUsed gets the block gas consumed to the store.
// CONTRACT: this should be only called during EndBlock.
func (k Keeper) SetBlockGasUsed(ctx sdk.Context, gas uint64) {
// GetTransientGasWanted returns the gas wanted in the current block from transient store.
func (k Keeper) GetTransientGasWanted(ctx sdk.Context) uint64 {
store := ctx.TransientStore(k.transientKey)
bz := store.Get(types.KeyPrefixTransientBlockGasWanted)
if len(bz) == 0 {
return 0
}
return sdk.BigEndianToUint64(bz)
}
// SetTransientBlockGasWanted sets the block gas wanted to the transient store.
func (k Keeper) SetTransientBlockGasWanted(ctx sdk.Context, gasWanted uint64) {
store := ctx.TransientStore(k.transientKey)
gasBz := sdk.Uint64ToBigEndian(gasWanted)
store.Set(types.KeyPrefixTransientBlockGasWanted, gasBz)
}
// AddTransientGasWanted adds the cumulative gas wanted in the transient store
func (k Keeper) AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error) {
result := k.GetTransientGasWanted(ctx) + gasWanted
k.SetTransientBlockGasWanted(ctx, result)
return result, nil
}
// GetBaseFeeV1 get the base fee from v1 version of states.
// return nil if base fee is not enabled
func (k Keeper) GetBaseFeeV1(ctx sdk.Context) *big.Int {
store := ctx.KVStore(k.storeKey)
gasBz := sdk.Uint64ToBigEndian(gas)
store.Set(types.KeyPrefixBlockGasUsed, gasBz)
bz := store.Get(v010.KeyPrefixBaseFeeV1)
if len(bz) == 0 {
return nil
}
return new(big.Int).SetBytes(bz)
}
+71 -17
View File
@@ -6,26 +6,34 @@ import (
"testing"
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/tests"
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/feemarket/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/tests"
ethermint "github.com/cerc-io/laconicd/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cerc-io/laconicd/x/feemarket/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/tmhash"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
@@ -47,12 +55,29 @@ type KeeperTestSuite struct {
appCodec codec.Codec
signer keyring.Signer
denom string
}
/// DoSetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
checkTx := false
var s *KeeperTestSuite
func TestKeeperTestSuite(t *testing.T) {
s = new(KeeperTestSuite)
suite.Run(t, s)
// Run Ginkgo integration tests
RegisterFailHandler(Fail)
RunSpecs(t, "Keeper Suite")
}
// SetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *KeeperTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx, nil)
suite.SetupApp(checkTx)
}
func (suite *KeeperTestSuite) SetupApp(checkTx bool) {
t := suite.T()
// account key
priv, err := ethsecp256k1.GenerateKey()
require.NoError(t, err)
@@ -64,7 +89,6 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
require.NoError(t, err)
suite.consAddress = sdk.ConsAddress(priv.PubKey().Address())
suite.app = app.Setup(suite.T(), checkTx, nil)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{
Height: 1,
ChainID: "ethermint_9000-1",
@@ -99,21 +123,51 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
}
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
valAddr := sdk.ValAddress(suite.address.Bytes())
validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{})
require.NoError(t, err)
validator = stakingkeeper.TestingUpdateValidator(suite.app.StakingKeeper, suite.ctx, validator, true)
err = suite.app.StakingKeeper.AfterValidatorCreated(suite.ctx, validator.GetOperator())
require.NoError(t, err)
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
require.NoError(t, err)
suite.app.StakingKeeper.SetValidator(suite.ctx, validator)
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
suite.appCodec = encodingConfig.Codec
suite.denom = evmtypes.DefaultEVMDenom
}
func (suite *KeeperTestSuite) SetupTest() {
suite.DoSetupTest(suite.T())
// Commit commits and starts a new block with an updated context.
func (suite *KeeperTestSuite) Commit() {
suite.CommitAfter(time.Second * 0)
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
// Commit commits a block at a given time.
func (suite *KeeperTestSuite) CommitAfter(t time.Duration) {
header := suite.ctx.BlockHeader()
suite.app.EndBlock(abci.RequestEndBlock{Height: header.Height})
_ = suite.app.Commit()
header.Height += 1
header.Time = header.Time.Add(t)
suite.app.BeginBlock(abci.RequestBeginBlock{
Header: header,
})
// update ctx
suite.ctx = suite.app.BaseApp.NewContext(false, header)
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.FeeMarketKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
}
func (suite *KeeperTestSuite) TestSetGetBlockGasUsed() {
func (suite *KeeperTestSuite) TestSetGetBlockGasWanted() {
testCases := []struct {
name string
malleate func()
@@ -122,7 +176,7 @@ func (suite *KeeperTestSuite) TestSetGetBlockGasUsed() {
{
"with last block given",
func() {
suite.app.FeeMarketKeeper.SetBlockGasUsed(suite.ctx, uint64(1000000))
suite.app.FeeMarketKeeper.SetBlockGasWanted(suite.ctx, uint64(1000000))
},
uint64(1000000),
},
@@ -130,7 +184,7 @@ func (suite *KeeperTestSuite) TestSetGetBlockGasUsed() {
for _, tc := range testCases {
tc.malleate()
gas := suite.app.FeeMarketKeeper.GetBlockGasUsed(suite.ctx)
gas := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx)
suite.Require().Equal(tc.expGas, gas, tc.name)
}
}
+6
View File
@@ -4,6 +4,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
v010 "github.com/cerc-io/laconicd/x/feemarket/migrations/v010"
v011 "github.com/cerc-io/laconicd/x/feemarket/migrations/v011"
)
// Migrator is a struct for handling in-place store migrations.
@@ -22,3 +23,8 @@ func NewMigrator(keeper Keeper) Migrator {
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v010.MigrateStore(ctx, &m.keeper.paramSpace, m.keeper.storeKey)
}
// Migrate2to3 migrates the store from consensus version v2 to v3
func (m Migrator) Migrate2to3(ctx sdk.Context) error {
return v011.MigrateStore(ctx, &m.keeper.paramSpace)
}
+14 -3
View File
@@ -3,13 +3,18 @@ package keeper
import (
"math/big"
sdkmath "cosmossdk.io/math"
"github.com/cerc-io/laconicd/x/feemarket/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GetParams returns the total set of fee market parameters.
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
k.paramSpace.GetParamSet(ctx, &params)
// TODO: update once https://github.com/cosmos/cosmos-sdk/pull/12615 is merged
// and released
for _, pair := range params.ParamSetPairs() {
k.paramSpace.GetIfExists(ctx, pair.Key, pair.Value)
}
return params
}
@@ -31,10 +36,16 @@ func (k Keeper) GetBaseFee(ctx sdk.Context) *big.Int {
return nil
}
return params.BaseFee.BigInt()
baseFee := params.BaseFee.BigInt()
if baseFee == nil || baseFee.Sign() == 0 {
// try v1 format
return k.GetBaseFeeV1(ctx)
}
return baseFee
}
// SetBaseFee set's the base fee in the paramSpace
func (k Keeper) SetBaseFee(ctx sdk.Context, baseFee *big.Int) {
k.paramSpace.Set(ctx, types.ParamStoreKeyBaseFee, sdk.NewIntFromBigInt(baseFee))
k.paramSpace.Set(ctx, types.ParamStoreKeyBaseFee, sdkmath.NewIntFromBigInt(baseFee))
}