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

Commit

Permalink
feat(precompile): Default Precompile Plugin (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
calbera authored Feb 19, 2023
1 parent f74b4cd commit efc8910
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 21 deletions.
9 changes: 2 additions & 7 deletions eth/core/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ package core

import (
"github.com/berachain/stargazer/eth/common"
"github.com/berachain/stargazer/eth/core/precompile"
"github.com/berachain/stargazer/eth/core/state"
"github.com/berachain/stargazer/eth/core/types"
"github.com/berachain/stargazer/eth/core/vm"
"github.com/berachain/stargazer/eth/params"
libtypes "github.com/berachain/stargazer/lib/types"
)
Expand Down Expand Up @@ -117,10 +117,5 @@ type (
// `PrecompilePlugin` defines the methods that the chain running Stargazer EVM should implement
// in order to support running their own stateful precompiled contracts. Implementing this
// plugin is optional.
PrecompilePlugin interface {
// `Reset` sets the native precompile context before beginning a state transition.
libtypes.Resettable
// `PrecompileManager` is the manager for the native precompiles.
vm.PrecompileManager
}
PrecompilePlugin = precompile.Plugin
)
68 changes: 68 additions & 0 deletions eth/core/precompile/default_plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: BUSL-1.1
//
// Copyright (C) 2023, Berachain Foundation. All rights reserved.
// Use of this software is govered by the Business Source License included
// in the LICENSE file of this repository and at www.mariadb.com/bsl11.
//
// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY
// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER
// VERSIONS OF THE LICENSED WORK.
//
// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF
// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF
// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE).
//
// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
// TITLE.

package precompile

import (
"context"
"math/big"

"github.com/berachain/stargazer/eth/common"
"github.com/berachain/stargazer/eth/core/vm"
"github.com/berachain/stargazer/lib/registry"
libtypes "github.com/berachain/stargazer/lib/types"
)

// `defaultPlugin` is the default precompile plugin, should any chain running Stargazer EVM not
// implement their own precompile plugin. Notably, this plugin can only run the default stateless
// precompiles provided by Go-Ethereum.
type defaultPlugin struct {
libtypes.Registry[common.Address, vm.PrecompileContainer]
}

// `NewDefaultPlugin` returns a new instance of the default precompile plugin.
func NewDefaultPlugin() Plugin {
return &defaultPlugin{
Registry: registry.NewMap[common.Address, vm.PrecompileContainer](),
}
}

// `Reset` implements `core.PrecompilePlugin`.
func (dp *defaultPlugin) Reset(ctx context.Context) {
// no-op
}

// `Run` supports executing stateless precompiles with the background context.
//
// `Run` implements `core.PrecompilePlugin`.
func (dp *defaultPlugin) Run(
sdb vm.GethStateDB, pc vm.PrecompileContainer, input []byte,
caller common.Address, value *big.Int, suppliedGas uint64, readonly bool,
) ([]byte, uint64, error) {
gasCost := pc.RequiredGas(input)
if gasCost > suppliedGas {
return nil, 0, vm.ErrOutOfGas
}

suppliedGas -= gasCost
output, err := pc.Run(context.Background(), input, caller, value, readonly)

return output, suppliedGas, err
}
62 changes: 62 additions & 0 deletions eth/core/precompile/default_plugin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: BUSL-1.1
//
// Copyright (C) 2023, Berachain Foundation. All rights reserved.
// Use of this software is govered by the Business Source License included
// in the LICENSE file of this repository and at www.mariadb.com/bsl11.
//
// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY
// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER
// VERSIONS OF THE LICENSED WORK.
//
// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF
// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF
// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE).
//
// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
// TITLE.

package precompile_test

import (
"context"

"github.com/berachain/stargazer/eth/common"
"github.com/berachain/stargazer/eth/core/precompile"
"github.com/ethereum/go-ethereum/core/vm"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

//nolint:lll // test data.
const precompInput = `a8b53bdf3306a35a7103ab5504a0c9b492295564b6202b1942a84ef300107281000000000000000000000000000000000000000000000000000000000000001b307835653165303366353363653138623737326363623030393366663731663366353366356337356237346463623331613835616138623838393262346538621122334455667788991011121314151617181920212223242526272829303132`

var _ = Describe("Default Plugin", func() {
var dp precompile.Plugin

BeforeEach(func() {
dp = precompile.NewDefaultPlugin()
})

It("should reset", func() {
Expect(func() { dp.Reset(context.Background()) }).ToNot(Panic())
})

When("running a stateless contract", func() {
It("should run out of gas", func() {
ret, remainingGas, err := dp.Run(nil, &mockStateless{&mockBase{}}, nil, common.Address{}, nil, 5, false)
Expect(ret).To(BeNil())
Expect(remainingGas).To(Equal(uint64(0)))
Expect(err.Error()).To(Equal("out of gas"))
})

It("should run a geth contract", func() {
pc := vm.PrecompiledContractsHomestead[common.BytesToAddress([]byte{1})]
_, remainingGas, err := dp.Run(nil, pc, []byte(precompInput), common.Address{}, nil, 3000, true)
Expect(remainingGas).To(Equal(uint64(0)))
Expect(err).To(BeNil())
})
})
})
6 changes: 6 additions & 0 deletions eth/core/precompile/factories.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ const (
dynamicContainerName = `DynamicContainerImpl`
)

// `AbstractFactory` is an interface that all precompile container factories must adhere to.
type AbstractFactory interface {
// `Build` builds and returns the precompile container for the type of container/factory.
Build(vm.RegistrablePrecompile) (vm.PrecompileContainer, error)
}

// Compile-time assertions to ensure these container factories adhere to `AbstractFactory`.
var (
_ AbstractFactory = (*StatelessFactory)(nil)
Expand Down
2 changes: 1 addition & 1 deletion eth/core/precompile/factories_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ type mockStateless struct {
}

func (ms *mockStateless) RequiredGas(input []byte) uint64 {
return 0
return 10
}

func (ms *mockStateless) Run(
Expand Down
13 changes: 9 additions & 4 deletions eth/core/precompile/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ package precompile
import (
"github.com/berachain/stargazer/eth/core/vm"
"github.com/berachain/stargazer/eth/types/abi"
libtypes "github.com/berachain/stargazer/lib/types"
)

type (
// `AbstractFactory` is an interface that all precompile container factories must adhere to.
AbstractFactory interface {
// `Build` builds and returns the precompile container for the type of container/factory.
Build(vm.RegistrablePrecompile) (vm.PrecompileContainer, error)
// `Plugin` defines the methods that the chain running Stargazer EVM should implement in order
// to support running their own stateful precompiled contracts. Implementing this plugin is
// optional.
Plugin interface {
// `Reset` sets the native precompile context before beginning a state transition.
libtypes.Resettable
// `PrecompileManager` is the manager for the native precompiles.
vm.PrecompileManager
}
)

Expand Down
2 changes: 1 addition & 1 deletion eth/core/precompile/precompile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
// TITLE.

package precompile
package precompile_test

import (
"testing"
Expand Down
7 changes: 7 additions & 0 deletions eth/core/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"fmt"
"sync"

"github.com/berachain/stargazer/eth/core/precompile"
"github.com/berachain/stargazer/eth/core/types"
"github.com/berachain/stargazer/eth/core/vm"
"github.com/berachain/stargazer/eth/crypto"
Expand Down Expand Up @@ -80,6 +81,12 @@ func NewStateProcessor(
statedb: statedb,
commit: commit,
}

if sp.pp == nil {
sp.pp = precompile.NewDefaultPlugin()
}
// TODO: register Geth default stateless precompile contracts.

return sp
}

Expand Down
36 changes: 31 additions & 5 deletions eth/core/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,39 @@ var (
}
)

var _ = Describe("StateProcessor no precompile plugin", func() {
It("should use the default plugin if none is provided", func() {
host := mock.NewMockHost()
bp := mock.NewBlockPluginMock()
gp := mock.NewGasPluginMock()
gp.SetBlockGasLimit(1000000)
bp.GetStargazerHeaderAtHeightFunc = func(height int64) *types.StargazerHeader {
header := types.NewEmptyStargazerHeader()
header.GasLimit = 1000000
header.Number = new(big.Int)
header.Difficulty = new(big.Int)
return header
}
host.GetBlockPluginFunc = func() core.BlockPlugin {
return bp
}
host.GetGasPluginFunc = func() core.GasPlugin {
return gp
}
host.GetConfigurationPluginFunc = func() core.ConfigurationPlugin {
return mock.NewConfigurationPluginMock()
}
host.GetPrecompilePluginFunc = func() core.PrecompilePlugin {
return nil
}
sp := core.NewStateProcessor(host, vmmock.NewEmptyStateDB(), vm.Config{}, true)
Expect(func() { sp.Prepare(context.Background(), 0) }).ToNot(Panic())
})
})

var _ = Describe("StateProcessor", func() {
var (
// evm *vmmock.StargazerEVMMock
sdb *vmmock.StargazerStateDBMock
// msg *mock.MessageMock
sdb *vmmock.StargazerStateDBMock
host *mock.StargazerHostChainMock
bp *mock.BlockPluginMock
gp *mock.GasPluginMock
Expand All @@ -68,9 +96,7 @@ var _ = Describe("StateProcessor", func() {
)

BeforeEach(func() {
// evm = vmmock.NewStargazerEVM()
sdb = vmmock.NewEmptyStateDB()
// msg = mock.NewEmptyMessage()
host = mock.NewMockHost()
bp = mock.NewBlockPluginMock()
gp = mock.NewGasPluginMock()
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/berachain/stargazer
go 1.19

// Required for supporting stateful precompiled contracts.
replace github.com/ethereum/go-ethereum => github.com/berachain/go-ethereum v0.0.0-20230218212458-98f7bdb37121
replace github.com/ethereum/go-ethereum => github.com/berachain/go-ethereum v0.0.0-20230219215613-52883710e99d

replace github.com/docker/docker => github.com/docker/docker v20.10.3-0.20221013203545-33ab36d6b304+incompatible // 22.06 branch

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/berachain/go-ethereum v0.0.0-20230218212458-98f7bdb37121 h1:TRngvPGUPcJotVumYnvTqSPaYxxRtsqhNrPg/CILxxM=
github.com/berachain/go-ethereum v0.0.0-20230218212458-98f7bdb37121/go.mod h1:DuefStAgaxoaYGLR0FueVcVbehmn5n9QUcVrMCuOvuc=
github.com/berachain/go-ethereum v0.0.0-20230219215613-52883710e99d h1:aDzdDISNsHFc8McCxw3ZGiTWRKDw181kvuozapCEhJs=
github.com/berachain/go-ethereum v0.0.0-20230219215613-52883710e99d/go.mod h1:DuefStAgaxoaYGLR0FueVcVbehmn5n9QUcVrMCuOvuc=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
Expand Down

0 comments on commit efc8910

Please sign in to comment.