Consume block gas to tx gas limit even upon overconsumption

This commit is contained in:
Jae Kwon 2018-11-20 20:07:30 -08:00
parent 10bdf8fa03
commit 4afd53d81b
4 changed files with 53 additions and 13 deletions

View File

@ -688,7 +688,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
ctx = app.initializeContext(ctx, mode)
// only run the tx if there is block gas remaining
if mode == runTxModeDeliver && ctx.BlockGasMeter().PastLimit() {
if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() {
result = sdk.ErrOutOfGas("no block gas left to run tx").Result()
return
}
@ -705,6 +705,12 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
}
}
// consume block gas whether panic or not.
if mode == runTxModeDeliver {
ctx.BlockGasMeter().ConsumeGas(
ctx.GasMeter().GasConsumedToLimit(), "block gas meter")
}
result.GasWanted = gasWanted
result.GasUsed = ctx.GasMeter().GasConsumed()
}()
@ -750,12 +756,6 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
result = app.runMsgs(runMsgCtx, msgs, mode)
result.GasWanted = gasWanted
// consume block gas
if mode == runTxModeDeliver {
ctx.BlockGasMeter().ConsumeGas(
ctx.GasMeter().GasConsumed(), "block gas meter")
}
// only update state if all messages pass
if result.IsOK() {
msCache.Write()

View File

@ -943,16 +943,16 @@ func TestMaxBlockGasLimits(t *testing.T) {
if tc.fail && (j+1) > tc.failAfterDeliver {
require.Equal(t, res.Code, sdk.CodeOutOfGas, fmt.Sprintf("%d: %v, %v", i, tc, res))
require.Equal(t, res.Codespace, sdk.CodespaceRoot, fmt.Sprintf("%d: %v, %v", i, tc, res))
require.True(t, ctx.BlockGasMeter().PastLimit())
//require.True(t, ctx.BlockGasMeter().IsPastLimit()) NOTE: not necessarily true.
require.True(t, ctx.BlockGasMeter().IsOutOfGas())
} else {
// check gas used and wanted
expBlockGasUsed := tc.gasUsedPerDeliver * uint64(j+1)
require.Equal(t, expBlockGasUsed, blockGasUsed,
fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, res))
require.True(t, res.IsOK(), fmt.Sprintf("%d,%d: %v, %v", i, j, tc, res))
require.False(t, ctx.BlockGasMeter().PastLimit())
require.False(t, ctx.BlockGasMeter().IsPastLimit())
}
}
}

View File

@ -34,8 +34,11 @@ type ErrorGasOverflow struct {
// GasMeter interface to track gas consumption
type GasMeter interface {
GasConsumed() Gas
GasConsumedToLimit() Gas
Limit() Gas
ConsumeGas(amount Gas, descriptor string)
PastLimit() bool
IsPastLimit() bool
IsOutOfGas() bool
}
type basicGasMeter struct {
@ -55,6 +58,18 @@ func (g *basicGasMeter) GasConsumed() Gas {
return g.consumed
}
func (g *basicGasMeter) Limit() Gas {
return g.limit
}
func (g *basicGasMeter) GasConsumedToLimit() Gas {
if g.consumed > g.limit {
return g.limit
} else {
return g.consumed
}
}
func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
var overflow bool
@ -69,10 +84,14 @@ func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
}
}
func (g *basicGasMeter) PastLimit() bool {
func (g *basicGasMeter) IsPastLimit() bool {
return g.consumed > g.limit
}
func (g *basicGasMeter) IsOutOfGas() bool {
return g.consumed >= g.limit
}
type infiniteGasMeter struct {
consumed Gas
}
@ -88,6 +107,14 @@ func (g *infiniteGasMeter) GasConsumed() Gas {
return g.consumed
}
func (g *infiniteGasMeter) GasConsumedToLimit() Gas {
return g.consumed
}
func (g *infiniteGasMeter) Limit() Gas {
return 0
}
func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
var overflow bool
@ -98,7 +125,11 @@ func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
}
}
func (g *infiniteGasMeter) PastLimit() bool {
func (g *infiniteGasMeter) IsPastLimit() bool {
return false
}
func (g *infiniteGasMeter) IsOutOfGas() bool {
return false
}

View File

@ -27,9 +27,18 @@ func TestGasMeter(t *testing.T) {
used += usage
require.NotPanics(t, func() { meter.ConsumeGas(usage, "") }, "Not exceeded limit but panicked. tc #%d, usage #%d", tcnum, unum)
require.Equal(t, used, meter.GasConsumed(), "Gas consumption not match. tc #%d, usage #%d", tcnum, unum)
require.Equal(t, used, meter.GasConsumedToLimit(), "Gas consumption (to limit) not match. tc #%d, usage #%d", tcnum, unum)
require.False(t, meter.IsPastLimit(), "Not exceeded limit but got IsPastLimit() true")
if unum < len(tc.usage)-1 {
require.False(t, meter.IsOutOfGas(), "Not yet at limit but got IsOutOfGas() true")
} else {
require.True(t, meter.IsOutOfGas(), "At limit but got IsOutOfGas() false")
}
}
require.Panics(t, func() { meter.ConsumeGas(1, "") }, "Exceeded but not panicked. tc #%d", tcnum)
require.Equal(t, meter.GasConsumedToLimit(), meter.Limit(), "Gas consumption (to limit) not match limit")
require.Equal(t, meter.GasConsumed(), meter.Limit()+1, "Gas consumption not match limit+1")
break
}