feat!: Add gas limits to queries (backport #16239) (#17324)

Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
This commit is contained in:
mergify[bot]
2023-08-09 10:22:34 +02:00
committed by GitHub
co-authored by Dev Ojha
parent 6b395f61d9
commit bee95b19b5
10 changed files with 109 additions and 2 deletions
+2 -1
View File
@@ -1116,7 +1116,8 @@ func (app *BaseApp) CreateQueryContext(height int64, prove bool) (sdk.Context, e
// branch the commit multi-store for safety
ctx := sdk.NewContext(cacheMS, app.checkState.ctx.BlockHeader(), true, app.logger).
WithMinGasPrices(app.minGasPrices).
WithBlockHeight(height)
WithBlockHeight(height).
WithGasMeter(storetypes.NewGasMeter(app.queryGasLimit))
if height != lastBlockHeight {
rms, ok := app.cms.(*rootmulti.Store)
+5
View File
@@ -3,6 +3,7 @@ package baseapp
import (
"context"
"fmt"
"math"
"sort"
"strconv"
@@ -123,6 +124,9 @@ type BaseApp struct {
// application parameter store.
paramStore ParamStore
// queryGasLimit defines the maximum gas for queries; unbounded if 0.
queryGasLimit uint64
// The minimum gas prices a validator is willing to accept for processing a
// transaction. This is mainly used for DoS and spam prevention.
minGasPrices sdk.DecCoins
@@ -192,6 +196,7 @@ func NewBaseApp(
msgServiceRouter: NewMsgServiceRouter(),
txDecoder: txDecoder,
fauxMerkleMode: false,
queryGasLimit: math.MaxUint64,
}
for _, option := range options {
+74
View File
@@ -85,6 +85,26 @@ func NewBaseAppSuite(t *testing.T, opts ...func(*baseapp.BaseApp)) *BaseAppSuite
}
}
func getQueryBaseapp(t *testing.T) *baseapp.BaseApp {
t.Helper()
db := dbm.NewMemDB()
name := t.Name()
app := baseapp.NewBaseApp(name, log.NewTestLogger(t), db, nil)
_, err := app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1})
require.NoError(t, err)
_, err = app.Commit()
require.NoError(t, err)
_, err = app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 2})
require.NoError(t, err)
_, err = app.Commit()
require.NoError(t, err)
return app
}
func NewBaseAppSuiteWithSnapshots(t *testing.T, cfg SnapshotsConfig, opts ...func(*baseapp.BaseApp)) *BaseAppSuite {
snapshotTimeout := 1 * time.Minute
snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t))
@@ -614,6 +634,60 @@ func TestSetMinGasPrices(t *testing.T) {
require.Equal(t, minGasPrices, ctx.MinGasPrices())
}
type ctxType string
const (
QueryCtx ctxType = "query"
CheckTxCtx ctxType = "checkTx"
)
var ctxTypes = []ctxType{QueryCtx, CheckTxCtx}
func (c ctxType) GetCtx(t *testing.T, bapp *baseapp.BaseApp) sdk.Context {
t.Helper()
if c == QueryCtx {
ctx, err := bapp.CreateQueryContext(1, false)
require.NoError(t, err)
return ctx
} else if c == CheckTxCtx {
return getCheckStateCtx(bapp)
}
// TODO: Not supported yet
return getFinalizeBlockStateCtx(bapp)
}
func TestQueryGasLimit(t *testing.T) {
testCases := []struct {
queryGasLimit uint64
gasActuallyUsed uint64
shouldQueryErr bool
}{
{queryGasLimit: 100, gasActuallyUsed: 50, shouldQueryErr: false}, // Valid case
{queryGasLimit: 100, gasActuallyUsed: 150, shouldQueryErr: true}, // gasActuallyUsed > queryGasLimit
{queryGasLimit: 0, gasActuallyUsed: 50, shouldQueryErr: false}, // fuzzing with queryGasLimit = 0
{queryGasLimit: 0, gasActuallyUsed: 0, shouldQueryErr: false}, // both queryGasLimit and gasActuallyUsed are 0
{queryGasLimit: 200, gasActuallyUsed: 200, shouldQueryErr: false}, // gasActuallyUsed == queryGasLimit
{queryGasLimit: 100, gasActuallyUsed: 1000, shouldQueryErr: true}, // gasActuallyUsed > queryGasLimit
}
for _, tc := range testCases {
for _, ctxType := range ctxTypes {
t.Run(fmt.Sprintf("%s: %d - %d", ctxType, tc.queryGasLimit, tc.gasActuallyUsed), func(t *testing.T) {
app := getQueryBaseapp(t)
baseapp.SetQueryGasLimit(tc.queryGasLimit)(app)
ctx := ctxType.GetCtx(t, app)
// query gas limit should have no effect when CtxType != QueryCtx
if tc.shouldQueryErr && ctxType == QueryCtx {
require.Panics(t, func() { ctx.GasMeter().ConsumeGas(tc.gasActuallyUsed, "test") })
} else {
require.NotPanics(t, func() { ctx.GasMeter().ConsumeGas(tc.gasActuallyUsed, "test") })
}
})
}
}
}
func TestGetMaximumBlockGas(t *testing.T) {
suite := NewBaseAppSuite(t)
_, err := suite.baseApp.InitChain(&abci.RequestInitChain{})
+10
View File
@@ -3,6 +3,7 @@ package baseapp
import (
"fmt"
"io"
"math"
dbm "github.com/cosmos/cosmos-db"
@@ -36,6 +37,15 @@ func SetMinGasPrices(gasPricesStr string) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.setMinGasPrices(gasPrices) }
}
// SetQueryGasLimit returns an option that sets a gas limit for queries.
func SetQueryGasLimit(queryGasLimit uint64) func(*BaseApp) {
if queryGasLimit == 0 {
queryGasLimit = math.MaxUint64
}
return func(bapp *BaseApp) { bapp.queryGasLimit = queryGasLimit }
}
// SetHaltHeight returns a BaseApp option function that sets the halt block height.
func SetHaltHeight(blockHeight uint64) func(*BaseApp) {
return func(bapp *BaseApp) { bapp.setHaltHeight(blockHeight) }