imp(evm): stateless custom precompiles (#1272)
* release: v0.17.0 changelog (#1153) * release: v0.17.0 changelog * rm newline * update link * imp(evm): EVM interface * fixes * fix lint * fix lint pt 2 * initial wiring for stateful contracts * Apply suggestions from code review Co-authored-by: Vladislav Varadinov <vladislav.varadinov@gmail.com> * changelog * comments from review * lint Co-authored-by: Vladislav Varadinov <vladislav.varadinov@gmail.com>
This commit is contained in:
parent
67f1e97531
commit
acf15474e7
@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (evm) [\#1272](https://github.com/evmos/ethermint/pull/1272) Implement modular interface for the EVM.
|
||||
* (deps) [\#1159](https://github.com/evmos/ethermint/pull/1159) Bump Geth version to `v1.10.19`.
|
||||
* (deps) [#1167](https://github.com/evmos/ethermint/pull/1167) Bump ibc-go to [`v4.0.0-rc2`](https://github.com/cosmos/ibc-go/releases/tag/v4.0.0-rc2)
|
||||
* (ante) [#1176](https://github.com/evmos/ethermint/pull/1176) Fix invalid tx hashes; Remove `Size_` field and validate `Hash`/`From` fields in ante handler,
|
||||
|
@ -305,7 +305,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
||||
|
||||
// check that caller has enough balance to cover asset transfer for **topmost** call
|
||||
// NOTE: here the gas consumed is from the context with the infinite gas meter
|
||||
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
||||
if coreMsg.Value().Sign() > 0 && !evm.Context().CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInsufficientFunds,
|
||||
"failed to transfer %s from address %s using the EVM block context transfer function",
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/evmos/ethermint/x/evm/statedb"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
evm "github.com/evmos/ethermint/x/evm/vm"
|
||||
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
||||
)
|
||||
|
||||
@ -26,7 +27,7 @@ type EVMKeeper interface {
|
||||
statedb.Keeper
|
||||
DynamicFeeEVMKeeper
|
||||
|
||||
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) *vm.EVM
|
||||
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
|
||||
DeductTxCostsFromUserBalance(
|
||||
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
||||
) (fees sdk.Coins, priority int64, err error)
|
||||
|
@ -106,6 +106,7 @@ import (
|
||||
"github.com/evmos/ethermint/x/evm"
|
||||
evmkeeper "github.com/evmos/ethermint/x/evm/keeper"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
"github.com/evmos/ethermint/x/evm/vm/geth"
|
||||
"github.com/evmos/ethermint/x/feemarket"
|
||||
feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper"
|
||||
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
||||
@ -396,7 +397,7 @@ func NewEthermintApp(
|
||||
app.EvmKeeper = evmkeeper.NewKeeper(
|
||||
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
||||
app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
|
||||
tracer,
|
||||
nil, geth.NewEVM, tracer,
|
||||
)
|
||||
|
||||
// Create IBC Keeper
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
ethermint "github.com/evmos/ethermint/types"
|
||||
"github.com/evmos/ethermint/x/evm/statedb"
|
||||
"github.com/evmos/ethermint/x/evm/types"
|
||||
evm "github.com/evmos/ethermint/x/evm/vm"
|
||||
)
|
||||
|
||||
// Keeper grants access to the EVM module state and implements the go-ethereum StateDB interface.
|
||||
@ -54,14 +55,25 @@ type Keeper struct {
|
||||
|
||||
// EVM Hooks for tx post-processing
|
||||
hooks types.EvmHooks
|
||||
|
||||
// custom stateless precompiled smart contracts
|
||||
customPrecompiles evm.PrecompiledContracts
|
||||
|
||||
// evm constructor function
|
||||
evmConstructor evm.Constructor
|
||||
}
|
||||
|
||||
// NewKeeper generates new evm module keeper
|
||||
func NewKeeper(
|
||||
cdc codec.BinaryCodec,
|
||||
storeKey, transientKey storetypes.StoreKey, paramSpace paramtypes.Subspace,
|
||||
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
|
||||
storeKey, transientKey storetypes.StoreKey,
|
||||
paramSpace paramtypes.Subspace,
|
||||
ak types.AccountKeeper,
|
||||
bankKeeper types.BankKeeper,
|
||||
sk types.StakingKeeper,
|
||||
fmk types.FeeMarketKeeper,
|
||||
customPrecompiles evm.PrecompiledContracts,
|
||||
evmConstructor evm.Constructor,
|
||||
tracer string,
|
||||
) *Keeper {
|
||||
// ensure evm module account is set
|
||||
@ -76,15 +88,17 @@ func NewKeeper(
|
||||
|
||||
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
|
||||
return &Keeper{
|
||||
cdc: cdc,
|
||||
paramSpace: paramSpace,
|
||||
accountKeeper: ak,
|
||||
bankKeeper: bankKeeper,
|
||||
stakingKeeper: sk,
|
||||
feeMarketKeeper: fmk,
|
||||
storeKey: storeKey,
|
||||
transientKey: transientKey,
|
||||
tracer: tracer,
|
||||
cdc: cdc,
|
||||
paramSpace: paramSpace,
|
||||
accountKeeper: ak,
|
||||
bankKeeper: bankKeeper,
|
||||
stakingKeeper: sk,
|
||||
feeMarketKeeper: fmk,
|
||||
storeKey: storeKey,
|
||||
transientKey: transientKey,
|
||||
customPrecompiles: customPrecompiles,
|
||||
evmConstructor: evmConstructor,
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
ethermint "github.com/evmos/ethermint/types"
|
||||
"github.com/evmos/ethermint/x/evm/statedb"
|
||||
"github.com/evmos/ethermint/x/evm/types"
|
||||
evm "github.com/evmos/ethermint/x/evm/vm"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
@ -77,7 +78,7 @@ func (k *Keeper) NewEVM(
|
||||
cfg *types.EVMConfig,
|
||||
tracer vm.EVMLogger,
|
||||
stateDB vm.StateDB,
|
||||
) *vm.EVM {
|
||||
) evm.EVM {
|
||||
blockCtx := vm.BlockContext{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
@ -95,7 +96,7 @@ func (k *Keeper) NewEVM(
|
||||
tracer = k.Tracer(ctx, msg, cfg.ChainConfig)
|
||||
}
|
||||
vmConfig := k.VMConfig(ctx, msg, cfg, tracer)
|
||||
return vm.NewEVM(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig)
|
||||
return k.evmConstructor(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig, k.customPrecompiles)
|
||||
}
|
||||
|
||||
// VMConfig creates an EVM configuration from the debug setting and the extra EIPs enabled on the
|
||||
@ -366,17 +367,19 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context,
|
||||
evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB)
|
||||
|
||||
leftoverGas := msg.Gas()
|
||||
|
||||
// Allow the tracer captures the tx level events, mainly the gas consumption.
|
||||
if evm.Config.Debug {
|
||||
evm.Config.Tracer.CaptureTxStart(leftoverGas)
|
||||
vmCfg := evm.Config()
|
||||
if vmCfg.Debug {
|
||||
vmCfg.Tracer.CaptureTxStart(leftoverGas)
|
||||
defer func() {
|
||||
evm.Config.Tracer.CaptureTxEnd(leftoverGas)
|
||||
vmCfg.Tracer.CaptureTxEnd(leftoverGas)
|
||||
}()
|
||||
}
|
||||
|
||||
sender := vm.AccountRef(msg.From())
|
||||
contractCreation := msg.To() == nil
|
||||
isLondon := cfg.ChainConfig.IsLondon(evm.Context.BlockNumber)
|
||||
isLondon := cfg.ChainConfig.IsLondon(evm.Context().BlockNumber)
|
||||
|
||||
intrinsicGas, err := k.GetEthIntrinsicGas(ctx, msg, cfg.ChainConfig, contractCreation)
|
||||
if err != nil {
|
||||
@ -394,7 +397,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context,
|
||||
// access list preparation is moved from ante handler to here, because it's needed when `ApplyMessage` is called
|
||||
// under contexts where ante handlers are not run, for example `eth_call` and `eth_estimateGas`.
|
||||
if rules := cfg.ChainConfig.Rules(big.NewInt(ctx.BlockHeight()), cfg.ChainConfig.MergeNetsplitBlock != nil); rules.IsBerlin {
|
||||
stateDB.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
||||
stateDB.PrepareAccessList(msg.From(), msg.To(), evm.ActivePrecompiles(rules), msg.AccessList())
|
||||
}
|
||||
|
||||
if contractCreation {
|
||||
|
@ -3,8 +3,19 @@ package statedb
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
)
|
||||
|
||||
// ExtStateDB defines an extension to the interface provided by the go-ethereum
|
||||
// codebase to support additional state transition functionalities. In particular
|
||||
// it supports appending a new entry to the state journal through
|
||||
// AppendJournalEntry so that the state can be reverted after running
|
||||
// stateful precompiled contracts.
|
||||
type ExtStateDB interface {
|
||||
vm.StateDB
|
||||
AppendJournalEntry(JournalEntry)
|
||||
}
|
||||
|
||||
// Keeper provide underlying storage of StateDB
|
||||
type Keeper interface {
|
||||
// Read methods
|
||||
|
@ -24,21 +24,21 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// journalEntry is a modification entry in the state change journal that can be
|
||||
// reverted on demand.
|
||||
type journalEntry interface {
|
||||
// revert undoes the changes introduced by this journal entry.
|
||||
revert(*StateDB)
|
||||
// JournalEntry is a modification entry in the state change journal that can be
|
||||
// Reverted on demand.
|
||||
type JournalEntry interface {
|
||||
// Revert undoes the changes introduced by this journal entry.
|
||||
Revert(*StateDB)
|
||||
|
||||
// dirtied returns the Ethereum address modified by this journal entry.
|
||||
dirtied() *common.Address
|
||||
// Dirtied returns the Ethereum address modified by this journal entry.
|
||||
Dirtied() *common.Address
|
||||
}
|
||||
|
||||
// journal contains the list of state modifications applied since the last state
|
||||
// commit. These are tracked to be able to be reverted in the case of an execution
|
||||
// exception or request for reversal.
|
||||
type journal struct {
|
||||
entries []journalEntry // Current changes tracked by the journal
|
||||
entries []JournalEntry // Current changes tracked by the journal
|
||||
dirties map[common.Address]int // Dirty accounts and the number of changes
|
||||
}
|
||||
|
||||
@ -64,22 +64,22 @@ func (j *journal) sortedDirties() []common.Address {
|
||||
}
|
||||
|
||||
// append inserts a new modification entry to the end of the change journal.
|
||||
func (j *journal) append(entry journalEntry) {
|
||||
func (j *journal) append(entry JournalEntry) {
|
||||
j.entries = append(j.entries, entry)
|
||||
if addr := entry.dirtied(); addr != nil {
|
||||
if addr := entry.Dirtied(); addr != nil {
|
||||
j.dirties[*addr]++
|
||||
}
|
||||
}
|
||||
|
||||
// revert undoes a batch of journalled modifications along with any reverted
|
||||
// Revert undoes a batch of journalled modifications along with any Reverted
|
||||
// dirty handling too.
|
||||
func (j *journal) revert(statedb *StateDB, snapshot int) {
|
||||
func (j *journal) Revert(statedb *StateDB, snapshot int) {
|
||||
for i := len(j.entries) - 1; i >= snapshot; i-- {
|
||||
// Undo the changes made by the operation
|
||||
j.entries[i].revert(statedb)
|
||||
j.entries[i].Revert(statedb)
|
||||
|
||||
// Drop any dirty tracking induced by the change
|
||||
if addr := j.entries[i].dirtied(); addr != nil {
|
||||
if addr := j.entries[i].Dirtied(); addr != nil {
|
||||
if j.dirties[*addr]--; j.dirties[*addr] == 0 {
|
||||
delete(j.dirties, *addr)
|
||||
}
|
||||
@ -141,23 +141,23 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func (ch createObjectChange) revert(s *StateDB) {
|
||||
func (ch createObjectChange) Revert(s *StateDB) {
|
||||
delete(s.stateObjects, *ch.account)
|
||||
}
|
||||
|
||||
func (ch createObjectChange) dirtied() *common.Address {
|
||||
func (ch createObjectChange) Dirtied() *common.Address {
|
||||
return ch.account
|
||||
}
|
||||
|
||||
func (ch resetObjectChange) revert(s *StateDB) {
|
||||
func (ch resetObjectChange) Revert(s *StateDB) {
|
||||
s.setStateObject(ch.prev)
|
||||
}
|
||||
|
||||
func (ch resetObjectChange) dirtied() *common.Address {
|
||||
func (ch resetObjectChange) Dirtied() *common.Address {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch suicideChange) revert(s *StateDB) {
|
||||
func (ch suicideChange) Revert(s *StateDB) {
|
||||
obj := s.getStateObject(*ch.account)
|
||||
if obj != nil {
|
||||
obj.suicided = ch.prev
|
||||
@ -165,59 +165,59 @@ func (ch suicideChange) revert(s *StateDB) {
|
||||
}
|
||||
}
|
||||
|
||||
func (ch suicideChange) dirtied() *common.Address {
|
||||
func (ch suicideChange) Dirtied() *common.Address {
|
||||
return ch.account
|
||||
}
|
||||
|
||||
func (ch balanceChange) revert(s *StateDB) {
|
||||
func (ch balanceChange) Revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setBalance(ch.prev)
|
||||
}
|
||||
|
||||
func (ch balanceChange) dirtied() *common.Address {
|
||||
func (ch balanceChange) Dirtied() *common.Address {
|
||||
return ch.account
|
||||
}
|
||||
|
||||
func (ch nonceChange) revert(s *StateDB) {
|
||||
func (ch nonceChange) Revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setNonce(ch.prev)
|
||||
}
|
||||
|
||||
func (ch nonceChange) dirtied() *common.Address {
|
||||
func (ch nonceChange) Dirtied() *common.Address {
|
||||
return ch.account
|
||||
}
|
||||
|
||||
func (ch codeChange) revert(s *StateDB) {
|
||||
func (ch codeChange) Revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
|
||||
}
|
||||
|
||||
func (ch codeChange) dirtied() *common.Address {
|
||||
func (ch codeChange) Dirtied() *common.Address {
|
||||
return ch.account
|
||||
}
|
||||
|
||||
func (ch storageChange) revert(s *StateDB) {
|
||||
func (ch storageChange) Revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
||||
}
|
||||
|
||||
func (ch storageChange) dirtied() *common.Address {
|
||||
func (ch storageChange) Dirtied() *common.Address {
|
||||
return ch.account
|
||||
}
|
||||
|
||||
func (ch refundChange) revert(s *StateDB) {
|
||||
func (ch refundChange) Revert(s *StateDB) {
|
||||
s.refund = ch.prev
|
||||
}
|
||||
|
||||
func (ch refundChange) dirtied() *common.Address {
|
||||
func (ch refundChange) Dirtied() *common.Address {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch addLogChange) revert(s *StateDB) {
|
||||
func (ch addLogChange) Revert(s *StateDB) {
|
||||
s.logs = s.logs[:len(s.logs)-1]
|
||||
}
|
||||
|
||||
func (ch addLogChange) dirtied() *common.Address {
|
||||
func (ch addLogChange) Dirtied() *common.Address {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch accessListAddAccountChange) revert(s *StateDB) {
|
||||
func (ch accessListAddAccountChange) Revert(s *StateDB) {
|
||||
/*
|
||||
One important invariant here, is that whenever a (addr, slot) is added, if the
|
||||
addr is not already present, the add causes two journal entries:
|
||||
@ -230,14 +230,14 @@ func (ch accessListAddAccountChange) revert(s *StateDB) {
|
||||
s.accessList.DeleteAddress(*ch.address)
|
||||
}
|
||||
|
||||
func (ch accessListAddAccountChange) dirtied() *common.Address {
|
||||
func (ch accessListAddAccountChange) Dirtied() *common.Address {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch accessListAddSlotChange) revert(s *StateDB) {
|
||||
func (ch accessListAddSlotChange) Revert(s *StateDB) {
|
||||
s.accessList.DeleteSlot(*ch.address, *ch.slot)
|
||||
}
|
||||
|
||||
func (ch accessListAddSlotChange) dirtied() *common.Address {
|
||||
func (ch accessListAddSlotChange) Dirtied() *common.Address {
|
||||
return nil
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ func (s *StateDB) RevertToSnapshot(revid int) {
|
||||
snapshot := s.validRevisions[idx].journalIndex
|
||||
|
||||
// Replay the journal to undo changes and remove invalidated snapshots
|
||||
s.journal.revert(s, snapshot)
|
||||
s.journal.Revert(s, snapshot)
|
||||
s.validRevisions = s.validRevisions[:idx]
|
||||
}
|
||||
|
||||
|
79
x/evm/vm/geth/geth.go
Normal file
79
x/evm/vm/geth/geth.go
Normal file
@ -0,0 +1,79 @@
|
||||
package geth
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
evm "github.com/evmos/ethermint/x/evm/vm"
|
||||
)
|
||||
|
||||
var (
|
||||
_ evm.EVM = (*EVM)(nil)
|
||||
_ evm.Constructor = NewEVM
|
||||
)
|
||||
|
||||
// EVM is the wrapper for the go-ethereum EVM.
|
||||
type EVM struct {
|
||||
*vm.EVM
|
||||
}
|
||||
|
||||
// NewEVM defines the constructor function for the go-ethereum (geth) EVM. It uses
|
||||
// the default precompiled contracts and the EVM concrete implementation from
|
||||
// geth.
|
||||
func NewEVM(
|
||||
blockCtx vm.BlockContext,
|
||||
txCtx vm.TxContext,
|
||||
stateDB vm.StateDB,
|
||||
chainConfig *params.ChainConfig,
|
||||
config vm.Config,
|
||||
_ evm.PrecompiledContracts, // unused
|
||||
) evm.EVM {
|
||||
return &EVM{
|
||||
EVM: vm.NewEVM(blockCtx, txCtx, stateDB, chainConfig, config),
|
||||
}
|
||||
}
|
||||
|
||||
// Context returns the EVM's Block Context
|
||||
func (e EVM) Context() vm.BlockContext {
|
||||
return e.EVM.Context
|
||||
}
|
||||
|
||||
// TxContext returns the EVM's Tx Context
|
||||
func (e EVM) TxContext() vm.TxContext {
|
||||
return e.EVM.TxContext
|
||||
}
|
||||
|
||||
// Config returns the configuration options for the EVM.
|
||||
func (e EVM) Config() vm.Config {
|
||||
return e.EVM.Config
|
||||
}
|
||||
|
||||
// Precompile returns the precompiled contract associated with the given address
|
||||
// and the current chain configuration. If the contract cannot be found it returns
|
||||
// nil.
|
||||
func (e EVM) Precompile(addr common.Address) (p vm.PrecompiledContract, found bool) {
|
||||
precompiles := GetPrecompiles(e.ChainConfig(), e.EVM.Context.BlockNumber)
|
||||
p, found = precompiles[addr]
|
||||
return p, found
|
||||
}
|
||||
|
||||
// ActivePrecompiles returns a list of all the active precompiled contract addresses
|
||||
// for the current chain configuration.
|
||||
func (EVM) ActivePrecompiles(rules params.Rules) []common.Address {
|
||||
return vm.ActivePrecompiles(rules)
|
||||
}
|
||||
|
||||
// RunPrecompiledContract runs a stateless precompiled contract and ignores the address and
|
||||
// value arguments. It uses the RunPrecompiledContract function from the geth vm package.
|
||||
func (EVM) RunPrecompiledContract(
|
||||
p evm.StatefulPrecompiledContract,
|
||||
_ common.Address, // address arg is unused
|
||||
input []byte,
|
||||
suppliedGas uint64,
|
||||
_ *big.Int, // value arg is unused
|
||||
) (ret []byte, remainingGas uint64, err error) {
|
||||
return vm.RunPrecompiledContract(p, input, suppliedGas)
|
||||
}
|
27
x/evm/vm/geth/precompiles.go
Normal file
27
x/evm/vm/geth/precompiles.go
Normal file
@ -0,0 +1,27 @@
|
||||
package geth
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
evm "github.com/evmos/ethermint/x/evm/vm"
|
||||
)
|
||||
|
||||
// GetPrecompiles returns all the precompiled contracts defined given the
|
||||
// current chain configuration and block height.
|
||||
func GetPrecompiles(cfg *params.ChainConfig, blockNumber *big.Int) evm.PrecompiledContracts {
|
||||
var precompiles evm.PrecompiledContracts
|
||||
switch {
|
||||
case cfg.IsBerlin(blockNumber):
|
||||
precompiles = vm.PrecompiledContractsBerlin
|
||||
case cfg.IsIstanbul(blockNumber):
|
||||
precompiles = vm.PrecompiledContractsIstanbul
|
||||
case cfg.IsByzantium(blockNumber):
|
||||
precompiles = vm.PrecompiledContractsByzantium
|
||||
default:
|
||||
precompiles = vm.PrecompiledContractsHomestead
|
||||
}
|
||||
return precompiles
|
||||
}
|
66
x/evm/vm/interface.go
Normal file
66
x/evm/vm/interface.go
Normal file
@ -0,0 +1,66 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// PrecompiledContracts defines a map of address -> precompiled contract
|
||||
type PrecompiledContracts map[common.Address]vm.PrecompiledContract
|
||||
|
||||
type StatefulPrecompiledContract interface {
|
||||
vm.PrecompiledContract
|
||||
RunStateful(evm EVM, addr common.Address, input []byte, value *big.Int) (ret []byte, err error)
|
||||
}
|
||||
|
||||
// EVM defines the interface for the Ethereum Virtual Machine used by the EVM module.
|
||||
type EVM interface {
|
||||
Config() vm.Config
|
||||
Context() vm.BlockContext
|
||||
TxContext() vm.TxContext
|
||||
|
||||
Reset(txCtx vm.TxContext, statedb vm.StateDB)
|
||||
Cancel()
|
||||
Cancelled() bool //nolint
|
||||
Interpreter() *vm.EVMInterpreter
|
||||
Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error)
|
||||
CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error)
|
||||
DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)
|
||||
StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)
|
||||
Create(caller vm.ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error)
|
||||
Create2(
|
||||
caller vm.ContractRef,
|
||||
code []byte,
|
||||
gas uint64,
|
||||
endowment *big.Int,
|
||||
salt *uint256.Int) (
|
||||
ret []byte, contractAddr common.Address, leftOverGas uint64, err error,
|
||||
)
|
||||
ChainConfig() *params.ChainConfig
|
||||
|
||||
ActivePrecompiles(rules params.Rules) []common.Address
|
||||
Precompile(addr common.Address) (vm.PrecompiledContract, bool)
|
||||
RunPrecompiledContract(
|
||||
p StatefulPrecompiledContract,
|
||||
addr common.Address,
|
||||
input []byte,
|
||||
suppliedGas uint64,
|
||||
value *big.Int) (
|
||||
ret []byte, remainingGas uint64, err error,
|
||||
)
|
||||
}
|
||||
|
||||
// Constructor defines the function used to instantiate the EVM on
|
||||
// each state transition.
|
||||
type Constructor func(
|
||||
blockCtx vm.BlockContext,
|
||||
txCtx vm.TxContext,
|
||||
stateDB vm.StateDB,
|
||||
chainConfig *params.ChainConfig,
|
||||
config vm.Config,
|
||||
customPrecompiles PrecompiledContracts,
|
||||
) EVM
|
Loading…
Reference in New Issue
Block a user