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

Problem: contract call which does lots of message calls is slow to execute #729

Merged
merged 7 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (evm) Reject invalid `MsgEthereumTx` wrapping tx
* (evm) Fix `SelfDestruct` opcode by deleting account code and state.
* (feemarket) [tharsis#855](https://github.com/tharsis/ethermint/pull/855) consistent `BaseFee` check logic.
* (evm) [tharsis#729](https://github.com/tharsis/ethermint/pull/729) Refactor EVM StateDB implementation.

### Improvements

Expand Down
4 changes: 2 additions & 2 deletions app/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
suite.Require().NoError(acc.SetSequence(1))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

suite.app.EvmKeeper.AddBalance(addr, big.NewInt(10000000000))
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt(10000000000))

suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100))

Expand Down Expand Up @@ -577,7 +577,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
suite.app.EvmKeeper.AddBalance(addr, big.NewInt((ethparams.InitialBaseFee+10)*100000))
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000))
_, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
if tc.expPass {
suite.Require().NoError(err)
Expand Down
39 changes: 14 additions & 25 deletions app/ante/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

ethermint "github.com/tharsis/ethermint/types"
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -95,9 +96,6 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
return next(ctx, tx, simulate)
}

avd.evmKeeper.WithContext(ctx)
evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom

for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
Expand All @@ -117,25 +115,25 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx

// check whether the sender address is EOA
fromAddr := common.BytesToAddress(from)
codeHash := avd.evmKeeper.GetCodeHash(fromAddr)
if codeHash != common.BytesToHash(evmtypes.EmptyCodeHash) {
acct, err := avd.evmKeeper.GetAccount(ctx, fromAddr)
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
"the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash)
"the sender is not EthAccount: address %s", fromAddr)
}

acc := avd.ak.GetAccount(ctx, from)
if acc == nil {
acc = avd.ak.NewAccountWithAddress(ctx, from)
if acct == nil {
acc := avd.ak.NewAccountWithAddress(ctx, from)
avd.ak.SetAccount(ctx, acc)
acct = statedb.NewEmptyAccount()
} else if acct.IsContract() {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
}

if err := evmkeeper.CheckSenderBalance(ctx, avd.bankKeeper, from, txData, evmDenom); err != nil {
if err := evmkeeper.CheckSenderBalance(sdk.NewIntFromBigInt(acct.Balance), txData); err != nil {
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

@fedekunze fedekunze Jan 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if acct.Balance is not nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sdk.NewIntFromBigInt treat nil as an empty int, so looks ok?

return ctx, sdkerrors.Wrap(err, "failed to check sender balance")
}

}
// recover the original gas meter
avd.evmKeeper.WithContext(ctx)
return next(ctx, tx, simulate)
}

Expand Down Expand Up @@ -221,9 +219,6 @@ func NewEthGasConsumeDecorator(
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
// - transaction or block gas meter runs out of gas
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// reset the refund gas value in the keeper for the current transaction
egcd.evmKeeper.ResetRefundTransient(ctx)

params := egcd.evmKeeper.GetParams(ctx)
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
Expand Down Expand Up @@ -278,8 +273,6 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
}

// we know that we have enough gas on the pool to cover the intrinsic gas
// set up the updated context to the evm Keeper
egcd.evmKeeper.WithContext(ctx)
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
return next(ctx, tx, simulate)
}

Expand All @@ -301,8 +294,6 @@ func NewCanTransferDecorator(evmKeeper EVMKeeper, fmk evmtypes.FeeMarketKeeper)
// AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to
// see if the address can execute the transaction.
func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
ctd.evmKeeper.WithContext(ctx)

params := ctd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID())
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
Expand Down Expand Up @@ -330,11 +321,12 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
CoinBase: common.Address{},
BaseFee: baseFee,
}
evm := ctd.evmKeeper.NewEVM(coreMsg, cfg, evmtypes.NewNoOpTracer())
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)

// 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(ctd.evmKeeper, 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",
Expand All @@ -360,7 +352,6 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
}
}

// set the original gas meter
return next(ctx, tx, simulate)
}

Expand Down Expand Up @@ -422,8 +413,6 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
return next(ctx, tx, simulate)
}

vbd.evmKeeper.WithContext(ctx)

