Skip to content

Commit

Permalink
fix revert error to return proper error message (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 authored Nov 8, 2024
1 parent 5df5933 commit 967c549
Show file tree
Hide file tree
Showing 17 changed files with 185 additions and 134 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ replace (
replace (
github.com/cometbft/cometbft => github.com/initia-labs/cometbft v0.0.0-20240925132752-ff8ff0126261
github.com/cosmos/ibc-go/v8 => github.com/initia-labs/ibc-go/v8 v8.0.0-20240802003717-19c0b4ad450d
github.com/ethereum/go-ethereum => github.com/initia-labs/evm v0.0.0-20241105070652-c43b570a4e98
github.com/ethereum/go-ethereum => github.com/initia-labs/evm v0.0.0-20241108055119-3d312736d7fb

// use custom version until this PR is merged
// - https://github.com/strangelove-ventures/cometbft-client/pull/10
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1440,8 +1440,8 @@ github.com/initia-labs/cometbft v0.0.0-20240925132752-ff8ff0126261 h1:V62KOhe6Em
github.com/initia-labs/cometbft v0.0.0-20240925132752-ff8ff0126261/go.mod h1:KsQ7Wm/dw9N0l7Ypn3QKGwgUX5XinTlcHGIF0DSjsw4=
github.com/initia-labs/cometbft-client v0.0.0-20240924071428-ef115cefa07e h1:k+pg63SFozCAK4LZFSiZtof6z69Tlu0O/Zftj1aAwes=
github.com/initia-labs/cometbft-client v0.0.0-20240924071428-ef115cefa07e/go.mod h1:aVposiPW9FOUeAeJ7JjJRdE3g+L6i8YDxFn6Cv6+Az4=
github.com/initia-labs/evm v0.0.0-20241105070652-c43b570a4e98 h1:JmJpxtYnF++Lj9MhD2LxOtgNAJM0aYqgO9nBkuhiGlI=
github.com/initia-labs/evm v0.0.0-20241105070652-c43b570a4e98/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E=
github.com/initia-labs/evm v0.0.0-20241108055119-3d312736d7fb h1:oyH9gg/4f7uMCIJYnSpp7wa1NrGjSMsXTtypUfrsPLU=
github.com/initia-labs/evm v0.0.0-20241108055119-3d312736d7fb/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E=
github.com/initia-labs/ibc-go/v8 v8.0.0-20240802003717-19c0b4ad450d h1:TLq8lB1PtQ0pjGf+bN8YgGVeLMuytZ26SBGMOs1seKY=
github.com/initia-labs/ibc-go/v8 v8.0.0-20240802003717-19c0b4ad450d/go.mod h1:zh6x1osR0hNvEcFrC/lhGD08sMfQmr9wHVvZ/mRWMCs=
github.com/initia-labs/initia v0.6.0 h1:/39ZN26zeixxZZdcfY1sOitiBhfnG3lcbPtpFqd9z7A=
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ replace (
replace (
github.com/cometbft/cometbft => github.com/initia-labs/cometbft v0.0.0-20240925132752-ff8ff0126261
github.com/cosmos/ibc-go/v8 => github.com/initia-labs/ibc-go/v8 v8.0.0-20240802003717-19c0b4ad450d
github.com/ethereum/go-ethereum => github.com/initia-labs/evm v0.0.0-20241105070652-c43b570a4e98
github.com/ethereum/go-ethereum => github.com/initia-labs/evm v0.0.0-20241108055119-3d312736d7fb

// use custom version until this PR is merged
// - https://github.com/strangelove-ventures/cometbft-client/pull/10
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1398,8 +1398,8 @@ github.com/initia-labs/OPinit/api v0.5.1 h1:zwyJf7HtKJCKvLJ1R9PjVfJO1L+d/jKoeFyT
github.com/initia-labs/OPinit/api v0.5.1/go.mod h1:gHK6DEWb3/DqQD5LjKirUx9jilAh2UioXanoQdgqVfU=
github.com/initia-labs/cometbft v0.0.0-20240925132752-ff8ff0126261 h1:V62KOhe6Em3wAvJsDVP+3is98I3mk/29OKNVs4IxeFQ=
github.com/initia-labs/cometbft v0.0.0-20240925132752-ff8ff0126261/go.mod h1:KsQ7Wm/dw9N0l7Ypn3QKGwgUX5XinTlcHGIF0DSjsw4=
github.com/initia-labs/evm v0.0.0-20241105070652-c43b570a4e98 h1:JmJpxtYnF++Lj9MhD2LxOtgNAJM0aYqgO9nBkuhiGlI=
github.com/initia-labs/evm v0.0.0-20241105070652-c43b570a4e98/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E=
github.com/initia-labs/evm v0.0.0-20241108055119-3d312736d7fb h1:oyH9gg/4f7uMCIJYnSpp7wa1NrGjSMsXTtypUfrsPLU=
github.com/initia-labs/evm v0.0.0-20241108055119-3d312736d7fb/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E=
github.com/initia-labs/ibc-go/v8 v8.0.0-20240802003717-19c0b4ad450d h1:TLq8lB1PtQ0pjGf+bN8YgGVeLMuytZ26SBGMOs1seKY=
github.com/initia-labs/ibc-go/v8 v8.0.0-20240802003717-19c0b4ad450d/go.mod h1:zh6x1osR0hNvEcFrC/lhGD08sMfQmr9wHVvZ/mRWMCs=
github.com/initia-labs/initia v0.6.0 h1:/39ZN26zeixxZZdcfY1sOitiBhfnG3lcbPtpFqd9z7A=
Expand Down
2 changes: 1 addition & 1 deletion x/evm/contracts/counter/Counter.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion x/evm/contracts/counter/Counter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ contract Counter is IIBCAsyncCallback {
COSMOS_CONTRACT.execute_cosmos(exec_msg);

if (call_revert) {
revert("revert");
revert("revert reason dummy value for test");
}
}

Expand Down
21 changes: 11 additions & 10 deletions x/evm/keeper/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,20 +181,21 @@ func (k Keeper) CreateEVM(ctx context.Context, caller common.Address, tracer *tr
return ctx, nil, err
}

vmConfig := vm.Config{
Tracer: tracer,
ExtraEips: extraEIPs,
NumRetainBlockHashes: &params.NumRetainBlockHashes,
chainConfig := types.DefaultChainConfig(ctx)
rules := chainConfig.Rules(blockContext.BlockNumber, blockContext.Random != nil, blockContext.Time)
vmConfig := vm.Config{Tracer: tracer, ExtraEips: extraEIPs, NumRetainBlockHashes: &params.NumRetainBlockHashes}
precompiles, err := k.precompiles(rules, stateDB)
if err != nil {
return ctx, nil, err
}

*evm = *vm.NewEVMWithPrecompiles(
blockContext,
txContext,
stateDB,
types.DefaultChainConfig(ctx),
chainConfig,
vmConfig,
// use custom precompiles
k.Precompiles(stateDB),
precompiles,
)

if tracer != nil {
Expand Down Expand Up @@ -239,7 +240,7 @@ func (k Keeper) EVMStaticCallWithTracer(ctx context.Context, caller common.Addre
sdkCtx := sdk.UnwrapSDKContext(ctx)
gasBalance := k.computeGasLimit(sdkCtx)
rules := evm.ChainConfig().Rules(evm.Context.BlockNumber, evm.Context.Random != nil, evm.Context.Time)
evm.StateDB.Prepare(rules, caller, types.NullAddress, &contractAddr, k.precompileAddrs, accessList)
evm.StateDB.Prepare(rules, caller, types.NullAddress, &contractAddr, k.precompileAddrs(rules), accessList)

retBz, gasRemaining, err := evm.StaticCall(
vm.AccountRef(caller),
Expand Down Expand Up @@ -277,7 +278,7 @@ func (k Keeper) EVMCallWithTracer(ctx context.Context, caller common.Address, co
}

rules := evm.ChainConfig().Rules(evm.Context.BlockNumber, evm.Context.Random != nil, evm.Context.Time)
evm.StateDB.Prepare(rules, caller, types.NullAddress, &contractAddr, k.precompileAddrs, accessList)
evm.StateDB.Prepare(rules, caller, types.NullAddress, &contractAddr, k.precompileAddrs(rules), accessList)

retBz, gasRemaining, err := evm.Call(
vm.AccountRef(caller),
Expand Down Expand Up @@ -371,7 +372,7 @@ func (k Keeper) EVMCreateWithTracer(ctx context.Context, caller common.Address,
}

rules := evm.ChainConfig().Rules(evm.Context.BlockNumber, evm.Context.Random != nil, evm.Context.Time)
evm.StateDB.Prepare(rules, caller, types.NullAddress, nil, k.precompileAddrs, accessList)
evm.StateDB.Prepare(rules, caller, types.NullAddress, nil, k.precompileAddrs(rules), accessList)

var gasRemaining uint64
if salt == nil {
Expand Down
5 changes: 3 additions & 2 deletions x/evm/keeper/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ func Test_RevertAfterExecuteCosmos(t *testing.T) {
require.NoError(t, err)

_, _, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz, nil, nil)
require.ErrorContains(t, err, types.ErrReverted.Error())
require.ErrorContains(t, err, vm.ErrExecutionReverted.Error())
require.ErrorContains(t, err, "revert reason dummy value for test")

// check balance
require.Equal(t, amount, input.BankKeeper.GetBalance(ctx, sdk.AccAddress(contractAddr.Bytes()), denom).Amount)
Expand All @@ -313,7 +314,7 @@ func Test_RevertAfterExecuteCosmos(t *testing.T) {
require.NoError(t, err)

_, _, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz, nil, nil)
require.NoError(t, err, types.ErrReverted.Error())
require.NoError(t, err)

require.Equal(t, math.ZeroInt(), input.BankKeeper.GetBalance(ctx, sdk.AccAddress(contractAddr.Bytes()), denom).Amount)
require.Equal(t, amount, input.BankKeeper.GetBalance(ctx, addr, denom).Amount)
Expand Down
12 changes: 0 additions & 12 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"

evmconfig "github.com/initia-labs/minievm/x/evm/config"
"github.com/initia-labs/minievm/x/evm/contracts/i_cosmos_callback"
Expand Down Expand Up @@ -78,9 +77,6 @@ type Keeper struct {
// evm stores
EVMBlockHashes collections.Map[uint64, []byte]

precompiles vm.PrecompiledContracts
precompileAddrs []common.Address

queryCosmosWhitelist types.QueryCosmosWhitelist
cosmosCallbackABI *abi.ABI
}
Expand Down Expand Up @@ -157,9 +153,6 @@ func NewKeeper(

EVMBlockHashes: collections.NewMap(sb, types.EVMBlockHashPrefix, "evm_block_hashes", collections.Uint64Key, collections.BytesValue),

precompiles: vm.PrecompiledContracts{},
precompileAddrs: []common.Address{},

queryCosmosWhitelist: queryCosmosWhitelist,
cosmosCallbackABI: cosmosCallbackABI,
}
Expand Down Expand Up @@ -189,11 +182,6 @@ func NewKeeper(

k.txUtils = NewTxUtils(k)

// setup precompiles
if err := k.loadPrecompiles(); err != nil {
panic(err)
}

return k
}

Expand Down
39 changes: 14 additions & 25 deletions x/evm/keeper/precompiles.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
package keeper

import (
"math/big"
"slices"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/params"

cosmosprecompile "github.com/initia-labs/minievm/x/evm/precompiles/cosmos"
erc20registryprecompile "github.com/initia-labs/minievm/x/evm/precompiles/erc20_registry"
"github.com/initia-labs/minievm/x/evm/types"
)

// loadPrecompiles loads the precompiled contracts.
func (k *Keeper) loadPrecompiles() error {
erc20RegistryPrecompile, err := erc20registryprecompile.NewERC20RegistryPrecompile(k.erc20StoresKeeper)
// precompiles returns the precompiled contracts for the EVM.
func (k *Keeper) precompiles(rules params.Rules, stateDB types.StateDB) (vm.PrecompiledContracts, error) {
erc20RegistryPrecompile, err := erc20registryprecompile.NewERC20RegistryPrecompile(stateDB, k.erc20StoresKeeper)
if err != nil {
return err
return nil, err
}

cosmosPrecompile, err := cosmosprecompile.NewCosmosPrecompile(
stateDB,
k.cdc,
k.ac,
k.accountKeeper,
Expand All @@ -30,28 +28,19 @@ func (k *Keeper) loadPrecompiles() error {
k.queryCosmosWhitelist,
)
if err != nil {
return err
return nil, err
}

// prepare precompiles; always use latest chain config
// to load all precompiles.
chainConfig := types.DefaultChainConfig(sdk.Context{})
rules := chainConfig.Rules(big.NewInt(1), true, 1)

// clone the active precompiles and add the new precompiles
precompiles := vm.ActivePrecompiledContracts(rules)
precompiles[types.CosmosPrecompileAddress] = cosmosPrecompile
precompiles[types.ERC20RegistryPrecompileAddress] = erc20RegistryPrecompile
k.precompiles = precompiles

precompileAddrs := slices.Clone(vm.ActivePrecompiles(rules))
precompileAddrs = append(precompileAddrs, types.CosmosPrecompileAddress, types.ERC20RegistryPrecompileAddress)
k.precompileAddrs = precompileAddrs

return nil
return precompiles, nil
}

func (k *Keeper) Precompiles(stateDB types.StateDB) vm.PrecompiledContracts {
k.precompiles[types.CosmosPrecompileAddress].(types.SetStateDB).SetStateDB(stateDB)
k.precompiles[types.ERC20RegistryPrecompileAddress].(types.SetStateDB).SetStateDB(stateDB)
return k.precompiles
// PrecompileAddrs returns the precompile addresses for the EVM.
func (k *Keeper) precompileAddrs(rules params.Rules) []common.Address {
addrs := append(vm.ActivePrecompiles(rules), types.CosmosPrecompileAddress, types.ERC20RegistryPrecompileAddress)
return addrs
}
48 changes: 48 additions & 0 deletions x/evm/keeper/precompiles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import (

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"

"github.com/initia-labs/minievm/x/evm/contracts/counter"
"github.com/initia-labs/minievm/x/evm/contracts/i_cosmos"
"github.com/initia-labs/minievm/x/evm/keeper"
"github.com/initia-labs/minievm/x/evm/types"

"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -199,3 +204,46 @@ func Test_ToERC20(t *testing.T) {

require.Equal(t, contractAddr, unpackedRet[0].(common.Address))
}

func Test_PrecompileRevertError(t *testing.T) {
ctx, input := createDefaultTestInput(t)
_, _, addr := keyPubAddr()

counterBz, err := hexutil.Decode(counter.CounterBin)
require.NoError(t, err)

// deploy counter contract
caller := common.BytesToAddress(addr.Bytes())
retBz, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz, nil, nil)
require.NoError(t, err)
require.NotEmpty(t, retBz)
require.Len(t, contractAddr, 20)

// call execute cosmos function
parsed, err := counter.CounterMetaData.GetAbi()
require.NoError(t, err)

denom := sdk.DefaultBondDenom
amount := math.NewInt(1000000000)
input.Faucet.Mint(ctx, contractAddr.Bytes(), sdk.NewCoin(denom, amount))

// call execute_cosmos with revert
inputBz, err := parsed.Pack("execute_cosmos",
fmt.Sprintf(`{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"%s","to_address":"%s","amount":[{"denom":"%s","amount":"%s"}]}`,
addr.String(), // try to call with wrong signer
addr.String(), // caller
denom,
amount,
),
false,
)
require.NoError(t, err)

_, _, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz, nil, nil)
require.ErrorContains(t, err, vm.ErrExecutionReverted.Error())
require.ErrorContains(t, err, sdkerrors.ErrUnauthorized.Error())

// check balance
require.Equal(t, amount, input.BankKeeper.GetBalance(ctx, sdk.AccAddress(contractAddr.Bytes()), denom).Amount)
require.Equal(t, math.ZeroInt(), input.BankKeeper.GetBalance(ctx, addr, denom).Amount)
}
33 changes: 21 additions & 12 deletions x/evm/precompiles/cosmos/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ import (

var _ vm.ExtendedPrecompiledContract = &CosmosPrecompile{}
var _ vm.PrecompiledContract = &CosmosPrecompile{}
var _ types.SetStateDB = &CosmosPrecompile{}

var erc20CosmosABI *abi.ABI

func init() {
var err error
erc20CosmosABI, err = i_cosmos.ICosmosMetaData.GetAbi()
if err != nil {
panic(err)
}
}

type CosmosPrecompile struct {
*abi.ABI
Expand All @@ -42,6 +51,7 @@ type CosmosPrecompile struct {
}

func NewCosmosPrecompile(
stateDB types.StateDB,
cdc codec.Codec,
ac address.Codec,
ak types.AccountKeeper,
Expand All @@ -50,33 +60,25 @@ func NewCosmosPrecompile(
grpcRouter types.GRPCRouter,
queryWhitelist types.QueryCosmosWhitelist,
) (*CosmosPrecompile, error) {
abi, err := i_cosmos.ICosmosMetaData.GetAbi()
if err != nil {
return nil, err
}

return &CosmosPrecompile{
ABI: abi,
ABI: erc20CosmosABI,
cdc: cdc,
ac: ac,
ak: ak,
bk: bk,
edk: edk,
stateDB: stateDB,
grpcRouter: grpcRouter,
queryWhitelist: queryWhitelist,
}, nil
}

func (e *CosmosPrecompile) SetStateDB(stateDB types.StateDB) {
e.stateDB = stateDB
}

func (e *CosmosPrecompile) originAddress(ctx context.Context, addrBz []byte) (sdk.AccAddress, error) {
account := e.ak.GetAccount(ctx, addrBz)
if shorthandCallerAccount, ok := account.(types.ShorthandAccountI); ok {
addr, err := shorthandCallerAccount.GetOriginalAddress(e.ac)
if err != nil {
return nil, types.ErrPrecompileFailed.Wrap(err.Error())
return nil, err
}

addrBz = addr.Bytes()
Expand All @@ -103,6 +105,13 @@ func (e *CosmosPrecompile) ExtendedRun(caller vm.ContractRef, input []byte, supp
}

if err != nil {
// convert cosmos error to EVM error
if err != vm.ErrOutOfGas {
resBz = types.NewRevertReason(err)
err = vm.ErrExecutionReverted
}

// revert the stateDB to the snapshot
e.stateDB.RevertToSnapshot(snapshot)
}
}()
Expand Down
Loading

0 comments on commit 967c549

Please sign in to comment.