Skip to content
This repository has been archived by the owner on Jun 9, 2024. It is now read-only.

Commit

Permalink
fix(precompile): Fix regression where eth_call can cause non-determ…
Browse files Browse the repository at this point in the history
…inistic gas consumption (#1136)
  • Loading branch information
itsdevbear authored Sep 24, 2023
1 parent 6a92c39 commit 15c1356
Show file tree
Hide file tree
Showing 13 changed files with 45 additions and 80 deletions.
9 changes: 4 additions & 5 deletions cosmos/x/evm/keeper/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"

"pkg.berachain.dev/polaris/cosmos/x/evm/plugins"
"pkg.berachain.dev/polaris/cosmos/x/evm/plugins/block"
"pkg.berachain.dev/polaris/cosmos/x/evm/plugins/configuration"
"pkg.berachain.dev/polaris/cosmos/x/evm/plugins/engine"
Expand All @@ -49,7 +48,7 @@ var _ core.PolarisHostChain = (*host)(nil)
// It includes core.PolarisHostChain and functions that are called in other packages.
type Host interface {
core.PolarisHostChain
GetAllPlugins() []plugins.Base
GetAllPlugins() []any
Setup(
storetypes.StoreKey,
storetypes.StoreKey,
Expand Down Expand Up @@ -103,7 +102,7 @@ func (h *host) Setup(
) {
// Setup the state, precompile, historical, and txpool plugins
h.sp = state.NewPlugin(ak, storeKey, log.NewFactory(h.pcs().GetPrecompiles()))
h.pp = precompile.NewPlugin(h.pcs().GetPrecompiles(), h.sp)
h.pp = precompile.NewPlugin(h.pcs().GetPrecompiles())
// TODO: re-enable historical plugin using ABCI listener.
h.hp = historical.NewPlugin(h.cp, h.bp, nil, storeKey)
h.txp.SetNonceRetriever(h.sp)
Expand Down Expand Up @@ -153,6 +152,6 @@ func (h *host) GetTxPoolPlugin() core.TxPoolPlugin {
}

// GetAllPlugins returns all the plugins.
func (h *host) GetAllPlugins() []plugins.Base {
return []plugins.Base{h.bp, h.cp, h.gp, h.hp, h.pp, h.sp, h.txp}
func (h *host) GetAllPlugins() []any {
return []any{h.bp, h.cp, h.gp, h.hp, h.pp, h.sp, h.txp}
}
4 changes: 0 additions & 4 deletions cosmos/x/evm/plugins/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ import (
"pkg.berachain.dev/polaris/eth/core"
)

// Base is the base interface which all x/evm Polaris plugins must implement

type Base interface{}

// HasGenesis represents the base class that all x/evm Polaris plugins which have
// InitGenesis or ExportGenesis methods must implement

Expand Down
1 change: 0 additions & 1 deletion cosmos/x/evm/plugins/block/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import (
)

type Plugin interface {
plugins.Base
plugins.HasGenesis
core.BlockPlugin

Expand Down
1 change: 0 additions & 1 deletion cosmos/x/evm/plugins/configuration/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (

// Plugin is the interface that must be implemented by the plugin.
type Plugin interface {
plugins.Base
plugins.HasGenesis
core.ConfigurationPlugin
SetChainConfig(*params.ChainConfig)
Expand Down
2 changes: 0 additions & 2 deletions cosmos/x/evm/plugins/engine/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ package engine
import (
"github.com/cosmos/cosmos-sdk/client"

"pkg.berachain.dev/polaris/cosmos/x/evm/plugins"
"pkg.berachain.dev/polaris/eth/core"
)

Expand All @@ -32,7 +31,6 @@ var _ Plugin = (*plugin)(nil)

// Plugin defines the required functions of the transaction pool plugin.
type Plugin interface {
plugins.Base
core.EnginePlugin
Start(client.Context)
}
Expand Down
2 changes: 0 additions & 2 deletions cosmos/x/evm/plugins/gas/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"

"pkg.berachain.dev/polaris/cosmos/x/evm/plugins"
"pkg.berachain.dev/polaris/eth/core"
"pkg.berachain.dev/polaris/eth/core/vm"
)
Expand All @@ -38,7 +37,6 @@ const gasMeterDescriptor = `polaris-gas-plugin`

// Plugin is the interface that must be implemented by the plugin.
type Plugin interface {
plugins.Base
core.GasPlugin
}

Expand Down
1 change: 0 additions & 1 deletion cosmos/x/evm/plugins/historical/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (

// Plugin is the interface that must be implemented by the plugin.
type Plugin interface {
plugins.Base
core.HistoricalPlugin
plugins.HasGenesis
}
Expand Down
52 changes: 18 additions & 34 deletions cosmos/x/evm/plugins/precompile/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"

"pkg.berachain.dev/polaris/cosmos/x/evm/plugins"
"pkg.berachain.dev/polaris/cosmos/x/evm/plugins/state"
"pkg.berachain.dev/polaris/eth/common"
"pkg.berachain.dev/polaris/eth/core"
ethprecompile "pkg.berachain.dev/polaris/eth/core/precompile"
ethstate "pkg.berachain.dev/polaris/eth/core/state"
"pkg.berachain.dev/polaris/eth/core/vm"
"pkg.berachain.dev/polaris/eth/params"
"pkg.berachain.dev/polaris/lib/registry"
Expand All @@ -41,13 +41,14 @@ import (

// Plugin is the interface that must be implemented by the plugin.
type Plugin interface {
plugins.Base
core.PrecompilePlugin
}

KVGasConfig() storetypes.GasConfig
SetKVGasConfig(storetypes.GasConfig)
TransientKVGasConfig() storetypes.GasConfig
SetTransientKVGasConfig(storetypes.GasConfig)
// polarisStateDB is the interface that must be implemented by the state DB.
// The stateDB must allow retrieving the plugin in order to set it's gas config.
type polarisStateDB interface {
// GetPlugin retrieves the underlying state plugin from the StateDB.
GetPlugin() ethstate.Plugin
}

// plugin runs precompile containers in the Cosmos environment with the context gas configs.
Expand All @@ -59,18 +60,17 @@ type plugin struct {
kvGasConfig storetypes.GasConfig
// transientKVGasConfig is the gas config for the transient KV store.
transientKVGasConfig storetypes.GasConfig
// sp allows resetting the context for the reentrancy into the EVM.
sp StatePlugin
}

// NewPlugin creates and returns a plugin with the default KV store gas configs.
func NewPlugin(precompiles []ethprecompile.Registrable, sp StatePlugin) Plugin {
func NewPlugin(precompiles []ethprecompile.Registrable) Plugin {
return &plugin{
Registry: registry.NewMap[common.Address, vm.PrecompileContainer](),
precompiles: precompiles,
Registry: registry.NewMap[common.Address, vm.PrecompileContainer](),
precompiles: precompiles,
// NOTE: these are hardcoded as they are also hardcoded in the sdk.
// This should be updated if it ever changes.
kvGasConfig: storetypes.KVGasConfig(),
transientKVGasConfig: storetypes.TransientGasConfig(),
sp: sp,
}
}

Expand All @@ -92,26 +92,6 @@ func (p *plugin) GetActive(rules *params.Rules) []common.Address {
return active
}

// KVGasConfig implements Plugin.
func (p *plugin) KVGasConfig() storetypes.GasConfig {
return p.kvGasConfig
}

// SetKVGasConfig implements Plugin.
func (p *plugin) SetKVGasConfig(kvGasConfig storetypes.GasConfig) {
p.kvGasConfig = kvGasConfig
}

// TransientKVGasConfig implements Plugin.
func (p *plugin) TransientKVGasConfig() storetypes.GasConfig {
return p.transientKVGasConfig
}

// SetTransientKVGasConfig implements Plugin.
func (p *plugin) SetTransientKVGasConfig(transientKVGasConfig storetypes.GasConfig) {
p.transientKVGasConfig = transientKVGasConfig
}

// Run runs the a precompile container and returns the remaining gas after execution by injecting
// a Cosmos SDK `GasMeter`. This function returns an error if the precompile execution returns an
// error or insufficient gas is provided.
Expand Down Expand Up @@ -187,7 +167,9 @@ func (p *plugin) enableReentrancy(sdb vm.PolarisStateDB) {
cem.EndPrecompileExecution()

// remove Cosmos gas consumption so gas is consumed only per OPCODE
p.sp.SetGasConfig(storetypes.GasConfig{}, storetypes.GasConfig{})
utils.MustGetAs[state.Plugin](
utils.MustGetAs[polarisStateDB](sdb).GetPlugin(),
).SetGasConfig(storetypes.GasConfig{}, storetypes.GasConfig{})
}

// DisableReentrancy sets the state so that execution cannot enter the EVM again.
Expand All @@ -205,5 +187,7 @@ func (p *plugin) disableReentrancy(sdb vm.PolarisStateDB) {
cem.BeginPrecompileExecution(sdb)

// restore ctx gas configs for continuing precompile execution
p.sp.SetGasConfig(p.kvGasConfig, p.transientKVGasConfig)
utils.MustGetAs[state.Plugin](
utils.MustGetAs[polarisStateDB](sdb).GetPlugin(),
).SetGasConfig(p.kvGasConfig, p.transientKVGasConfig)
}
33 changes: 8 additions & 25 deletions cosmos/x/evm/plugins/precompile/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"pkg.berachain.dev/polaris/cosmos/x/evm/plugins/state/events"
"pkg.berachain.dev/polaris/cosmos/x/evm/plugins/state/events/mock"
"pkg.berachain.dev/polaris/eth/common"
ethstate "pkg.berachain.dev/polaris/eth/core/state"
coretypes "pkg.berachain.dev/polaris/eth/core/types"
"pkg.berachain.dev/polaris/eth/core/vm"
"pkg.berachain.dev/polaris/lib/utils"
Expand All @@ -53,7 +54,7 @@ var _ = Describe("plugin", func() {
ctx = ctx.WithEventManager(
events.NewManagerFrom(ctx.EventManager(), mock.NewPrecompileLogFactory()),
)
p = utils.MustGetAs[*plugin](NewPlugin(nil, &mockSP{ctx}))
p = utils.MustGetAs[*plugin](NewPlugin(nil))
e = &mockEVM{nil, ctx, &mockSDB{nil, ctx, 0}}
})

Expand All @@ -68,20 +69,6 @@ var _ = Describe("plugin", func() {
Expect(err).To(MatchError("out of gas"))
})

It("should plug in custom gas configs", func() {
Expect(p.KVGasConfig().DeleteCost).To(Equal(uint64(1000)))
Expect(p.TransientKVGasConfig().DeleteCost).To(Equal(uint64(100)))

p.SetKVGasConfig(storetypes.GasConfig{
DeleteCost: 2,
})
Expect(p.KVGasConfig().DeleteCost).To(Equal(uint64(2)))
p.SetTransientKVGasConfig(storetypes.GasConfig{
DeleteCost: 3,
})
Expect(p.TransientKVGasConfig().DeleteCost).To(Equal(uint64(3)))
})

It("should handle read-only static calls", func() {
ms := utils.MustGetAs[tmock.MultiStore](ctx.MultiStore())
cem := utils.MustGetAs[state.ControllableEventManager](ctx.EventManager())
Expand Down Expand Up @@ -123,16 +110,6 @@ var (
addr2 = common.BytesToAddress([]byte{2})
)

// MOCKS BELOW.

type mockSP struct {
ctx sdk.Context
}

func (msp *mockSP) SetGasConfig(kvg storetypes.GasConfig, tkvg storetypes.GasConfig) {
msp.ctx = msp.ctx.WithKVGasConfig(kvg).WithTransientKVGasConfig(tkvg)
}

type mockEVM struct {
vm.PrecompileEVM
ctx sdk.Context
Expand All @@ -149,6 +126,12 @@ type mockSDB struct {
logs int
}

func (ms *mockSDB) GetPlugin() ethstate.Plugin {
return state.NewPlugin(
nil, nil, nil,
)
}

func (ms *mockSDB) GetContext() context.Context {
return ms.ctx
}
Expand Down
3 changes: 0 additions & 3 deletions cosmos/x/evm/plugins/state/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ var (

// Plugin is the interface that must be implemented by the plugin.
type Plugin interface {
plugins.Base
plugins.HasGenesis
core.StatePlugin
// SetQueryContextFn sets the query context func for the plugin.
Expand Down Expand Up @@ -544,5 +543,3 @@ func (p *plugin) Clone() ethstate.Plugin {
func (p *plugin) SetGasConfig(kvGasConfig, transientKVGasConfig storetypes.GasConfig) {
p.ctx = p.ctx.WithKVGasConfig(kvGasConfig).WithTransientKVGasConfig(transientKVGasConfig)
}

// IsPlugin implements plugins.Base.
2 changes: 0 additions & 2 deletions cosmos/x/evm/plugins/txpool/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (

"github.com/ethereum/go-ethereum/event"

"pkg.berachain.dev/polaris/cosmos/x/evm/plugins"
mempool "pkg.berachain.dev/polaris/cosmos/x/evm/plugins/txpool/mempool"
"pkg.berachain.dev/polaris/eth/core"
coretypes "pkg.berachain.dev/polaris/eth/core/types"
Expand All @@ -41,7 +40,6 @@ var _ Plugin = (*plugin)(nil)

// Plugin defines the required functions of the transaction pool plugin.
type Plugin interface {
plugins.Base
core.TxPoolPlugin
SetNonceRetriever(mempool.NonceRetriever)
SetClientContext(client.Context)
Expand Down
6 changes: 6 additions & 0 deletions eth/core/precompile/default_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ func NewDefaultPlugin() Plugin {
}
}

// Register is a no-op for the default plugin.
func (dp *defaultPlugin) Register(vm.PrecompileContainer) error {
// no-op
return nil
}

// GetPrecompiles implements core.PrecompilePlugin.
func (dp *defaultPlugin) GetPrecompiles(rules *params.Rules) []Registrable {
return GetDefaultPrecompiles(rules)
Expand Down
9 changes: 9 additions & 0 deletions eth/core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ func newStateDBWithJournals(
}
}

// =============================================================================
// Plugin
// =============================================================================

// GetPlugin returns the plugin from statedb.
func (sdb *stateDB) GetPlugin() Plugin {
return sdb.Plugin
}

// =============================================================================
// Snapshot
// =============================================================================
Expand Down

0 comments on commit 15c1356

Please sign in to comment.