err := tx.ValidateBasic()
// ErrNoSignatures is fine with eth tx
if err != nil && !errors.Is(err, sdkerrors.ErrNoSignatures) {
Expand Down
51 changes: 25 additions & 26 deletions app/ante/eth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/tharsis/ethermint/app/ante"
"github.com/tharsis/ethermint/tests"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"

ethtypes "github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -65,6 +66,8 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
tx.From = addr.Hex()

var vmdb *statedb.StateDB

testCases := []struct {
name string
tx sdk.Tx
Expand All @@ -86,7 +89,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
tx,
func() {
// set not as an EOA
suite.app.EvmKeeper.SetCode(addr, []byte("1"))
vmdb.SetCode(addr, []byte("1"))
},
true,
false,
Expand All @@ -96,7 +99,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
tx,
func() {
// reset back to EOA
suite.app.EvmKeeper.SetCode(addr, nil)
vmdb.SetCode(addr, nil)
},
true,
false,
Expand All @@ -105,7 +108,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
"success new account",
tx,
func() {
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
vmdb.AddBalance(addr, big.NewInt(1000000))
},
true,
true,
Expand All @@ -117,7 +120,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
vmdb.AddBalance(addr, big.NewInt(1000000))
},
true,
true,
Expand All @@ -126,7 +129,10 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {

for _, tc := range testCases {
suite.Run(tc.name, func() {
vmdb = suite.StateDB()
tc.malleate()
suite.Require().NoError(vmdb.Commit())

_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)

if tc.expPass {
Expand Down Expand Up @@ -204,6 +210,8 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000000, big.NewInt(1), nil, nil, nil, &ethtypes.AccessList{{Address: addr, StorageKeys: nil}})
tx2.From = addr.Hex()

var vmdb *statedb.StateDB

testCases := []struct {
name string
tx sdk.Tx
Expand All @@ -221,40 +229,28 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
{
"gas limit too low",
tx,
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
},
func() {},
false, false,
},
{
"not enough balance for fees",
tx2,
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
},
func() {},
false, false,
},
{
"not enough tx gas",
tx2,
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
vmdb.AddBalance(addr, big.NewInt(1000000))
},
false, true,
},
{
"not enough block gas",
tx2,
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
vmdb.AddBalance(addr, big.NewInt(1000000))

suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(1))
},
Expand All @@ -264,10 +260,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
"success",
tx2,
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
vmdb.AddBalance(addr, big.NewInt(1000000))

suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(10000000000000000000))
},
Expand All @@ -277,7 +270,9 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {

for _, tc := range testCases {
suite.Run(tc.name, func() {
vmdb = suite.StateDB()
tc.malleate()
suite.Require().NoError(vmdb.Commit())

if tc.expPanic {
suite.Require().Panics(func() {
Expand Down Expand Up @@ -331,6 +326,8 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
err := tx.Sign(suite.ethSigner, tests.NewSigner(privKey))
suite.Require().NoError(err)

var vmdb *statedb.StateDB

testCases := []struct {
name string
tx sdk.Tx
Expand All @@ -355,15 +352,17 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
vmdb.AddBalance(addr, big.NewInt(1000000))
},
true,
},
}

for _, tc := range testCases {
suite.Run(tc.name, func() {
vmdb = suite.StateDB()
tc.malleate()
suite.Require().NoError(vmdb.Commit())

_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)

Expand Down Expand Up @@ -458,7 +457,7 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
txData, err := evmtypes.UnpackTxData(msg.Data)
suite.Require().NoError(err)

nonce := suite.app.EvmKeeper.GetNonce(addr)
nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, addr)
suite.Require().Equal(txData.GetNonce()+1, nonce)
} else {
suite.Require().Error(err)
Expand Down
9 changes: 3 additions & 6 deletions app/ante/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,20 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
tx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)

// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
type EVMKeeper interface {
vm.StateDB
statedb.Keeper

ChainID() *big.Int
GetParams(ctx sdk.Context) evmtypes.Params
WithContext(ctx sdk.Context)
ResetRefundTransient(ctx sdk.Context)
NewEVM(msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.Tracer) *vm.EVM
GetCodeHash(addr common.Address) common.Hash
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.Tracer, stateDB vm.StateDB) *vm.EVM
DeductTxCostsFromUserBalance(
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
) (sdk.Coins, error)
Expand Down
9 changes: 5 additions & 4 deletions app/ante/sigs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math/big"

"github.com/tharsis/ethermint/tests"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)

Expand All @@ -14,11 +15,11 @@ func (suite AnteTestSuite) TestSignatures() {
addr, privKey := tests.NewAddrKey()
to := tests.GenerateAddress()

acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
suite.Require().NoError(acc.SetSequence(1))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
acc := statedb.NewEmptyAccount()
acc.Nonce = 1
acc.Balance = big.NewInt(10000000000)

suite.app.EvmKeeper.AddBalance(addr, big.NewInt(10000000000))
suite.app.EvmKeeper.SetAccount(suite.ctx, addr, *acc)
msgEthereumTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
msgEthereumTx.From = addr.Hex()

Expand Down
6 changes: 6 additions & 0 deletions app/ante/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"

"github.com/stretchr/testify/suite"
Expand All @@ -25,6 +26,7 @@ import (
ante "github.com/tharsis/ethermint/app/ante"
"github.com/tharsis/ethermint/encoding"
"github.com/tharsis/ethermint/tests"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"

Expand All @@ -43,6 +45,10 @@ type AnteTestSuite struct {
enableLondonHF bool
}

func (suite *AnteTestSuite) StateDB() *statedb.StateDB {
return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())))
}
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

func (suite *AnteTestSuite) SetupTest() {
checkTx := false

Expand Down
Loading