upgrade to ethermint v0.21.0 #99
@ -294,12 +294,13 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
|
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
|
||||||
cfg := &evmtypes.EVMConfig{
|
cfg := &statedb.EVMConfig{
|
||||||
ChainConfig: ethCfg,
|
ChainConfig: ethCfg,
|
||||||
Params: params,
|
Params: params,
|
||||||
CoinBase: common.Address{},
|
CoinBase: common.Address{},
|
||||||
BaseFee: baseFee,
|
BaseFee: baseFee,
|
||||||
}
|
}
|
||||||
|
|
||||||
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
|
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
|
||||||
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)
|
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)
|
||||||
|
|
||||||
|
@ -20,10 +20,12 @@ import (
|
|||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
tx "github.com/cosmos/cosmos-sdk/types/tx"
|
tx "github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"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"
|
evm "github.com/evmos/ethermint/x/evm/vm"
|
||||||
@ -42,7 +44,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) evm.EVM
|
NewEVM(ctx sdk.Context, msg core.Message, cfg *statedb.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
|
||||||
DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error
|
DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error
|
||||||
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
||||||
ResetTransientGasUsed(ctx sdk.Context)
|
ResetTransientGasUsed(ctx sdk.Context)
|
||||||
|
79
x/evm/keeper/config.go
Normal file
79
x/evm/keeper/config.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Copyright 2021 Evmos Foundation
|
||||||
|
// This file is part of Evmos' Ethermint library.
|
||||||
|
//
|
||||||
|
// The Ethermint library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The Ethermint library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
|
||||||
|
package keeper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/evmos/ethermint/x/evm/statedb"
|
||||||
|
"github.com/evmos/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EVMConfig creates the EVMConfig based on current state
|
||||||
|
func (k *Keeper) EVMConfig(ctx sdk.Context, proposerAddress sdk.ConsAddress, chainID *big.Int) (*statedb.EVMConfig, error) {
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
||||||
|
|
||||||
|
// get the coinbase address from the block proposer
|
||||||
|
coinbase, err := k.GetCoinbaseAddress(ctx, proposerAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errorsmod.Wrap(err, "failed to obtain coinbase address")
|
||||||
|
}
|
||||||
|
|
||||||
|
baseFee := k.GetBaseFee(ctx, ethCfg)
|
||||||
|
return &statedb.EVMConfig{
|
||||||
|
Params: params,
|
||||||
|
ChainConfig: ethCfg,
|
||||||
|
CoinBase: coinbase,
|
||||||
|
BaseFee: baseFee,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TxConfig loads `TxConfig` from current transient storage
|
||||||
|
func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig {
|
||||||
|
return statedb.NewTxConfig(
|
||||||
|
common.BytesToHash(ctx.HeaderHash()), // BlockHash
|
||||||
|
txHash, // TxHash
|
||||||
|
uint(k.GetTxIndexTransient(ctx)), // TxIndex
|
||||||
|
uint(k.GetLogSizeTransient(ctx)), // LogIndex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VMConfig creates an EVM configuration from the debug setting and the extra EIPs enabled on the
|
||||||
|
// module parameters. The config generated uses the default JumpTable from the EVM.
|
||||||
|
func (k Keeper) VMConfig(ctx sdk.Context, msg core.Message, cfg *statedb.EVMConfig, tracer vm.EVMLogger) vm.Config {
|
||||||
|
noBaseFee := true
|
||||||
|
if types.IsLondon(cfg.ChainConfig, ctx.BlockHeight()) {
|
||||||
|
noBaseFee = k.feeMarketKeeper.GetParams(ctx).NoBaseFee
|
||||||
|
}
|
||||||
|
|
||||||
|
var debug bool
|
||||||
|
if _, ok := tracer.(types.NoOpTracer); !ok {
|
||||||
|
debug = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm.Config{
|
||||||
|
Debug: debug,
|
||||||
|
Tracer: tracer,
|
||||||
|
NoBaseFee: noBaseFee,
|
||||||
|
ExtraEips: cfg.Params.EIPs(),
|
||||||
|
}
|
||||||
|
}
|
90
x/evm/keeper/gas.go
Normal file
90
x/evm/keeper/gas.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2021 Evmos Foundation
|
||||||
|
// This file is part of Evmos' Ethermint library.
|
||||||
|
//
|
||||||
|
// The Ethermint library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The Ethermint library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
|
||||||
|
package keeper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
|
sdkmath "cosmossdk.io/math"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
|
|
||||||
|
"github.com/evmos/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEthIntrinsicGas returns the intrinsic gas cost for the transaction
|
||||||
|
func (k *Keeper) GetEthIntrinsicGas(ctx sdk.Context, msg core.Message, cfg *params.ChainConfig, isContractCreation bool) (uint64, error) {
|
||||||
|
height := big.NewInt(ctx.BlockHeight())
|
||||||
|
homestead := cfg.IsHomestead(height)
|
||||||
|
istanbul := cfg.IsIstanbul(height)
|
||||||
|
|
||||||
|
return core.IntrinsicGas(msg.Data(), msg.AccessList(), isContractCreation, homestead, istanbul)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefundGas transfers the leftover gas to the sender of the message, caped to half of the total gas
|
||||||
|
// consumed in the transaction. Additionally, the function sets the total gas consumed to the value
|
||||||
|
// returned by the EVM execution, thus ignoring the previous intrinsic gas consumed during in the
|
||||||
|
// AnteHandler.
|
||||||
|
func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64, denom string) error {
|
||||||
|
// Return EVM tokens for remaining gas, exchanged at the original rate.
|
||||||
|
remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice())
|
||||||
|
|
||||||
|
switch remaining.Sign() {
|
||||||
|
case -1:
|
||||||
|
// negative refund errors
|
||||||
|
return errorsmod.Wrapf(types.ErrInvalidRefund, "refunded amount value cannot be negative %d", remaining.Int64())
|
||||||
|
case 1:
|
||||||
|
// positive amount refund
|
||||||
|
refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(remaining))}
|
||||||
|
|
||||||
|
// refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees
|
||||||
|
|
||||||
|
err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins)
|
||||||
|
if err != nil {
|
||||||
|
err = errorsmod.Wrapf(errortypes.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error())
|
||||||
|
return errorsmod.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// no refund, consume gas and update the tx gas meter
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetGasMeterAndConsumeGas reset first the gas meter consumed value to zero and set it back to the new value
|
||||||
|
// 'gasUsed'
|
||||||
|
func (k *Keeper) ResetGasMeterAndConsumeGas(ctx sdk.Context, gasUsed uint64) {
|
||||||
|
// reset the gas count
|
||||||
|
ctx.GasMeter().RefundGas(ctx.GasMeter().GasConsumed(), "reset the gas count")
|
||||||
|
ctx.GasMeter().ConsumeGas(gasUsed, "apply evm transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GasToRefund calculates the amount of gas the state machine should refund to the sender. It is
|
||||||
|
// capped by the refund quotient value.
|
||||||
|
// Note: do not pass 0 to refundQuotient
|
||||||
|
func GasToRefund(availableRefund, gasConsumed, refundQuotient uint64) uint64 {
|
||||||
|
// Apply refund counter
|
||||||
|
refund := gasConsumed / refundQuotient
|
||||||
|
if refund > availableRefund {
|
||||||
|
return availableRefund
|
||||||
|
}
|
||||||
|
return refund
|
||||||
|
}
|
@ -532,7 +532,7 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest)
|
|||||||
// traceTx do trace on one transaction, it returns a tuple: (traceResult, nextLogIndex, error).
|
// traceTx do trace on one transaction, it returns a tuple: (traceResult, nextLogIndex, error).
|
||||||
func (k *Keeper) traceTx(
|
func (k *Keeper) traceTx(
|
||||||
ctx sdk.Context,
|
ctx sdk.Context,
|
||||||
cfg *types.EVMConfig,
|
cfg *statedb.EVMConfig,
|
||||||
txConfig statedb.TxConfig,
|
txConfig statedb.TxConfig,
|
||||||
signer ethtypes.Signer,
|
signer ethtypes.Signer,
|
||||||
tx *ethtypes.Transaction,
|
tx *ethtypes.Transaction,
|
||||||
|
@ -18,15 +18,10 @@ package keeper
|
|||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
sdkmath "cosmossdk.io/math"
|
|
||||||
|
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
errorsmod "cosmossdk.io/errors"
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
||||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
|
||||||
|
|
||||||
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"
|
||||||
@ -41,48 +36,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GasToRefund calculates the amount of gas the state machine should refund to the sender. It is
|
|
||||||
// capped by the refund quotient value.
|
|
||||||
// Note: do not pass 0 to refundQuotient
|
|
||||||
func GasToRefund(availableRefund, gasConsumed, refundQuotient uint64) uint64 {
|
|
||||||
// Apply refund counter
|
|
||||||
refund := gasConsumed / refundQuotient
|
|
||||||
if refund > availableRefund {
|
|
||||||
return availableRefund
|
|
||||||
}
|
|
||||||
return refund
|
|
||||||
}
|
|
||||||
|
|
||||||
// EVMConfig creates the EVMConfig based on current state
|
|
||||||
func (k *Keeper) EVMConfig(ctx sdk.Context, proposerAddress sdk.ConsAddress, chainID *big.Int) (*types.EVMConfig, error) {
|
|
||||||
params := k.GetParams(ctx)
|
|
||||||
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
|
||||||
|
|
||||||
// get the coinbase address from the block proposer
|
|
||||||
coinbase, err := k.GetCoinbaseAddress(ctx, proposerAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errorsmod.Wrap(err, "failed to obtain coinbase address")
|
|
||||||
}
|
|
||||||
|
|
||||||
baseFee := k.GetBaseFee(ctx, ethCfg)
|
|
||||||
return &types.EVMConfig{
|
|
||||||
Params: params,
|
|
||||||
ChainConfig: ethCfg,
|
|
||||||
CoinBase: coinbase,
|
|
||||||
BaseFee: baseFee,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TxConfig loads `TxConfig` from current transient storage
|
|
||||||
func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig {
|
|
||||||
return statedb.NewTxConfig(
|
|
||||||
common.BytesToHash(ctx.HeaderHash()), // BlockHash
|
|
||||||
txHash, // TxHash
|
|
||||||
uint(k.GetTxIndexTransient(ctx)), // TxIndex
|
|
||||||
uint(k.GetLogSizeTransient(ctx)), // LogIndex
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEVM generates a go-ethereum VM from the provided Message fields and the chain parameters
|
// NewEVM generates a go-ethereum VM from the provided Message fields and the chain parameters
|
||||||
// (ChainConfig and module Params). It additionally sets the validator operator address as the
|
// (ChainConfig and module Params). It additionally sets the validator operator address as the
|
||||||
// coinbase address to make it available for the COINBASE opcode, even though there is no
|
// coinbase address to make it available for the COINBASE opcode, even though there is no
|
||||||
@ -95,7 +48,7 @@ func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig
|
|||||||
func (k *Keeper) NewEVM(
|
func (k *Keeper) NewEVM(
|
||||||
ctx sdk.Context,
|
ctx sdk.Context,
|
||||||
msg core.Message,
|
msg core.Message,
|
||||||
cfg *types.EVMConfig,
|
cfg *statedb.EVMConfig,
|
||||||
tracer vm.EVMLogger,
|
tracer vm.EVMLogger,
|
||||||
stateDB vm.StateDB,
|
stateDB vm.StateDB,
|
||||||
) evm.EVM {
|
) evm.EVM {
|
||||||
@ -120,27 +73,6 @@ func (k *Keeper) NewEVM(
|
|||||||
return k.evmConstructor(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig, k.customPrecompiles)
|
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
|
|
||||||
// module parameters. The config generated uses the default JumpTable from the EVM.
|
|
||||||
func (k Keeper) VMConfig(ctx sdk.Context, msg core.Message, cfg *types.EVMConfig, tracer vm.EVMLogger) vm.Config {
|
|
||||||
noBaseFee := true
|
|
||||||
if types.IsLondon(cfg.ChainConfig, ctx.BlockHeight()) {
|
|
||||||
noBaseFee = k.feeMarketKeeper.GetParams(ctx).NoBaseFee
|
|
||||||
}
|
|
||||||
|
|
||||||
var debug bool
|
|
||||||
if _, ok := tracer.(types.NoOpTracer); !ok {
|
|
||||||
debug = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return vm.Config{
|
|
||||||
Debug: debug,
|
|
||||||
Tracer: tracer,
|
|
||||||
NoBaseFee: noBaseFee,
|
|
||||||
ExtraEips: cfg.Params.EIPs(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases:
|
// GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases:
|
||||||
// 1. The requested height matches the current height from context (and thus same epoch number)
|
// 1. The requested height matches the current height from context (and thus same epoch number)
|
||||||
// 2. The requested height is from an previous height from the same chain epoch
|
// 2. The requested height is from an previous height from the same chain epoch
|
||||||
@ -329,6 +261,17 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplyMessage calls ApplyMessageWithConfig with an empty TxConfig.
|
||||||
|
func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer vm.EVMLogger, commit bool) (*types.MsgEthereumTxResponse, error) {
|
||||||
|
cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errorsmod.Wrap(err, "failed to load evm config")
|
||||||
|
}
|
||||||
|
|
||||||
|
txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash()))
|
||||||
|
return k.ApplyMessageWithConfig(ctx, msg, tracer, commit, cfg, txConfig)
|
||||||
|
}
|
||||||
|
|
||||||
// ApplyMessageWithConfig computes the new state by applying the given message against the existing state.
|
// ApplyMessageWithConfig computes the new state by applying the given message against the existing state.
|
||||||
// If the message fails, the VM execution error with the reason will be returned to the client
|
// If the message fails, the VM execution error with the reason will be returned to the client
|
||||||
// and the transaction won't be committed to the store.
|
// and the transaction won't be committed to the store.
|
||||||
@ -371,7 +314,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context,
|
|||||||
msg core.Message,
|
msg core.Message,
|
||||||
tracer vm.EVMLogger,
|
tracer vm.EVMLogger,
|
||||||
commit bool,
|
commit bool,
|
||||||
cfg *types.EVMConfig,
|
cfg *statedb.EVMConfig,
|
||||||
txConfig statedb.TxConfig,
|
txConfig statedb.TxConfig,
|
||||||
) (*types.MsgEthereumTxResponse, error) {
|
) (*types.MsgEthereumTxResponse, error) {
|
||||||
var (
|
var (
|
||||||
@ -485,83 +428,3 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context,
|
|||||||
Hash: txConfig.TxHash.Hex(),
|
Hash: txConfig.TxHash.Hex(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyMessage calls ApplyMessageWithConfig with default EVMConfig
|
|
||||||
func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer vm.EVMLogger, commit bool) (*types.MsgEthereumTxResponse, error) {
|
|
||||||
cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errorsmod.Wrap(err, "failed to load evm config")
|
|
||||||
}
|
|
||||||
txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash()))
|
|
||||||
return k.ApplyMessageWithConfig(ctx, msg, tracer, commit, cfg, txConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetEthIntrinsicGas returns the intrinsic gas cost for the transaction
|
|
||||||
func (k *Keeper) GetEthIntrinsicGas(ctx sdk.Context, msg core.Message, cfg *params.ChainConfig, isContractCreation bool) (uint64, error) {
|
|
||||||
height := big.NewInt(ctx.BlockHeight())
|
|
||||||
homestead := cfg.IsHomestead(height)
|
|
||||||
istanbul := cfg.IsIstanbul(height)
|
|
||||||
|
|
||||||
return core.IntrinsicGas(msg.Data(), msg.AccessList(), isContractCreation, homestead, istanbul)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RefundGas transfers the leftover gas to the sender of the message, caped to half of the total gas
|
|
||||||
// consumed in the transaction. Additionally, the function sets the total gas consumed to the value
|
|
||||||
// returned by the EVM execution, thus ignoring the previous intrinsic gas consumed during in the
|
|
||||||
// AnteHandler.
|
|
||||||
func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64, denom string) error {
|
|
||||||
// Return EVM tokens for remaining gas, exchanged at the original rate.
|
|
||||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice())
|
|
||||||
|
|
||||||
switch remaining.Sign() {
|
|
||||||
case -1:
|
|
||||||
// negative refund errors
|
|
||||||
return errorsmod.Wrapf(types.ErrInvalidRefund, "refunded amount value cannot be negative %d", remaining.Int64())
|
|
||||||
case 1:
|
|
||||||
// positive amount refund
|
|
||||||
refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(remaining))}
|
|
||||||
|
|
||||||
// refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees
|
|
||||||
|
|
||||||
err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins)
|
|
||||||
if err != nil {
|
|
||||||
err = errorsmod.Wrapf(errortypes.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error())
|
|
||||||
return errorsmod.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// no refund, consume gas and update the tx gas meter
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetGasMeterAndConsumeGas reset first the gas meter consumed value to zero and set it back to the new value
|
|
||||||
// 'gasUsed'
|
|
||||||
func (k *Keeper) ResetGasMeterAndConsumeGas(ctx sdk.Context, gasUsed uint64) {
|
|
||||||
// reset the gas count
|
|
||||||
ctx.GasMeter().RefundGas(ctx.GasMeter().GasConsumed(), "reset the gas count")
|
|
||||||
ctx.GasMeter().ConsumeGas(gasUsed, "apply evm transaction")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProposerAddress returns current block proposer's address when provided proposer address is empty.
|
|
||||||
func GetProposerAddress(ctx sdk.Context, proposerAddress sdk.ConsAddress) sdk.ConsAddress {
|
|
||||||
if len(proposerAddress) == 0 {
|
|
||||||
proposerAddress = ctx.BlockHeader().ProposerAddress
|
|
||||||
}
|
|
||||||
return proposerAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCoinbaseAddress returns the block proposer's validator operator address.
|
|
||||||
func (k Keeper) GetCoinbaseAddress(ctx sdk.Context, proposerAddress sdk.ConsAddress) (common.Address, error) {
|
|
||||||
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, GetProposerAddress(ctx, proposerAddress))
|
|
||||||
if !found {
|
|
||||||
return common.Address{}, errorsmod.Wrapf(
|
|
||||||
stakingtypes.ErrNoValidatorFound,
|
|
||||||
"failed to retrieve validator from block proposer address %s",
|
|
||||||
proposerAddress.String(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
coinbase := common.BytesToAddress(validator.GetOperator())
|
|
||||||
return coinbase, nil
|
|
||||||
}
|
|
||||||
|
@ -571,7 +571,7 @@ func (suite *KeeperTestSuite) TestApplyMessageWithConfig() {
|
|||||||
msg core.Message
|
msg core.Message
|
||||||
err error
|
err error
|
||||||
expectedGasUsed uint64
|
expectedGasUsed uint64
|
||||||
config *types.EVMConfig
|
config *statedb.EVMConfig
|
||||||
keeperParams types.Params
|
keeperParams types.Params
|
||||||
signer ethtypes.Signer
|
signer ethtypes.Signer
|
||||||
vmdb *statedb.StateDB
|
vmdb *statedb.StateDB
|
||||||
@ -660,13 +660,10 @@ func (suite *KeeperTestSuite) TestApplyMessageWithConfig() {
|
|||||||
suite.Require().Equal(expectedGasUsed, res.GasUsed)
|
suite.Require().Equal(expectedGasUsed, res.GasUsed)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) createContractGethMsg(nonce uint64, signer ethtypes.Signer, cfg *params.ChainConfig, gasPrice *big.Int) (core.Message, error) {
|
func (suite *KeeperTestSuite) createContractGethMsg(nonce uint64, signer ethtypes.Signer, cfg *params.ChainConfig, gasPrice *big.Int) (core.Message, error) {
|
||||||
|
|
||||||
ethMsg, err := suite.createContractMsgTx(nonce, signer, cfg, gasPrice)
|
ethMsg, err := suite.createContractMsgTx(nonce, signer, cfg, gasPrice)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -676,7 +673,6 @@ func (suite *KeeperTestSuite) createContractGethMsg(nonce uint64, signer ethtype
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) createContractMsgTx(nonce uint64, signer ethtypes.Signer, cfg *params.ChainConfig, gasPrice *big.Int) (*types.MsgEthereumTx, error) {
|
func (suite *KeeperTestSuite) createContractMsgTx(nonce uint64, signer ethtypes.Signer, cfg *params.ChainConfig, gasPrice *big.Int) (*types.MsgEthereumTx, error) {
|
||||||
|
|
||||||
contractCreateTx := ðtypes.AccessListTx{
|
contractCreateTx := ðtypes.AccessListTx{
|
||||||
GasPrice: gasPrice,
|
GasPrice: gasPrice,
|
||||||
Gas: params.TxGasContractCreation,
|
Gas: params.TxGasContractCreation,
|
||||||
|
@ -18,19 +18,43 @@ package keeper
|
|||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
errorsmod "cosmossdk.io/errors"
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdkmath "cosmossdk.io/math"
|
sdkmath "cosmossdk.io/math"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
|
|
||||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
"github.com/evmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetCoinbaseAddress returns the block proposer's validator operator address.
|
||||||
|
func (k Keeper) GetCoinbaseAddress(ctx sdk.Context, proposerAddress sdk.ConsAddress) (common.Address, error) {
|
||||||
|
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, GetProposerAddress(ctx, proposerAddress))
|
||||||
|
if !found {
|
||||||
|
return common.Address{}, errorsmod.Wrapf(
|
||||||
|
stakingtypes.ErrNoValidatorFound,
|
||||||
|
"failed to retrieve validator from block proposer address %s",
|
||||||
|
proposerAddress.String(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinbase := common.BytesToAddress(validator.GetOperator())
|
||||||
|
return coinbase, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProposerAddress returns current block proposer's address when provided proposer address is empty.
|
||||||
|
func GetProposerAddress(ctx sdk.Context, proposerAddress sdk.ConsAddress) sdk.ConsAddress {
|
||||||
|
if len(proposerAddress) == 0 {
|
||||||
|
proposerAddress = ctx.BlockHeader().ProposerAddress
|
||||||
|
}
|
||||||
|
return proposerAddress
|
||||||
|
}
|
||||||
|
|
||||||
// DeductTxCostsFromUserBalance deducts the fees from the user balance. Returns an
|
// DeductTxCostsFromUserBalance deducts the fees from the user balance. Returns an
|
||||||
// error if the specified sender address does not exist or the account balance is not sufficient.
|
// error if the specified sender address does not exist or the account balance is not sufficient.
|
||||||
func (k *Keeper) DeductTxCostsFromUserBalance(
|
func (k *Keeper) DeductTxCostsFromUserBalance(
|
||||||
@ -56,7 +80,7 @@ func (k *Keeper) DeductTxCostsFromUserBalance(
|
|||||||
// gas limit is not reached, the gas limit is higher than the intrinsic gas and that the
|
// gas limit is not reached, the gas limit is higher than the intrinsic gas and that the
|
||||||
// base fee is higher than the gas fee cap.
|
// base fee is higher than the gas fee cap.
|
||||||
func VerifyFee(
|
func VerifyFee(
|
||||||
txData evmtypes.TxData,
|
txData types.TxData,
|
||||||
denom string,
|
denom string,
|
||||||
baseFee *big.Int,
|
baseFee *big.Int,
|
||||||
homestead, istanbul, isCheckTx bool,
|
homestead, istanbul, isCheckTx bool,
|
||||||
@ -107,7 +131,7 @@ func VerifyFee(
|
|||||||
// sender has enough funds to pay for the fees and value of the transaction.
|
// sender has enough funds to pay for the fees and value of the transaction.
|
||||||
func CheckSenderBalance(
|
func CheckSenderBalance(
|
||||||
balance sdkmath.Int,
|
balance sdkmath.Int,
|
||||||
txData evmtypes.TxData,
|
txData types.TxData,
|
||||||
) error {
|
) error {
|
||||||
cost := txData.Cost()
|
cost := txData.Cost()
|
||||||
|
|
||||||
|
@ -15,7 +15,13 @@
|
|||||||
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
|
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
|
||||||
package statedb
|
package statedb
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/common"
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/evmos/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
// TxConfig encapulates the readonly information of current tx for `StateDB`.
|
// TxConfig encapulates the readonly information of current tx for `StateDB`.
|
||||||
type TxConfig struct {
|
type TxConfig struct {
|
||||||
@ -45,3 +51,12 @@ func NewEmptyTxConfig(bhash common.Hash) TxConfig {
|
|||||||
LogIndex: 0,
|
LogIndex: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EVMConfig encapsulates common parameters needed to create an EVM to execute a message
|
||||||
|
// It's mainly to reduce the number of method parameters
|
||||||
|
type EVMConfig struct {
|
||||||
|
Params types.Params
|
||||||
|
ChainConfig *params.ChainConfig
|
||||||
|
CoinBase common.Address
|
||||||
|
BaseFee *big.Int
|
||||||
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
// Copyright 2021 Evmos Foundation
|
|
||||||
// This file is part of Evmos' Ethermint library.
|
|
||||||
//
|
|
||||||
// The Ethermint library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The Ethermint library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
|
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EVMConfig encapsulates common parameters needed to create an EVM to execute a message
|
|
||||||
// It's mainly to reduce the number of method parameters
|
|
||||||
type EVMConfig struct {
|
|
||||||
Params Params
|
|
||||||
ChainConfig *params.ChainConfig
|
|
||||||
CoinBase common.Address
|
|
||||||
BaseFee *big.Int
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user