Co-authored-by: Akhil Kumar P <36399231+akhilkumarpilli@users.noreply.github.com>
This commit is contained in:
co-authored by
Akhil Kumar P
parent
5fad40124a
commit
eefb4c5586
@@ -0,0 +1,255 @@
|
||||
package baseapp_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
|
||||
cmtjson "github.com/cometbft/cometbft/libs/json"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
coretesting "cosmossdk.io/core/testing"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
store "cosmossdk.io/store/types"
|
||||
_ "cosmossdk.io/x/accounts"
|
||||
|
||||
baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
baseapputil "github.com/cosmos/cosmos-sdk/tests/integration/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/configurator"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
)
|
||||
|
||||
var blockMaxGas = uint64(simtestutil.DefaultConsensusParams.Block.MaxGas)
|
||||
|
||||
type BlockGasImpl struct {
|
||||
panicTx bool
|
||||
gasToConsume uint64
|
||||
key store.StoreKey
|
||||
}
|
||||
|
||||
func (m BlockGasImpl) Set(ctx context.Context, msg *baseapptestutil.MsgKeyValue) (*baseapptestutil.MsgCreateKeyValueResponse, error) {
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
sdkCtx.KVStore(m.key).Set(msg.Key, msg.Value)
|
||||
sdkCtx.GasMeter().ConsumeGas(m.gasToConsume, "TestMsg")
|
||||
if m.panicTx {
|
||||
panic("panic in tx execution")
|
||||
}
|
||||
return &baseapptestutil.MsgCreateKeyValueResponse{}, nil
|
||||
}
|
||||
|
||||
func TestBaseApp_BlockGas(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
gasToConsume uint64 // gas to consume in the msg execution
|
||||
panicTx bool // panic explicitly in tx execution
|
||||
expErr bool
|
||||
}{
|
||||
{"less than block gas meter", 10, false, false},
|
||||
{"more than block gas meter", blockMaxGas, false, true},
|
||||
{"more than block gas meter", uint64(float64(blockMaxGas) * 1.2), false, true},
|
||||
{"consume MaxUint64", math.MaxUint64, true, true},
|
||||
{"consume MaxGasWanted", txtypes.MaxGasWanted, false, true},
|
||||
{"consume block gas when panicked", 10, true, true},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
var (
|
||||
bankKeeper baseapputil.BankKeeper
|
||||
accountKeeper baseapputil.AuthKeeper
|
||||
appBuilder *runtime.AppBuilder
|
||||
txConfig client.TxConfig
|
||||
cdc codec.Codec
|
||||
interfaceRegistry codectypes.InterfaceRegistry
|
||||
err error
|
||||
)
|
||||
|
||||
err = depinject.Inject(
|
||||
depinject.Configs(
|
||||
configurator.NewAppConfig(
|
||||
configurator.AccountsModule(),
|
||||
configurator.AuthModule(),
|
||||
configurator.TxModule(),
|
||||
configurator.ValidateModule(),
|
||||
configurator.ConsensusModule(),
|
||||
configurator.BankModule(),
|
||||
configurator.StakingModule(),
|
||||
),
|
||||
depinject.Supply(log.NewNopLogger()),
|
||||
),
|
||||
&bankKeeper,
|
||||
&accountKeeper,
|
||||
&interfaceRegistry,
|
||||
&txConfig,
|
||||
&cdc,
|
||||
&appBuilder)
|
||||
require.NoError(t, err)
|
||||
|
||||
bapp := appBuilder.Build(coretesting.NewMemDB(), nil)
|
||||
err = bapp.Load(true)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
baseapptestutil.RegisterInterfaces(interfaceRegistry)
|
||||
baseapptestutil.RegisterKeyValueServer(bapp.MsgServiceRouter(), BlockGasImpl{
|
||||
panicTx: tc.panicTx,
|
||||
gasToConsume: tc.gasToConsume,
|
||||
key: bapp.UnsafeFindStoreKey(testutil.BankModuleName),
|
||||
})
|
||||
|
||||
genState := baseapputil.GenesisStateWithSingleValidator(t, cdc, appBuilder)
|
||||
stateBytes, err := cmtjson.MarshalIndent(genState, "", " ")
|
||||
require.NoError(t, err)
|
||||
_, err = bapp.InitChain(&abci.InitChainRequest{
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: simtestutil.DefaultConsensusParams,
|
||||
AppStateBytes: stateBytes,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
ctx := bapp.NewContext(false)
|
||||
|
||||
// tx fee
|
||||
feeCoin := sdk.NewCoin("atom", sdkmath.NewInt(150))
|
||||
feeAmount := sdk.NewCoins(feeCoin)
|
||||
|
||||
// test account and fund
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
err = bankKeeper.MintCoins(ctx, testutil.MintModuleName, feeAmount)
|
||||
require.NoError(t, err)
|
||||
err = bankKeeper.SendCoinsFromModuleToAccount(ctx, testutil.MintModuleName, addr1, feeAmount)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, feeCoin.Amount, bankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount)
|
||||
|
||||
// msg and signatures
|
||||
msg := &baseapptestutil.MsgKeyValue{
|
||||
Key: []byte("ok"),
|
||||
Value: []byte("ok"),
|
||||
Signer: addr1.String(),
|
||||
}
|
||||
|
||||
txBuilder := txConfig.NewTxBuilder()
|
||||
|
||||
require.NoError(t, txBuilder.SetMsgs(msg))
|
||||
txBuilder.SetFeeAmount(feeAmount)
|
||||
txBuilder.SetGasLimit(uint64(simtestutil.DefaultConsensusParams.Block.MaxGas))
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
_, txBytes, err := createTestTx(txConfig, txBuilder, privs, accNums, accSeqs, ctx.ChainID())
|
||||
require.NoError(t, err)
|
||||
|
||||
rsp, err := bapp.FinalizeBlock(&abci.FinalizeBlockRequest{Height: 1, Txs: [][]byte{txBytes}})
|
||||
require.NoError(t, err)
|
||||
|
||||
// check result
|
||||
ctx = bapp.GetContextForFinalizeBlock(txBytes)
|
||||
okValue := ctx.KVStore(bapp.UnsafeFindStoreKey(testutil.BankModuleName)).Get([]byte("ok"))
|
||||
|
||||
if tc.expErr {
|
||||
if tc.panicTx {
|
||||
require.Equal(t, sdkerrors.ErrPanic.ABCICode(), rsp.TxResults[0].Code)
|
||||
} else {
|
||||
require.Equal(t, sdkerrors.ErrOutOfGas.ABCICode(), rsp.TxResults[0].Code)
|
||||
}
|
||||
require.Empty(t, okValue)
|
||||
} else {
|
||||
require.Equal(t, uint32(0), rsp.TxResults[0].Code, "failure", rsp.TxResults[0].Log)
|
||||
require.Equal(t, []byte("ok"), okValue)
|
||||
}
|
||||
// check block gas is always consumed
|
||||
baseGas := uint64(38142) // baseGas is the gas consumed before tx msg
|
||||
expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas)
|
||||
if expGasConsumed > uint64(simtestutil.DefaultConsensusParams.Block.MaxGas) {
|
||||
// capped by gasLimit
|
||||
expGasConsumed = uint64(simtestutil.DefaultConsensusParams.Block.MaxGas)
|
||||
}
|
||||
require.Equal(t, int(expGasConsumed), int(ctx.BlockGasMeter().GasConsumed()))
|
||||
// tx fee is always deducted
|
||||
require.Equal(t, int64(0), bankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount.Int64())
|
||||
// sender's sequence is always increased
|
||||
seq := accountKeeper.GetAccount(ctx, addr1).GetSequence()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(1), seq)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func createTestTx(txConfig client.TxConfig, txBuilder client.TxBuilder, privs []cryptotypes.PrivKey, accNums, accSeqs []uint64, chainID string) (xauthsigning.Tx, []byte, error) {
|
||||
defaultSignMode, err := xauthsigning.APISignModeToInternal(txConfig.SignModeHandler().DefaultMode())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// First round: we gather all the signer infos. We use the "set empty
|
||||
// signature" hack to do that.
|
||||
var sigsV2 []signing.SignatureV2
|
||||
for i, priv := range privs {
|
||||
sigV2 := signing.SignatureV2{
|
||||
PubKey: priv.PubKey(),
|
||||
Data: &signing.SingleSignatureData{
|
||||
SignMode: defaultSignMode,
|
||||
Signature: nil,
|
||||
},
|
||||
Sequence: accSeqs[i],
|
||||
}
|
||||
|
||||
sigsV2 = append(sigsV2, sigV2)
|
||||
}
|
||||
err = txBuilder.SetSignatures(sigsV2...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Second round: all signer infos are set, so each signer can sign.
|
||||
sigsV2 = []signing.SignatureV2{}
|
||||
for i, priv := range privs {
|
||||
signerData := xauthsigning.SignerData{
|
||||
Address: sdk.AccAddress(priv.PubKey().Bytes()).String(),
|
||||
ChainID: chainID,
|
||||
AccountNumber: accNums[i],
|
||||
Sequence: accSeqs[i],
|
||||
PubKey: priv.PubKey(),
|
||||
}
|
||||
sigV2, err := tx.SignWithPrivKey(
|
||||
context.TODO(), defaultSignMode, signerData,
|
||||
txBuilder, priv, txConfig, accSeqs[i])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sigsV2 = append(sigsV2, sigV2)
|
||||
}
|
||||
err = txBuilder.SetSignatures(sigsV2...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
txBytes, err := txConfig.TxEncoder()(txBuilder.GetTx())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return txBuilder.GetTx(), txBytes, nil
|
||||
}
|
||||
|
||||
func addUint64Saturating(a, b uint64) uint64 {
|
||||
if math.MaxUint64-a < b {
|
||||
return math.MaxUint64
|
||||
}
|
||||
|
||||
return a + b
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package baseapp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
cmttypes "github.com/cometbft/cometbft/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
_ "cosmossdk.io/x/bank"
|
||||
banktypes "cosmossdk.io/x/bank/types"
|
||||
_ "cosmossdk.io/x/consensus"
|
||||
_ "cosmossdk.io/x/staking"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/mock"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
// GenesisStateWithSingleValidator initializes GenesisState with a single validator and genesis accounts
|
||||
// that also act as delegators.
|
||||
func GenesisStateWithSingleValidator(t *testing.T, codec codec.Codec, builder *runtime.AppBuilder) map[string]json.RawMessage {
|
||||
t.Helper()
|
||||
|
||||
privVal := mock.NewPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
// create validator set with single validator
|
||||
validator := cmttypes.NewValidator(pubKey, 1)
|
||||
valSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{validator})
|
||||
|
||||
// generate genesis account
|
||||
senderPrivKey := secp256k1.GenPrivKey()
|
||||
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
|
||||
balances := []banktypes.Balance{
|
||||
{
|
||||
Address: acc.GetAddress().String(),
|
||||
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100000000000000))),
|
||||
},
|
||||
}
|
||||
|
||||
genesisState := builder.DefaultGenesis()
|
||||
// sus
|
||||
genesisState, err = simtestutil.GenesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balances...)
|
||||
require.NoError(t, err)
|
||||
|
||||
return genesisState
|
||||
}
|
||||
|
||||
type BankKeeper interface {
|
||||
MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error
|
||||
SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
|
||||
GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin
|
||||
}
|
||||
|
||||
type AuthKeeper interface {
|
||||
GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI
|
||||
}
|
||||
Reference in New Issue
Block a user