github.com/Finschia/finschia-sdk@v0.48.1/baseapp/block_gas_test.go (about) 1 package baseapp_test 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math" 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 abci "github.com/tendermint/tendermint/abci/types" 11 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 12 dbm "github.com/tendermint/tm-db" 13 14 ocabci "github.com/Finschia/ostracon/abci/types" 15 "github.com/Finschia/ostracon/libs/log" 16 17 "github.com/Finschia/finschia-sdk/baseapp" 18 "github.com/Finschia/finschia-sdk/client" 19 "github.com/Finschia/finschia-sdk/client/tx" 20 cryptotypes "github.com/Finschia/finschia-sdk/crypto/types" 21 "github.com/Finschia/finschia-sdk/simapp" 22 "github.com/Finschia/finschia-sdk/testutil/testdata" 23 sdk "github.com/Finschia/finschia-sdk/types" 24 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 25 txtypes "github.com/Finschia/finschia-sdk/types/tx" 26 "github.com/Finschia/finschia-sdk/types/tx/signing" 27 xauthsigning "github.com/Finschia/finschia-sdk/x/auth/signing" 28 banktypes "github.com/Finschia/finschia-sdk/x/bank/types" 29 minttypes "github.com/Finschia/finschia-sdk/x/mint/types" 30 ) 31 32 var blockMaxGas = uint64(simapp.DefaultConsensusParams.Block.MaxGas) 33 34 func TestBaseApp_BlockGas(t *testing.T) { 35 testcases := []struct { 36 name string 37 gasToConsume uint64 // gas to consume in the msg execution 38 panicTx bool // panic explicitly in tx execution 39 expErr bool 40 }{ 41 {"less than block gas meter", 10, false, false}, 42 {"more than block gas meter", blockMaxGas, false, true}, 43 {"more than block gas meter", uint64(float64(blockMaxGas) * 1.2), false, true}, 44 {"consume MaxUint64", math.MaxUint64, false, true}, 45 {"consume MaxGasWanted", txtypes.MaxGasWanted, false, true}, 46 {"consume block gas when paniced", 10, true, true}, 47 } 48 for _, tc := range testcases { 49 t.Run(tc.name, func(t *testing.T) { 50 var app *simapp.SimApp 51 routerOpt := func(bapp *baseapp.BaseApp) { 52 route := (&testdata.TestMsg{}).Route() 53 bapp.Router().AddRoute(sdk.NewRoute(route, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 54 _, ok := msg.(*testdata.TestMsg) 55 if !ok { 56 return &sdk.Result{}, fmt.Errorf("Wrong Msg type, expected %T, got %T", (*testdata.TestMsg)(nil), msg) 57 } 58 ctx.KVStore(app.GetKey(banktypes.ModuleName)).Set([]byte("ok"), []byte("ok")) 59 ctx.GasMeter().ConsumeGas(tc.gasToConsume, "TestMsg") 60 if tc.panicTx { 61 panic("panic in tx execution") 62 } 63 return &sdk.Result{}, nil 64 })) 65 } 66 encCfg := simapp.MakeTestEncodingConfig() 67 encCfg.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) 68 encCfg.InterfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), 69 &testdata.TestMsg{}, 70 ) 71 app = simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, "", 0, encCfg, simapp.EmptyAppOptions{}, routerOpt) 72 genState := simapp.NewDefaultGenesisState(encCfg.Marshaler) 73 stateBytes, err := json.MarshalIndent(genState, "", " ") 74 require.NoError(t, err) 75 app.InitChain(abci.RequestInitChain{ 76 Validators: []abci.ValidatorUpdate{}, 77 ConsensusParams: simapp.DefaultConsensusParams, 78 AppStateBytes: stateBytes, 79 }) 80 81 ctx := app.NewContext(false, tmproto.Header{}) 82 83 // tx fee 84 feeCoin := sdk.NewCoin("atom", sdk.NewInt(150)) 85 feeAmount := sdk.NewCoins(feeCoin) 86 87 // test account and fund 88 priv1, _, addr1 := testdata.KeyTestPubAddr() 89 err = app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, feeAmount) 90 require.NoError(t, err) 91 err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr1, feeAmount) 92 require.NoError(t, err) 93 require.Equal(t, feeCoin.Amount, app.BankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount) 94 seq, _ := app.AccountKeeper.GetSequence(ctx, addr1) 95 require.Equal(t, uint64(0), seq) 96 97 // msg and signatures 98 msg := testdata.NewTestMsg(addr1) 99 100 txBuilder := encCfg.TxConfig.NewTxBuilder() 101 require.NoError(t, txBuilder.SetMsgs(msg)) 102 txBuilder.SetFeeAmount(feeAmount) 103 txBuilder.SetGasLimit(txtypes.MaxGasWanted) // tx validation checks that gasLimit can't be bigger than this 104 105 privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{6}, []uint64{0} 106 _, txBytes, err := createTestTx(encCfg.TxConfig, txBuilder, privs, accNums, accSeqs, ctx.ChainID()) 107 require.NoError(t, err) 108 109 app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: 1}}) 110 rsp := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 111 112 // check result 113 ctx = app.GetContextForDeliverTx(txBytes) 114 okValue := ctx.KVStore(app.GetKey(banktypes.ModuleName)).Get([]byte("ok")) 115 116 if tc.expErr { 117 if tc.panicTx { 118 require.Equal(t, sdkerrors.ErrPanic.ABCICode(), rsp.Code) 119 } else { 120 require.Equal(t, sdkerrors.ErrOutOfGas.ABCICode(), rsp.Code) 121 } 122 require.Empty(t, okValue) 123 } else { 124 require.Equal(t, uint32(0), rsp.Code) 125 require.Equal(t, []byte("ok"), okValue) 126 } 127 // check block gas is always consumed 128 baseGas := uint64(37352) // baseGas is the gas consumed before tx msg 129 expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas) 130 if expGasConsumed > txtypes.MaxGasWanted { 131 // capped by gasLimit 132 expGasConsumed = txtypes.MaxGasWanted 133 } 134 require.Equal(t, expGasConsumed, ctx.BlockGasMeter().GasConsumed()) 135 // tx fee is always deducted 136 require.Equal(t, int64(0), app.BankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount.Int64()) 137 // sender's sequence is always increased 138 seq, err = app.AccountKeeper.GetSequence(ctx, addr1) 139 require.NoError(t, err) 140 require.Equal(t, uint64(1), seq) 141 }) 142 } 143 } 144 145 func createTestTx(txConfig client.TxConfig, txBuilder client.TxBuilder, privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (xauthsigning.Tx, []byte, error) { 146 // First round: we gather all the signer infos. We use the "set empty 147 // signature" hack to do that. 148 var sigsV2 []signing.SignatureV2 149 for i, priv := range privs { 150 sigV2 := signing.SignatureV2{ 151 PubKey: priv.PubKey(), 152 Data: &signing.SingleSignatureData{ 153 SignMode: txConfig.SignModeHandler().DefaultMode(), 154 Signature: nil, 155 }, 156 Sequence: accSeqs[i], 157 } 158 159 sigsV2 = append(sigsV2, sigV2) 160 } 161 err := txBuilder.SetSignatures(sigsV2...) 162 if err != nil { 163 return nil, nil, err 164 } 165 166 // Second round: all signer infos are set, so each signer can sign. 167 sigsV2 = []signing.SignatureV2{} 168 for i, priv := range privs { 169 signerData := xauthsigning.SignerData{ 170 ChainID: chainID, 171 AccountNumber: accNums[i], 172 Sequence: accSeqs[i], 173 } 174 sigV2, err := tx.SignWithPrivKey( 175 txConfig.SignModeHandler().DefaultMode(), signerData, 176 txBuilder, priv, txConfig, accSeqs[i]) 177 if err != nil { 178 return nil, nil, err 179 } 180 181 sigsV2 = append(sigsV2, sigV2) 182 } 183 err = txBuilder.SetSignatures(sigsV2...) 184 if err != nil { 185 return nil, nil, err 186 } 187 188 txBytes, err := txConfig.TxEncoder()(txBuilder.GetTx()) 189 if err != nil { 190 return nil, nil, err 191 } 192 193 return txBuilder.GetTx(), txBytes, nil 194 } 195 196 func addUint64Saturating(a, b uint64) uint64 { 197 if math.MaxUint64-a < b { 198 return math.MaxUint64 199 } 200 201 return a + b 202 }