Skip to content

Commit

Permalink
(wip) Cherry-pick: Problem: evm transfer is not efficient (crypto-org…
Browse files Browse the repository at this point in the history
…-chain#448)

Reason for Cherry-pick:
- Required patch for migrating Block STM (Parallel Transaction Execution)
- Avoid common conflict problem when transfer eth

Notes
- (bug) While cherry-picking necessary one, I'm trying to implement native state revert using only SDK's store functions, but some error occurs. Need to fix it.
- (refactor) Refactored test codes by referencing Cronos because it is more clean and maintainable

Original Commit Message:
* Problem: evm transfer is not efficient

Solution:
- override the Transfer callback in block context.

Update CHANGELOG.md

Signed-off-by: yihuang <[email protected]>

* test reverted sdk

* update deps

---------

Signed-off-by: yihuang <[email protected]>

Cherry-picked-by: zsystm <[email protected]>
  • Loading branch information
yihuang authored and zsystm committed Jun 10, 2024
1 parent 9736934 commit bebf553
Show file tree
Hide file tree
Showing 19 changed files with 951 additions and 517 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug Fixes

* (evm) [#447](https://github.com/crypto-org-chain/ethermint/pull/447) Deduct fee through virtual bank transfer.
- (rpc) [#1688](https://github.com/evmos/ethermint/pull/1688) Align filter rule for `debug_traceBlockByNumber`

### Improvements

- (ante) [#1717](https://github.com/evmos/ethermint/pull/1717) Reuse sender recovery result.
- (evm) [#447](https://github.com/crypto-org-chain/ethermint/pull/447) Deduct fee through virtual bank transfer.
- (evm) [#448](https://github.com/crypto-org-chain/ethermint/pull/448) Refactor the evm transfer to be more efficient.

## [v0.21.0] - 2023-01-26

Expand Down
4 changes: 3 additions & 1 deletion app/ante/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ func (avd EthAccountVerificationDecorator) AnteHandle(
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
}

if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
params := avd.evmKeeper.GetParams(ctx)
balance := avd.evmKeeper.GetBalance(ctx, from, params.EvmDenom)
if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(balance), txData); err != nil {
return ctx, errorsmod.Wrap(err, "failed to check sender balance")
}
}
Expand Down
1 change: 0 additions & 1 deletion app/ante/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ type EVMKeeper interface {

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
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
ResetTransientGasUsed(ctx sdk.Context)
GetTxIndexTransient(ctx sdk.Context) uint64
GetParams(ctx sdk.Context) evmtypes.Params
Expand Down
35 changes: 35 additions & 0 deletions testutil/config/encoding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package config

import (
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/evmos/ethermint/encoding"
"github.com/evmos/ethermint/types"
"github.com/evmos/ethermint/x/evm"
"github.com/evmos/ethermint/x/feemarket"
)

func MakeConfigForTest(moduleManager module.BasicManager) types.EncodingConfig {
config := encoding.MakeConfig()
if moduleManager == nil {
moduleManager = module.NewBasicManager(
auth.AppModuleBasic{},
bank.AppModuleBasic{},
distr.AppModuleBasic{},
gov.NewAppModuleBasic([]govclient.ProposalHandler{paramsclient.ProposalHandler}),
staking.AppModuleBasic{},
// Ethermint modules
evm.AppModuleBasic{},
feemarket.AppModuleBasic{},
)
}
moduleManager.RegisterLegacyAminoCodec(config.Amino)
moduleManager.RegisterInterfaces(config.InterfaceRegistry)
return config
}
6 changes: 3 additions & 3 deletions x/evm/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ func (suite *HandlerTestSuite) TestERC20TransferReverted() {
k.SetHooks(tc.hooks)

// add some fund to pay gas fee
suite.Require().NoError(k.SetBalance(suite.Ctx, suite.Address, big.NewInt(1000000000000000)))
suite.Require().NoError(k.SetBalance(suite.Ctx, suite.Address, big.NewInt(1000000000000000), types.DefaultEVMDenom))

contract := suite.deployERC20Contract()

Expand All @@ -477,7 +477,7 @@ func (suite *HandlerTestSuite) TestERC20TransferReverted() {
)
suite.SignTx(tx)

before := k.GetBalance(suite.Ctx, suite.Address)
before := k.GetEVMDenomBalance(suite.Ctx, suite.Address)

evmParams := suite.App.EvmKeeper.GetParams(suite.Ctx)
ethCfg := evmParams.GetChainConfig().EthereumConfig(nil)
Expand All @@ -497,7 +497,7 @@ func (suite *HandlerTestSuite) TestERC20TransferReverted() {
suite.Require().Equal(tc.expErr, res.VmError)
suite.Require().Empty(res.Logs)

after := k.GetBalance(suite.Ctx, suite.Address)
after := k.GetEVMDenomBalance(suite.Ctx, suite.Address)

if tc.expErr == "out of gas" {
suite.Require().Equal(tc.gasLimit, res.GasUsed)
Expand Down
8 changes: 4 additions & 4 deletions x/evm/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ func (k Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*typ

ctx := sdk.UnwrapSDKContext(c)
acct := k.GetAccountOrEmpty(ctx, addr)
balance := k.GetEVMDenomBalance(ctx, addr)

return &types.QueryAccountResponse{
Balance: acct.Balance.String(),
Balance: balance.String(),
CodeHash: common.BytesToHash(acct.CodeHash).Hex(),
Nonce: acct.Nonce,
}, nil
Expand Down Expand Up @@ -156,8 +157,7 @@ func (k Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*typ
}

ctx := sdk.UnwrapSDKContext(c)

balanceInt := k.GetBalance(ctx, common.HexToAddress(req.Address))
balanceInt := k.GetEVMDenomBalance(ctx, common.HexToAddress(req.Address))

return &types.QueryBalanceResponse{
Balance: balanceInt.String(),
Expand Down Expand Up @@ -206,7 +206,7 @@ func (k Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.Que
ctx := sdk.UnwrapSDKContext(c)

address := common.HexToAddress(req.Address)
acct := k.GetAccountWithoutBalance(ctx, address)
acct := k.GetAccount(ctx, address)

var code []byte
if acct != nil && acct.IsContract() {
Expand Down
53 changes: 27 additions & 26 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ func (k Keeper) GetAuthority() sdk.AccAddress {

// GetBlockBloomTransient returns bloom bytes for the current block height
func (k Keeper) GetBlockBloomTransient(ctx sdk.Context) *big.Int {
store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom)
prefixStore := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom)
heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight()))
bz := store.Get(heightBz)
bz := prefixStore.Get(heightBz)
if len(bz) == 0 {
return big.NewInt(0)
}
Expand All @@ -183,9 +183,9 @@ func (k Keeper) GetBlockBloomTransient(ctx sdk.Context) *big.Int {
// SetBlockBloomTransient sets the given bloom bytes to the transient store. This value is reset on
// every block.
func (k Keeper) SetBlockBloomTransient(ctx sdk.Context, bloom *big.Int) {
store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom)
prefixStore := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom)
heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight()))
store.Set(heightBz, bloom.Bytes())
prefixStore.Set(heightBz, bloom.Bytes())
}

// ----------------------------------------------------------------------------
Expand All @@ -194,14 +194,14 @@ func (k Keeper) SetBlockBloomTransient(ctx sdk.Context, bloom *big.Int) {

// SetTxIndexTransient set the index of processing transaction
func (k Keeper) SetTxIndexTransient(ctx sdk.Context, index uint64) {
store := ctx.TransientStore(k.transientKey)
store.Set(types.KeyPrefixTransientTxIndex, sdk.Uint64ToBigEndian(index))
prefixStore := ctx.TransientStore(k.transientKey)
prefixStore.Set(types.KeyPrefixTransientTxIndex, sdk.Uint64ToBigEndian(index))
}

// GetTxIndexTransient returns EVM transaction index on the current block.
func (k Keeper) GetTxIndexTransient(ctx sdk.Context) uint64 {
store := ctx.TransientStore(k.transientKey)
bz := store.Get(types.KeyPrefixTransientTxIndex)
prefixStore := ctx.TransientStore(k.transientKey)
bz := prefixStore.Get(types.KeyPrefixTransientTxIndex)
if len(bz) == 0 {
return 0
}
Expand All @@ -215,8 +215,8 @@ func (k Keeper) GetTxIndexTransient(ctx sdk.Context) uint64 {

// GetLogSizeTransient returns EVM log index on the current block.
func (k Keeper) GetLogSizeTransient(ctx sdk.Context) uint64 {
store := ctx.TransientStore(k.transientKey)
bz := store.Get(types.KeyPrefixTransientLogSize)
tStore := ctx.TransientStore(k.transientKey)
bz := tStore.Get(types.KeyPrefixTransientLogSize)
if len(bz) == 0 {
return 0
}
Expand All @@ -227,8 +227,8 @@ func (k Keeper) GetLogSizeTransient(ctx sdk.Context) uint64 {
// SetLogSizeTransient fetches the current EVM log index from the transient store, increases its
// value by one and then sets the new index back to the transient store.
func (k Keeper) SetLogSizeTransient(ctx sdk.Context, logSize uint64) {
store := ctx.TransientStore(k.transientKey)
store.Set(types.KeyPrefixTransientLogSize, sdk.Uint64ToBigEndian(logSize))
tStore := ctx.TransientStore(k.transientKey)
tStore.Set(types.KeyPrefixTransientLogSize, sdk.Uint64ToBigEndian(logSize))
}

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -275,9 +275,7 @@ func (k Keeper) Tracer(ctx sdk.Context, msg core.Message, ethCfg *params.ChainCo
return types.NewTracer(k.tracer, msg, ethCfg, ctx.BlockHeight())
}

// GetAccountWithoutBalance load nonce and codehash without balance,
// more efficient in cases where balance is not needed.
func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *statedb.Account {
func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account {
cosmosAddr := sdk.AccAddress(addr.Bytes())
acct := k.accountKeeper.GetAccount(ctx, cosmosAddr)
if acct == nil {
Expand Down Expand Up @@ -305,7 +303,6 @@ func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) statedb

// empty account
return statedb.Account{
Balance: new(big.Int),
CodeHash: types.EmptyCodeHash,
}
}
Expand All @@ -321,17 +318,21 @@ func (k *Keeper) GetNonce(ctx sdk.Context, addr common.Address) uint64 {
return acct.GetSequence()
}

// GetBalance load account's balance of gas token
func (k *Keeper) GetBalance(ctx sdk.Context, addr common.Address) *big.Int {
// GetEVMDenomBalance returns the balance of evm denom
func (k *Keeper) GetEVMDenomBalance(ctx sdk.Context, addr common.Address) *big.Int {
cosmosAddr := sdk.AccAddress(addr.Bytes())
evmParams := k.GetParams(ctx)
evmDenom := evmParams.GetEvmDenom()
// if node is pruned, params is empty. Return invalid value
if evmDenom == "" {
return big.NewInt(-1)
}
coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, evmDenom)
return coin.Amount.BigInt()
return k.GetBalance(ctx, cosmosAddr, evmDenom)
}

// GetBalance load account's balance of specified denom
func (k *Keeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) *big.Int {
return k.bankKeeper.GetBalance(ctx, addr, denom).Amount.BigInt()
}

// GetBaseFee returns current base fee, return values:
Expand Down Expand Up @@ -366,14 +367,14 @@ func (k Keeper) GetMinGasMultiplier(ctx sdk.Context) sdkmath.LegacyDec {

// ResetTransientGasUsed reset gas used to prepare for execution of current cosmos tx, called in ante handler.
func (k Keeper) ResetTransientGasUsed(ctx sdk.Context) {
store := ctx.TransientStore(k.transientKey)
store.Delete(types.KeyPrefixTransientGasUsed)
tstore := ctx.TransientStore(k.transientKey)
tstore.Delete(types.KeyPrefixTransientGasUsed)
}

// GetTransientGasUsed returns the gas used by current cosmos tx.
func (k Keeper) GetTransientGasUsed(ctx sdk.Context) uint64 {
store := ctx.TransientStore(k.transientKey)
bz := store.Get(types.KeyPrefixTransientGasUsed)
tstore := ctx.TransientStore(k.transientKey)
bz := tstore.Get(types.KeyPrefixTransientGasUsed)
if len(bz) == 0 {
return 0
}
Expand All @@ -382,9 +383,9 @@ func (k Keeper) GetTransientGasUsed(ctx sdk.Context) uint64 {

// SetTransientGasUsed sets the gas used by current cosmos tx.
func (k Keeper) SetTransientGasUsed(ctx sdk.Context, gasUsed uint64) {
store := ctx.TransientStore(k.transientKey)
tstore := ctx.TransientStore(k.transientKey)
bz := sdk.Uint64ToBigEndian(gasUsed)
store.Set(types.KeyPrefixTransientGasUsed, bz)
tstore.Set(types.KeyPrefixTransientGasUsed, bz)
}

// AddTransientGasUsed accumulate gas used by each eth msgs included in current cosmos tx.
Expand Down
1 change: 0 additions & 1 deletion x/evm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,6 @@ func (suite *KeeperTestSuite) TestGetAccountStorage() {

func (suite *KeeperTestSuite) TestGetAccountOrEmpty() {
empty := statedb.Account{
Balance: new(big.Int),
CodeHash: types.EmptyCodeHash,
}

Expand Down
2 changes: 1 addition & 1 deletion x/evm/keeper/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (k *Keeper) NewEVM(
) evm.EVM {
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Transfer: statedb.Transfer,
GetHash: k.GetHashFn(ctx),
Coinbase: cfg.CoinBase,
GasLimit: ethermint.BlockGasLimit(ctx),
Expand Down
Loading

0 comments on commit bebf553

Please sign in to comment.