Sync from fork #74
@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
|
|
||||||
### State Machine Breaking
|
### 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) [\#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)
|
* (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,
|
* (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
|
// 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
|
// 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(
|
return ctx, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrInsufficientFunds,
|
sdkerrors.ErrInsufficientFunds,
|
||||||
"failed to transfer %s from address %s using the EVM block context transfer function",
|
"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/ethereum/go-ethereum/params"
|
||||||
"github.com/evmos/ethermint/x/evm/statedb"
|
"github.com/evmos/ethermint/x/evm/statedb"
|
||||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
|
evm "github.com/evmos/ethermint/x/evm/vm"
|
||||||
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ type EVMKeeper interface {
|
|||||||
statedb.Keeper
|
statedb.Keeper
|
||||||
DynamicFeeEVMKeeper
|
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(
|
DeductTxCostsFromUserBalance(
|
||||||
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
||||||
) (fees sdk.Coins, priority int64, err error)
|
) (fees sdk.Coins, priority int64, err error)
|
||||||
|
@ -106,6 +106,7 @@ import (
|
|||||||
"github.com/evmos/ethermint/x/evm"
|
"github.com/evmos/ethermint/x/evm"
|
||||||
evmkeeper "github.com/evmos/ethermint/x/evm/keeper"
|
evmkeeper "github.com/evmos/ethermint/x/evm/keeper"
|
||||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
|
"github.com/evmos/ethermint/x/evm/vm/geth"
|
||||||
"github.com/evmos/ethermint/x/feemarket"
|
"github.com/evmos/ethermint/x/feemarket"
|
||||||
feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper"
|
feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper"
|
||||||
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
||||||
@ -396,7 +397,7 @@ func NewEthermintApp(
|
|||||||
app.EvmKeeper = evmkeeper.NewKeeper(
|
app.EvmKeeper = evmkeeper.NewKeeper(
|
||||||
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
||||||
app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
|
app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
|
||||||
tracer,
|
nil, geth.NewEVM, tracer,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create IBC Keeper
|
// Create IBC Keeper
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
ethermint "github.com/evmos/ethermint/types"
|
ethermint "github.com/evmos/ethermint/types"
|
||||||
"github.com/evmos/ethermint/x/evm/statedb"
|
"github.com/evmos/ethermint/x/evm/statedb"
|
||||||
"github.com/evmos/ethermint/x/evm/types"
|
"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.
|
// 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
|
// EVM Hooks for tx post-processing
|
||||||
hooks types.EvmHooks
|
hooks types.EvmHooks
|
||||||
|
|
||||||
|
// custom stateless precompiled smart contracts
|
||||||
|
customPrecompiles evm.PrecompiledContracts
|
||||||
|
|
||||||
|
// evm constructor function
|
||||||
|
evmConstructor evm.Constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeeper generates new evm module keeper
|
// NewKeeper generates new evm module keeper
|
||||||
func NewKeeper(
|
func NewKeeper(
|
||||||
cdc codec.BinaryCodec,
|
cdc codec.BinaryCodec,
|
||||||
storeKey, transientKey storetypes.StoreKey, paramSpace paramtypes.Subspace,
|
storeKey, transientKey storetypes.StoreKey,
|
||||||
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
|
paramSpace paramtypes.Subspace,
|
||||||
|
ak types.AccountKeeper,
|
||||||
|
bankKeeper types.BankKeeper,
|
||||||
|
sk types.StakingKeeper,
|
||||||
fmk types.FeeMarketKeeper,
|
fmk types.FeeMarketKeeper,
|
||||||
|
customPrecompiles evm.PrecompiledContracts,
|
||||||
|
evmConstructor evm.Constructor,
|
||||||
tracer string,
|
tracer string,
|
||||||
) *Keeper {
|
) *Keeper {
|
||||||
// ensure evm module account is set
|
// 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
|
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
|
||||||
return &Keeper{
|
return &Keeper{
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
paramSpace: paramSpace,
|
paramSpace: paramSpace,
|
||||||
accountKeeper: ak,
|
accountKeeper: ak,
|
||||||
bankKeeper: bankKeeper,
|
bankKeeper: bankKeeper,
|
||||||
stakingKeeper: sk,
|
stakingKeeper: sk,
|
||||||
feeMarketKeeper: fmk,
|
feeMarketKeeper: fmk,
|
||||||
storeKey: storeKey,
|
storeKey: storeKey,
|
||||||
transientKey: transientKey,
|
transientKey: transientKey,
|
||||||
tracer: tracer,
|
customPrecompiles: customPrecompiles,
|
||||||
|
evmConstructor: evmConstructor,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
ethermint "github.com/evmos/ethermint/types"
|
ethermint "github.com/evmos/ethermint/types"
|
||||||
"github.com/evmos/ethermint/x/evm/statedb"
|
"github.com/evmos/ethermint/x/evm/statedb"
|
||||||
"github.com/evmos/ethermint/x/evm/types"
|
"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/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
@ -77,7 +78,7 @@ func (k *Keeper) NewEVM(
|
|||||||
cfg *types.EVMConfig,
|
cfg *types.EVMConfig,
|
||||||
tracer vm.EVMLogger,
|
tracer vm.EVMLogger,
|
||||||
stateDB vm.StateDB,
|
stateDB vm.StateDB,
|
||||||
) *vm.EVM {
|
) evm.EVM {
|
||||||
blockCtx := vm.BlockContext{
|
blockCtx := vm.BlockContext{
|
||||||
CanTransfer: core.CanTransfer,
|
CanTransfer: core.CanTransfer,
|
||||||
Transfer: core.Transfer,
|
Transfer: core.Transfer,
|
||||||
@ -95,7 +96,7 @@ func (k *Keeper) NewEVM(
|
|||||||
tracer = k.Tracer(ctx, msg, cfg.ChainConfig)
|
tracer = k.Tracer(ctx, msg, cfg.ChainConfig)
|
||||||
}
|
}
|
||||||
vmConfig := k.VMConfig(ctx, msg, cfg, tracer)
|
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
|
// 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)
|
evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB)
|
||||||
|
|
||||||
leftoverGas := msg.Gas()
|
leftoverGas := msg.Gas()
|
||||||
|
|
||||||
// Allow the tracer captures the tx level events, mainly the gas consumption.
|
// Allow the tracer captures the tx level events, mainly the gas consumption.
|
||||||
if evm.Config.Debug {
|
vmCfg := evm.Config()
|
||||||
evm.Config.Tracer.CaptureTxStart(leftoverGas)
|
if vmCfg.Debug {
|
||||||
|
vmCfg.Tracer.CaptureTxStart(leftoverGas)
|
||||||
defer func() {
|
defer func() {
|
||||||
evm.Config.Tracer.CaptureTxEnd(leftoverGas)
|
vmCfg.Tracer.CaptureTxEnd(leftoverGas)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
sender := vm.AccountRef(msg.From())
|
sender := vm.AccountRef(msg.From())
|
||||||
contractCreation := msg.To() == nil
|
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)
|
intrinsicGas, err := k.GetEthIntrinsicGas(ctx, msg, cfg.ChainConfig, contractCreation)
|
||||||
if err != nil {
|
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
|
// 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`.
|
// 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 {
|
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 {
|
if contractCreation {
|
||||||
|
@ -3,8 +3,19 @@ package statedb
|
|||||||
import (
|
import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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
|
// Keeper provide underlying storage of StateDB
|
||||||
type Keeper interface {
|
type Keeper interface {
|
||||||
// Read methods
|
// Read methods
|
||||||
|
@ -24,21 +24,21 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// journalEntry is a modification entry in the state change journal that can be
|
// JournalEntry is a modification entry in the state change journal that can be
|
||||||
// reverted on demand.
|
// Reverted on demand.
|
||||||
type journalEntry interface {
|
type JournalEntry interface {
|
||||||
// revert undoes the changes introduced by this journal entry.
|
// Revert undoes the changes introduced by this journal entry.
|
||||||
revert(*StateDB)
|
Revert(*StateDB)
|
||||||
|
|
||||||
// dirtied returns the Ethereum address modified by this journal entry.
|
// Dirtied returns the Ethereum address modified by this journal entry.
|
||||||
dirtied() *common.Address
|
Dirtied() *common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// journal contains the list of state modifications applied since the last state
|
// 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
|
// commit. These are tracked to be able to be reverted in the case of an execution
|
||||||
// exception or request for reversal.
|
// exception or request for reversal.
|
||||||
type journal struct {
|
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
|
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.
|
// 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)
|
j.entries = append(j.entries, entry)
|
||||||
if addr := entry.dirtied(); addr != nil {
|
if addr := entry.Dirtied(); addr != nil {
|
||||||
j.dirties[*addr]++
|
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.
|
// 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-- {
|
for i := len(j.entries) - 1; i >= snapshot; i-- {
|
||||||
// Undo the changes made by the operation
|
// 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
|
// 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 {
|
if j.dirties[*addr]--; j.dirties[*addr] == 0 {
|
||||||
delete(j.dirties, *addr)
|
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)
|
delete(s.stateObjects, *ch.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch createObjectChange) dirtied() *common.Address {
|
func (ch createObjectChange) Dirtied() *common.Address {
|
||||||
return ch.account
|
return ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch resetObjectChange) revert(s *StateDB) {
|
func (ch resetObjectChange) Revert(s *StateDB) {
|
||||||
s.setStateObject(ch.prev)
|
s.setStateObject(ch.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch resetObjectChange) dirtied() *common.Address {
|
func (ch resetObjectChange) Dirtied() *common.Address {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch suicideChange) revert(s *StateDB) {
|
func (ch suicideChange) Revert(s *StateDB) {
|
||||||
obj := s.getStateObject(*ch.account)
|
obj := s.getStateObject(*ch.account)
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
obj.suicided = ch.prev
|
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
|
return ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch balanceChange) revert(s *StateDB) {
|
func (ch balanceChange) Revert(s *StateDB) {
|
||||||
s.getStateObject(*ch.account).setBalance(ch.prev)
|
s.getStateObject(*ch.account).setBalance(ch.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch balanceChange) dirtied() *common.Address {
|
func (ch balanceChange) Dirtied() *common.Address {
|
||||||
return ch.account
|
return ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch nonceChange) revert(s *StateDB) {
|
func (ch nonceChange) Revert(s *StateDB) {
|
||||||
s.getStateObject(*ch.account).setNonce(ch.prev)
|
s.getStateObject(*ch.account).setNonce(ch.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch nonceChange) dirtied() *common.Address {
|
func (ch nonceChange) Dirtied() *common.Address {
|
||||||
return ch.account
|
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)
|
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
|
return ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch storageChange) revert(s *StateDB) {
|
func (ch storageChange) Revert(s *StateDB) {
|
||||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch storageChange) dirtied() *common.Address {
|
func (ch storageChange) Dirtied() *common.Address {
|
||||||
return ch.account
|
return ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch refundChange) revert(s *StateDB) {
|
func (ch refundChange) Revert(s *StateDB) {
|
||||||
s.refund = ch.prev
|
s.refund = ch.prev
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch refundChange) dirtied() *common.Address {
|
func (ch refundChange) Dirtied() *common.Address {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch addLogChange) revert(s *StateDB) {
|
func (ch addLogChange) Revert(s *StateDB) {
|
||||||
s.logs = s.logs[:len(s.logs)-1]
|
s.logs = s.logs[:len(s.logs)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch addLogChange) dirtied() *common.Address {
|
func (ch addLogChange) Dirtied() *common.Address {
|
||||||
return nil
|
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
|
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:
|
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)
|
s.accessList.DeleteAddress(*ch.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch accessListAddAccountChange) dirtied() *common.Address {
|
func (ch accessListAddAccountChange) Dirtied() *common.Address {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch accessListAddSlotChange) revert(s *StateDB) {
|
func (ch accessListAddSlotChange) Revert(s *StateDB) {
|
||||||
s.accessList.DeleteSlot(*ch.address, *ch.slot)
|
s.accessList.DeleteSlot(*ch.address, *ch.slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch accessListAddSlotChange) dirtied() *common.Address {
|
func (ch accessListAddSlotChange) Dirtied() *common.Address {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ func (s *StateDB) RevertToSnapshot(revid int) {
|
|||||||
snapshot := s.validRevisions[idx].journalIndex
|
snapshot := s.validRevisions[idx].journalIndex
|
||||||
|
|
||||||
// Replay the journal to undo changes and remove invalidated snapshots
|
// 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]
|
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