Skip to content

Commit

Permalink
Merge PR: Worm/v1.2.0 merge pr2084 eip144 (#2178)
Browse files Browse the repository at this point in the history
* Merge PR: migrate EIP144 (#2084)

* migrate EIP144

* recover SetStorage

* no cache for eip144

* fix simulate bugs

* fix simulate bugs

* add eth call test

* unsupport multical

* remove check in apply func

* edit receiver for  OverrideBytes()

* rename simulateData

* add simulateWithOverrides path

* add handleSimulate

* applyOverrides only run in checktx mode

Co-authored-by: KamiD <[email protected]>

* edit makefile version to v1.2.3

* support multicall

* remove TestEth_Call_Overrides

* remove edits

Co-authored-by: KamiD <[email protected]>
  • Loading branch information
lcmmhcc and KamiD authored Jun 15, 2022
1 parent bd7b66c commit ee3ebfa
Show file tree
Hide file tree
Showing 17 changed files with 264 additions and 81 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ GithubTop=github.com



Version=v1.2.2
Version=v1.2.3
CosmosSDK=v0.39.2
Tendermint=v0.33.9
Iavl=v0.14.3
Expand Down
72 changes: 54 additions & 18 deletions app/rpc/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -800,8 +800,8 @@ func (api *PublicEthereumAPI) SendRawTransaction(data hexutil.Bytes) (common.Has
}

func (api *PublicEthereumAPI) buildKey(args rpctypes.CallArgs) common.Hash {
latest, e := api.wrappedBackend.GetLatestBlockNumber()
if e != nil {
latest, err := api.wrappedBackend.GetLatestBlockNumber()
if err != nil {
return common.Hash{}
}
return sha256.Sum256([]byte(args.String() + strconv.Itoa(int(latest))))
Expand Down Expand Up @@ -833,19 +833,28 @@ func (api *PublicEthereumAPI) addCallCache(key common.Hash, data []byte) {
}

// Call performs a raw contract call.
func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNrOrHash rpctypes.BlockNumberOrHash, _ *map[common.Address]rpctypes.Account) (hexutil.Bytes, error) {
func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNrOrHash rpctypes.BlockNumberOrHash, overrides *evmtypes.StateOverrides) (hexutil.Bytes, error) {
monitor := monitor.GetMonitor("eth_call", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("args", args, "block number", blockNrOrHash)
key := api.buildKey(args)
cacheData, ok := api.getFromCallCache(key)
if ok {
return cacheData, nil

if overrides != nil {
if err := overrides.Check(); err != nil {
return nil, err
}
}
var key common.Hash
if overrides == nil {
key = api.buildKey(args)
if cacheData, ok := api.getFromCallCache(key); ok {
return cacheData, nil
}
}

blockNr, err := api.backend.ConvertToBlockNumber(blockNrOrHash)
if err != nil {
return nil, err
}
simRes, err := api.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit), false)
simRes, err := api.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit), false, overrides)
if err != nil {
return []byte{}, TransformDataError(err, "eth_call")
}
Expand All @@ -854,12 +863,14 @@ func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNrOrHash rpctype
if err != nil {
return []byte{}, TransformDataError(err, "eth_call")
}
api.addCallCache(key, data.Ret)
if overrides == nil {
api.addCallCache(key, data.Ret)
}
return data.Ret, nil
}

// MultiCall performs multiple raw contract call.
func (api *PublicEthereumAPI) MultiCall(args []rpctypes.CallArgs, blockNr rpctypes.BlockNumber, _ *map[common.Address]rpctypes.Account) ([]hexutil.Bytes, error) {
func (api *PublicEthereumAPI) MultiCall(args []rpctypes.CallArgs, blockNr rpctypes.BlockNumber, _ *[]evmtypes.StateOverrides) ([]hexutil.Bytes, error) {
if !viper.GetBool(FlagEnableMultiCall) {
return nil, errors.New("the method is not allowed")
}
Expand All @@ -882,9 +893,13 @@ func (api *PublicEthereumAPI) MultiCall(args []rpctypes.CallArgs, blockNr rpctyp
// DoCall performs a simulated call operation through the evmtypes. It returns the
// estimated gas used on the operation or an error if fails.
func (api *PublicEthereumAPI) doCall(
args rpctypes.CallArgs, blockNum rpctypes.BlockNumber, globalGasCap *big.Int, isEstimate bool,
args rpctypes.CallArgs,
blockNum rpctypes.BlockNumber,
globalGasCap *big.Int,
isEstimate bool,
overrides *evmtypes.StateOverrides,
) (*sdk.SimulationResponse, error) {

var err error
clientCtx := api.clientCtx
// pass the given block height to the context if the height is not pending or latest
if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) {
Expand Down Expand Up @@ -934,11 +949,16 @@ func (api *PublicEthereumAPI) doCall(

// Create new call message
msg := evmtypes.NewMsgEthereumTx(nonce, args.To, value, gas, gasPrice, data)

var overridesBytes []byte
if overrides != nil {
if overridesBytes, err = overrides.GetBytes(); err != nil {
return nil, fmt.Errorf("fail to encode overrides")
}
}
sim := api.evmFactory.BuildSimulator(api)
//only worked when fast-query has been enabled
if sim != nil {
return sim.DoCall(msg, addr.String())
return sim.DoCall(msg, addr.String(), overridesBytes)
}

//Generate tx to be used to simulate (signature isn't needed)
Expand All @@ -957,11 +977,27 @@ func (api *PublicEthereumAPI) doCall(
if err != nil {
return nil, err
}

// Transaction simulation through query. only pass from when eth_estimateGas.
// eth_call's from maybe nil
simulatePath := fmt.Sprintf("app/simulate/%s", addr.String())
res, _, err := clientCtx.QueryWithData(simulatePath, txBytes)
var simulatePath string
var queryData []byte
if overrides != nil {
simulatePath = fmt.Sprintf("app/simulateWithOverrides/%s", addr.String())
queryOverridesData := sdk.SimulateData{
TxBytes: txBytes,
OverridesBytes: overridesBytes,
}
queryData, err = json.Marshal(queryOverridesData)
if err != nil {
return nil, fmt.Errorf("fail to encode queryData for simulateWithOverrides")
}

} else {
simulatePath = fmt.Sprintf("app/simulate/%s", addr.String())
queryData = txBytes
}

res, _, err := clientCtx.QueryWithData(simulatePath, queryData)
if err != nil {
return nil, err
}
Expand All @@ -981,7 +1017,7 @@ func (api *PublicEthereumAPI) EstimateGas(args rpctypes.CallArgs) (hexutil.Uint6
monitor := monitor.GetMonitor("eth_estimateGas", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("args", args)

simResponse, err := api.doCall(args, 0, big.NewInt(ethermint.DefaultRPCGasLimit), true)
simResponse, err := api.doCall(args, 0, big.NewInt(ethermint.DefaultRPCGasLimit), true, nil)
if err != nil {
return 0, TransformDataError(err, "eth_estimateGas")
}
Expand Down
5 changes: 4 additions & 1 deletion app/rpc/namespaces/eth/simulation/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ type EvmSimulator struct {
}

// DoCall call simulate tx. we pass the sender by args to reduce address convert
func (es *EvmSimulator) DoCall(msg *evmtypes.MsgEthereumTx, sender string) (*sdk.SimulationResponse, error) {
func (es *EvmSimulator) DoCall(msg *evmtypes.MsgEthereumTx, sender string, overridesBytes []byte) (*sdk.SimulationResponse, error) {
es.ctx = es.ctx.WithFrom(sender)
if overridesBytes != nil {
es.ctx.SetOverrideBytes(overridesBytes)
}
r, e := es.handler(es.ctx, msg)
if e != nil {
return nil, e
Expand Down
14 changes: 0 additions & 14 deletions app/rpc/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,6 @@ func (ca CallArgs) String() string {
return strings.TrimRight(arg, ", ")
}

// Account indicates the overriding fields of account during the execution of
// a message call.
// NOTE: state and stateDiff can't be specified at the same time. If state is
// set, message execution will only use the data in the given state. Otherwise
// if statDiff is set, all diff will be applied first and then execute the call
// message.
type Account struct {
Nonce *hexutil.Uint64 `json:"nonce"`
Code *hexutil.Bytes `json:"code"`
Balance **hexutil.Big `json:"balance"`
State *map[common.Hash]common.Hash `json:"state"`
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
}

// EthHeaderWithBlockHash represents a block header in the Ethereum blockchain with block hash generated from Tendermint Block
type EthHeaderWithBlockHash struct {
ParentHash common.Hash `json:"parentHash"`
Expand Down
78 changes: 43 additions & 35 deletions libs/cosmos-sdk/baseapp/abci.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package baseapp

import (
"encoding/json"
"fmt"
"os"
"sort"
Expand All @@ -11,6 +12,7 @@ import (
"time"

"github.com/okex/exchain/libs/cosmos-sdk/codec"
"github.com/okex/exchain/libs/cosmos-sdk/types"
sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
sdkerrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors"
"github.com/okex/exchain/libs/iavl"
Expand Down Expand Up @@ -176,7 +178,6 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc
return
}


func (app *BaseApp) addCommitTraceInfo() {
nodeReadCountStr := strconv.Itoa(app.cms.GetNodeReadCount())
dbReadCountStr := strconv.Itoa(app.cms.GetDBReadCount())
Expand Down Expand Up @@ -327,48 +328,55 @@ func (app *BaseApp) Query(req abci.RequestQuery) abci.ResponseQuery {

return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path"))
}
func handleSimulate(app *BaseApp, path []string, height int64, txBytes []byte, overrideBytes []byte) abci.ResponseQuery {
// if path contains address, it means 'eth_estimateGas' the sender
hasExtraPaths := len(path) > 2
var from string
if hasExtraPaths {
if addr, err := sdk.AccAddressFromBech32(path[2]); err == nil {
if err = sdk.VerifyAddressFormat(addr); err == nil {
from = path[2]
}
}
}
tx, err := app.txDecoder(txBytes)
if err != nil {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx"))
}
gInfo, res, err := app.Simulate(txBytes, tx, height, overrideBytes, from)

// if path contains mempool, it means to enable MaxGasUsedPerBlock
// return the actual gasUsed even though simulate tx failed
isMempoolSim := hasExtraPaths && path[2] == "mempool"
if err != nil && !isMempoolSim {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx"))
}

simRes := sdk.SimulationResponse{
GasInfo: gInfo,
Result: res,
}

return abci.ResponseQuery{
Codespace: sdkerrors.RootCodespace,
Height: height,
Value: codec.Cdc.MustMarshalBinaryBare(simRes),
}
}
func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
if len(path) >= 2 {
switch path[1] {
case "simulate":
txBytes := req.Data
return handleSimulate(app, path, req.Height, req.Data, nil)

tx, err := app.txDecoder(txBytes)
if err != nil {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx"))
}

// if path contains address, it means 'eth_estimateGas' the sender
hasExtraPaths := len(path) > 2
var from string
if hasExtraPaths {
if addr, err := sdk.AccAddressFromBech32(path[2]); err == nil {
if err = sdk.VerifyAddressFormat(addr); err == nil {
from = path[2]
}
}
}

gInfo, res, err := app.Simulate(txBytes, tx, req.Height, from)

// if path contains mempool, it means to enable MaxGasUsedPerBlock
// return the actual gasUsed even though simulate tx failed
isMempoolSim := hasExtraPaths && path[2] == "mempool"
if err != nil && !isMempoolSim {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx"))
case "simulateWithOverrides":
queryBytes := req.Data
var queryData types.SimulateData
if err := json.Unmarshal(queryBytes, &queryData); err != nil {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode simulateOverrideData"))
}
return handleSimulate(app, path, req.Height, queryData.TxBytes, queryData.OverridesBytes)

simRes := sdk.SimulationResponse{
GasInfo: gInfo,
Result: res,
}

return abci.ResponseQuery{
Codespace: sdkerrors.RootCodespace,
Height: req.Height,
Value: codec.Cdc.MustMarshalBinaryBare(simRes),
}
case "trace":
tmtx, err := GetABCITx(req.Data)
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion libs/cosmos-sdk/baseapp/baseapp_mode_simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package baseapp

import (
"fmt"

sdkerrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors"
tmtypes "github.com/okex/exchain/libs/tendermint/types"
)
Expand All @@ -19,6 +20,8 @@ func (m *modeHandlerSimulate) handleStartHeight(info *runTxInfo, height int64) e
} else {
info.ctx = app.getContextForTx(m.mode, info.txBytes)
}

if info.overridesBytes != nil {
info.ctx.SetOverrideBytes(info.overridesBytes)
}
return err
}
7 changes: 4 additions & 3 deletions libs/cosmos-sdk/baseapp/baseapp_runtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ type runTxInfo struct {
startingGas uint64
gInfo sdk.GasInfo

result *sdk.Result
txBytes []byte
tx sdk.Tx
result *sdk.Result
txBytes []byte
tx sdk.Tx
overridesBytes []byte
}

func (app *BaseApp) runTx(mode runTxMode,
Expand Down
4 changes: 2 additions & 2 deletions libs/cosmos-sdk/baseapp/baseapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -981,13 +981,13 @@ func TestSimulateTx(t *testing.T) {
require.Nil(t, err)

// simulate a message, check gas reported
gInfo, result, err := app.Simulate(txBytes, tx, 0)
gInfo, result, err := app.Simulate(txBytes, tx, 0, nil)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, gasConsumed, gInfo.GasUsed)

// simulate again, same result
gInfo, result, err = app.Simulate(txBytes, tx, 0)
gInfo, result, err = app.Simulate(txBytes, tx, 0, nil)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, gasConsumed, gInfo.GasUsed)
Expand Down
7 changes: 5 additions & 2 deletions libs/cosmos-sdk/baseapp/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ func (app *BaseApp) Check(tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) {
return info.gInfo, info.result, e
}

func (app *BaseApp) Simulate(txBytes []byte, tx sdk.Tx, height int64, from ...string) (sdk.GasInfo, *sdk.Result, error) {
info, e := app.runTx(runTxModeSimulate, txBytes, tx, height, from...)
func (app *BaseApp) Simulate(txBytes []byte, tx sdk.Tx, height int64, overridesBytes []byte, from ...string) (sdk.GasInfo, *sdk.Result, error) {
info := &runTxInfo{
overridesBytes: overridesBytes,
}
e := app.runtxWithInfo(info, runTxModeSimulate, txBytes, tx, height, from...)
return info.gInfo, info.result, e
}

Expand Down
2 changes: 1 addition & 1 deletion libs/cosmos-sdk/simapp/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func SignCheckDeliver(
require.Nil(t, err)

// Must simulate now as CheckTx doesn't run Msgs anymore
_, res, err := app.Simulate(txBytes, tx, 0)
_, res, err := app.Simulate(txBytes, tx, 0, nil)

if expSimPass {
require.NoError(t, err)
Expand Down
9 changes: 9 additions & 0 deletions libs/cosmos-sdk/types/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Context struct {
cache *Cache
trc *trace.Tracer
accountCache *AccountCache
overridesBytes []byte // overridesBytes is used to save overrides info, passed from ethCall to x/evm
}

// Proposed rename, not done to avoid API breakage
Expand Down Expand Up @@ -129,6 +130,10 @@ func (c *Context) GetToAccountCacheGas() Gas {
return c.accountCache.ToAccGotGas
}

func (c *Context) OverrideBytes() []byte {
return c.overridesBytes
}

func (c *Context) UpdateFromAccountCache(fromAcc interface{}, fromAccGettedGas Gas) {
if c.accountCache != nil {
c.accountCache.FromAcc = fromAcc
Expand Down Expand Up @@ -328,6 +333,10 @@ func (c Context) WithCache(cache *Cache) Context {
func (c *Context) IsZero() bool {
return c.ms == nil
}
func (c *Context) SetOverrideBytes(b []byte) *Context {
c.overridesBytes = b
return c
}

// WithValue is deprecated, provided for backwards compatibility
// Please use
Expand Down
Loading

0 comments on commit ee3ebfa

Please sign in to comment.