fix: set block gas meter on prepare/process proposal (backport #15012) (#15040)

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot] 2023-02-15 16:30:08 -05:00 committed by GitHub
parent 04e9890555
commit 2e80d3b8b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 20 deletions

View File

@ -159,7 +159,8 @@ clean:
rm -rf \
$(BUILDDIR)/ \
artifacts/ \
tmp-swagger-gen/
tmp-swagger-gen/ \
.testnets
.PHONY: distclean clean

View File

@ -171,15 +171,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
WithBlockHeight(req.Header.Height)
}
// add block gas meter
var gasMeter sdk.GasMeter
if maxGas := app.GetMaximumBlockGas(app.deliverState.ctx); maxGas > 0 {
gasMeter = sdk.NewGasMeter(maxGas)
} else {
gasMeter = sdk.NewInfiniteGasMeter()
}
// NOTE: header hash is not set in NewContext, so we manually set it here
gasMeter := app.getBlockGasMeter(app.deliverState.ctx)
app.deliverState.ctx = app.deliverState.ctx.
WithBlockGasMeter(gasMeter).
@ -258,13 +250,15 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci.
panic("PrepareProposal called with invalid height")
}
gasMeter := app.getBlockGasMeter(app.prepareProposalState.ctx)
ctx := app.getContextForProposal(app.prepareProposalState.ctx, req.Height)
ctx = ctx.WithVoteInfos(app.voteInfos).
WithBlockHeight(req.Height).
WithBlockTime(req.Time).
WithProposer(req.ProposerAddress).
WithConsensusParams(app.GetConsensusParams(ctx))
WithConsensusParams(app.GetConsensusParams(ctx)).
WithBlockGasMeter(gasMeter)
defer func() {
if err := recover(); err != nil {
@ -274,6 +268,7 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci.
"time", req.Time,
"panic", err,
)
resp = abci.ResponsePrepareProposal{Txs: req.Txs}
}
}()
@ -302,6 +297,7 @@ func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci.
panic("app.ProcessProposal is not set")
}
gasMeter := app.getBlockGasMeter(app.processProposalState.ctx)
ctx := app.getContextForProposal(app.processProposalState.ctx, req.Height)
ctx = ctx.
@ -310,7 +306,8 @@ func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci.
WithBlockTime(req.Time).
WithHeaderHash(req.Hash).
WithProposer(req.ProposerAddress).
WithConsensusParams(app.GetConsensusParams(ctx))
WithConsensusParams(app.GetConsensusParams(ctx)).
WithBlockGasMeter(gasMeter)
defer func() {
if err := recover(); err != nil {

View File

@ -542,15 +542,26 @@ func (app *BaseApp) getState(mode runTxMode) *state {
switch mode {
case runTxModeDeliver:
return app.deliverState
case runTxPrepareProposal:
return app.prepareProposalState
case runTxProcessProposal:
return app.processProposalState
default:
return app.checkState
}
}
func (app *BaseApp) getBlockGasMeter(ctx sdk.Context) storetypes.GasMeter {
if maxGas := app.GetMaximumBlockGas(ctx); maxGas > 0 {
return storetypes.NewGasMeter(maxGas)
}
return storetypes.NewInfiniteGasMeter()
}
// retrieve the context for the tx w/ txBytes and other memoized values.
func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) sdk.Context {
modeState := app.getState(mode)
@ -624,8 +635,10 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
}()
blockGasConsumed := false
// consumeBlockGas makes sure block gas is consumed at most once. It must happen after
// tx processing, and must be executed even if tx processing fails. Hence, we use trick with `defer`
// consumeBlockGas makes sure block gas is consumed at most once. It must
// happen after tx processing, and must be executed even if tx processing
// fails. Hence, it's execution is deferred.
consumeBlockGas := func() {
if !blockGasConsumed {
blockGasConsumed = true
@ -638,8 +651,9 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
// If BlockGasMeter() panics it will be caught by the above recover and will
// return an error - in any case BlockGasMeter will consume gas past the limit.
//
// NOTE: This must exist in a separate defer function for the above recovery
// to recover from this one.
// NOTE: consumeBlockGas must exist in a separate defer function from the
// general deferred recovery function to recover from consumeBlockGas as it'll
// be executed first (deferred statements are executed as stack).
if mode == runTxModeDeliver {
defer consumeBlockGas()
}
@ -717,9 +731,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
// and we're in DeliverTx. Note, runMsgs will never return a reference to a
// Result if any single message fails or does not have a registered Handler.
result, err = app.runMsgs(runMsgCtx, msgs, mode)
if err == nil {
// Run optional postHandlers.
//
// Note: If the postHandler fails, we also revert the runMsgs state.
@ -765,7 +777,6 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s
// NOTE: GasWanted is determined by the AnteHandler and GasUsed by the GasMeter.
for i, msg := range msgs {
if mode != runTxModeDeliver && mode != runTxModeSimulate {
break
}
@ -938,6 +949,7 @@ func (app *BaseApp) DefaultProcessProposal() sdk.ProcessProposalHandler {
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}
}
}
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}
}
}

View File

@ -83,7 +83,8 @@ func (g *basicGasMeter) Limit() Gas {
// GasConsumedToLimit returns the gas limit if gas consumed is past the limit,
// otherwise it returns the consumed gas.
// NOTE: This behaviour is only called when recovering from panic when
//
// NOTE: This behavior is only called when recovering from panic when
// BlockGasMeter consumes gas past the limit.
func (g *basicGasMeter) GasConsumedToLimit() Gas {
if g.IsPastLimit() {