diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4e56494a..f5e5f675f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,8 +45,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (deps) [#1168](https://github.com/evmos/ethermint/pull/1168) Upgrade Cosmos SDK to `v0.46`. * (feemarket) [#1194](https://github.com/evmos/ethermint/pull/1194) Apply feemarket to native cosmos tx. * (eth) [#1346](https://github.com/evmos/ethermint/pull/1346) Added support for `sdk.Dec` and `ed25519` type on eip712. +* (eth) [#1430](https://github.com/evmos/ethermint/pull/1430) Added support for array of type `Any` on eip712.  * (ante) [1460](https://github.com/evmos/ethermint/pull/1460) Add KV Gas config on ethereum Txs. * (eth) [#1459](https://github.com/evmos/ethermint/pull/1459) Added support for messages with optional types omitted on eip712. +* (geth) [#1413](https://github.com/evmos/ethermint/pull/1413) Update geth version to v1.10.25. ### API Breaking diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 79cda75324..6baf11a3b9 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -420,7 +420,29 @@ func (suite AnteTestSuite) TestAnteHandler() { coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)) amount := sdk.NewCoins(coinAmount) gas := uint64(200000) - txBuilder := suite.CreateTestEIP712MsgEditValidator(from, privKey, "ethermint_9000-1", gas, amount) + txBuilder := suite.CreateTestEIP712MsgSubmitEvidence(from, privKey, "ethermint_9000-1", gas, amount) + return txBuilder.GetTx() + }, false, false, true, + }, + { + "success- DeliverTx EIP712 submit proposal v1", + func() sdk.Tx { + from := acc.GetAddress() + coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)) + amount := sdk.NewCoins(coinAmount) + gas := uint64(200000) + txBuilder := suite.CreateTestEIP712SubmitProposalV1(from, privKey, "ethermint_9000-1", gas, amount) + return txBuilder.GetTx() + }, false, false, true, + }, + { + "success- DeliverTx EIP712 MsgExec", + func() sdk.Tx { + from := acc.GetAddress() + coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)) + amount := sdk.NewCoins(coinAmount) + gas := uint64(200000) + txBuilder := suite.CreateTestEIP712MsgExec(from, privKey, "ethermint_9000-1", gas, amount) return txBuilder.GetTx() }, false, false, true, }, diff --git a/app/ante/eip712.go b/app/ante/eip712.go index 6367a02382..f12b96fe4d 100644 --- a/app/ante/eip712.go +++ b/app/ante/eip712.go @@ -15,9 +15,11 @@ import ( ethcrypto "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/secp256k1" + "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/evmos/ethermint/crypto/ethsecp256k1" "github.com/evmos/ethermint/ethereum/eip712" ethermint "github.com/evmos/ethermint/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" ) @@ -218,7 +220,7 @@ func VerifySignature( return sdkerrors.Wrap(err, "failed to pack tx data in EIP712 object") } - sigHash, err := eip712.ComputeTypedDataHash(typedData) + sigHash, _, err := apitypes.TypedDataAndHash(typedData) if err != nil { return err } diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index 22f3c2c6bc..5da28a3af3 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -16,6 +16,7 @@ import ( types2 "github.com/cosmos/cosmos-sdk/x/bank/types" types3 "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/evmos/ethermint/ethereum/eip712" "github.com/evmos/ethermint/types" @@ -37,6 +38,7 @@ import ( authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + authz "github.com/cosmos/cosmos-sdk/x/authz" cryptocodec "github.com/evmos/ethermint/crypto/codec" "github.com/evmos/ethermint/crypto/ethsecp256k1" @@ -365,6 +367,52 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgVoteV1(from sdk.AccAddress, priv return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgVote) } +func (suite *AnteTestSuite) CreateTestEIP712SubmitProposalV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder { + // Build V1 proposal messages. Must all be same-type, since EIP-712 + // does not support arrays of variable type. + authAcc := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx) + + proposal1, ok := types5.ContentFromProposalType("My proposal 1", "My description 1", types5.ProposalTypeText) + suite.Require().True(ok) + content1, err := govtypes.NewLegacyContent( + proposal1, + sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()), + ) + suite.Require().NoError(err) + + proposal2, ok := types5.ContentFromProposalType("My proposal 2", "My description 2", types5.ProposalTypeText) + suite.Require().True(ok) + content2, err := govtypes.NewLegacyContent( + proposal2, + sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()), + ) + suite.Require().NoError(err) + + proposalMsgs := []sdk.Msg{ + content1, + content2, + } + + // Build V1 proposal + msgProposal, err := govtypes.NewMsgSubmitProposal( + proposalMsgs, + sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100))), + sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), from.Bytes()), + "Metadata", + ) + + suite.Require().NoError(err) + + return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgProposal) +} + +func (suite *AnteTestSuite) CreateTestEIP712MsgExec(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder { + recipient := sdk.AccAddress(common.Address{}.Bytes()) + msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1)))) + msgExec := authz.NewMsgExec(from, []sdk.Msg{msgSend}) + return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, &msgExec) +} + // StdSignBytes returns the bytes to sign for a transaction. func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequence uint64, timeout uint64, fee legacytx.StdFee, msgs []sdk.Msg, memo string, tip *txtypes.Tip) []byte { msgsBytes := make([]json.RawMessage, 0, len(msgs)) @@ -431,7 +479,7 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder( }) suite.Require().NoError(err) - sigHash, err := eip712.ComputeTypedDataHash(typedData) + sigHash, _, err := apitypes.TypedDataAndHash(typedData) suite.Require().NoError(err) // Sign typedData diff --git a/docs/api/proto-docs.md b/docs/api/proto-docs.md index f2298082c9..722db9b51b 100644 --- a/docs/api/proto-docs.md +++ b/docs/api/proto-docs.md @@ -275,6 +275,7 @@ TraceConfig holds extra parameters to trace functions. | `overrides` | [ChainConfig](#ethermint.evm.v1.ChainConfig) | | Chain overrides, can be used to execute a trace using future fork rules | | `enable_memory` | [bool](#bool) | | enable memory capture | | `enable_return_data` | [bool](#bool) | | enable return data capture | +| `tracer_json_config` | [string](#string) | | tracer config | diff --git a/ethereum/eip712/eip712.go b/ethereum/eip712/eip712.go index 326c24e2c1..001225a414 100644 --- a/ethereum/eip712/eip712.go +++ b/ethereum/eip712/eip712.go @@ -21,28 +21,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/signer/core/apitypes" ) -// ComputeTypedDataHash computes keccak hash of typed data for signing. -func ComputeTypedDataHash(typedData apitypes.TypedData) ([]byte, error) { - domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) - if err != nil { - err = errorsmod.Wrap(err, "failed to pack and hash typedData EIP712Domain") - return nil, err - } - - typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) - if err != nil { - err = errorsmod.Wrap(err, "failed to pack and hash typedData primary type") - return nil, err - } - - rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) - return crypto.Keccak256(rawData), nil -} - // WrapTxToTypedData is an ultimate method that wraps Amino-encoded Cosmos Tx JSON data // into an EIP712-compatible TypedData request. func WrapTxToTypedData( @@ -207,7 +188,11 @@ func traverseFields( } for i := 0; i < n; i++ { - var field reflect.Value + var ( + field reflect.Value + err error + ) + if v.IsValid() { field = v.Field(i) } @@ -216,23 +201,10 @@ func traverseFields( fieldName := jsonNameFromTag(t.Field(i).Tag) if fieldType == cosmosAnyType { - any, ok := field.Interface().(*codectypes.Any) - if !ok { - return errorsmod.Wrapf(errortypes.ErrPackAny, "%T", field.Interface()) - } - - anyWrapper := &cosmosAnyWrapper{ - Type: any.TypeUrl, - } - - if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil { - return errorsmod.Wrap(err, "failed to unpack Any in msg struct") + // Unpack field, value as Any + if fieldType, field, err = unpackAny(cdc, field); err != nil { + return err } - - fieldType = reflect.TypeOf(anyWrapper) - field = reflect.ValueOf(anyWrapper) - - // then continue as normal } // If field is an empty value, do not include in types, since it will not be present in the object @@ -274,6 +246,12 @@ func traverseFields( fieldType = fieldType.Elem() field = field.Index(0) isCollection = true + + if fieldType == cosmosAnyType { + if fieldType, field, err = unpackAny(cdc, field); err != nil { + return err + } + } } for { @@ -364,6 +342,27 @@ func jsonNameFromTag(tag reflect.StructTag) string { return parts[0] } +// Unpack the given Any value with Type/Value deconstruction +func unpackAny(cdc codectypes.AnyUnpacker, field reflect.Value) (reflect.Type, reflect.Value, error) { + any, ok := field.Interface().(*codectypes.Any) + if !ok { + return nil, reflect.Value{}, errorsmod.Wrapf(errortypes.ErrPackAny, "%T", field.Interface()) + } + + anyWrapper := &cosmosAnyWrapper{ + Type: any.TypeUrl, + } + + if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil { + return nil, reflect.Value{}, errorsmod.Wrap(err, "failed to unpack Any in msg struct") + } + + fieldType := reflect.TypeOf(anyWrapper) + field = reflect.ValueOf(anyWrapper) + + return fieldType, field, nil +} + // _.foo_bar.baz -> TypeFooBarBaz // // this is needed for Geth's own signing code which doesn't diff --git a/go.mod b/go.mod index 7668f3e4c5..dccc235a8f 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/ibc-go/v5 v5.1.0 github.com/davecgh/go-spew v1.1.1 - github.com/ethereum/go-ethereum v1.10.19 + github.com/ethereum/go-ethereum v1.10.25 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index 031a2e5bbf..9bc32c4e34 100644 --- a/go.sum +++ b/go.sum @@ -274,8 +274,10 @@ github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6 github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= @@ -352,8 +354,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= -github.com/ethereum/go-ethereum v1.10.19 h1:EOR5JbL4MD5yeOqv8W2iC1s4NximrTjqFccUz8lyBRA= -github.com/ethereum/go-ethereum v1.10.19/go.mod h1:IJBNMtzKcNHPtllYihy6BL2IgK1u+32JriaTbdt4v+w= +github.com/ethereum/go-ethereum v1.10.25 h1:5dFrKJDnYf8L6/5o42abCE6a9yJm9cs4EJVRyYMr55s= +github.com/ethereum/go-ethereum v1.10.25/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= @@ -952,8 +954,10 @@ github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -1065,8 +1069,10 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -1076,6 +1082,7 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1706,7 +1713,6 @@ gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= diff --git a/gomod2nix.toml b/gomod2nix.toml index d0fc061f6b..5f4d2916d2 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -160,8 +160,8 @@ schema = 3 version = "v1.0.0" hash = "sha256-k1DYvCqO3BKNcGEve/nMW0RxzMkK2tGfXbUbycqcVSo=" [mod."github.com/ethereum/go-ethereum"] - version = "v1.10.19" - hash = "sha256-7FPnTGcCb8Xd1QVR+6PmGTaHdTY1mm/8osFTW1JLuG8=" + version = "v1.10.25" + hash = "sha256-tNlI2XyuTXjGuBoe5vlYDcaGN2Sub7yltVtI6TeLLSc=" [mod."github.com/felixge/httpsnoop"] version = "v1.0.1" hash = "sha256-TNXnnC/ZGNY9lInAcES1cBGqIdEljKuh5LH/khVFjVk=" diff --git a/nix/go-ethereum.nix b/nix/go-ethereum.nix index 259939fe37..6c2ec2c891 100644 --- a/nix/go-ethereum.nix +++ b/nix/go-ethereum.nix @@ -1,4 +1,4 @@ -{ lib, stdenv, buildGoModule, fetchFromGitHub, libobjc, IOKit }: +{ lib, stdenv, buildGoModule, fetchFromGitHub, libobjc, IOKit, nixosTests }: let # A list of binaries to put into separate outputs @@ -7,19 +7,18 @@ let "clef" ]; -in -buildGoModule rec { +in buildGoModule rec { pname = "go-ethereum"; - version = "1.10.19"; + version = "1.10.25"; src = fetchFromGitHub { owner = "ethereum"; repo = pname; rev = "v${version}"; - sha256 = "0f6n9rg42ph47mvykc9f0lf99yzwqy4jm7mlzyks4l6i6fl1g3q1"; + sha256 = "sha256-mnf0kMfQEEQMricZJfyF7ZB/2F1dyPBx9iT2v/rGh1U="; }; - vendorSha256 = "1s5yfpk2yn7f3zwjl2fdrh6c63ki2b8rlmnlss27yxibsidaj0yd"; + vendorSha256 = "sha256-Dj+xN8lr98LJyYr2FwJ7yUIJkUeUrr1fkcbj4hShJI0="; doCheck = false; @@ -47,14 +46,19 @@ buildGoModule rec { "cmd/utils" ]; + # Following upstream: https://github.com/ethereum/go-ethereum/blob/v1.10.25/build/ci.go#L218 + tags = [ "urfave_cli_no_docs" ]; + # Fix for usb-related segmentation faults on darwin propagatedBuildInputs = lib.optionals stdenv.isDarwin [ libobjc IOKit ]; + passthru.tests = { inherit (nixosTests) geth; }; + meta = with lib; { homepage = "https://geth.ethereum.org/"; description = "Official golang implementation of the Ethereum protocol"; license = with licenses; [ lgpl3Plus gpl3Plus ]; - maintainers = with maintainers; [ adisbladis lionello RaghavSood ]; + maintainers = with maintainers; [ adisbladis RaghavSood ]; }; -} +} \ No newline at end of file diff --git a/proto/ethermint/evm/v1/evm.proto b/proto/ethermint/evm/v1/evm.proto index a66af799f1..02c2d62b6a 100644 --- a/proto/ethermint/evm/v1/evm.proto +++ b/proto/ethermint/evm/v1/evm.proto @@ -224,5 +224,7 @@ message TraceConfig { // enable memory capture bool enable_memory = 11 [(gogoproto.jsontag) = "enableMemory"]; // enable return data capture - bool enable_return_data = 12 [(gogoproto.jsontag) = "enableReturnData"]; + bool enable_return_data = 12 [ (gogoproto.jsontag) = "enableReturnData" ]; + // tracer config + string tracer_json_config = 13 [ (gogoproto.jsontag) = "tracerConfig" ]; } diff --git a/rpc/backend/account_info_test.go b/rpc/backend/account_info_test.go index e0c95c664f..4382c54a12 100644 --- a/rpc/backend/account_info_test.go +++ b/rpc/backend/account_info_test.go @@ -103,6 +103,18 @@ func (suite *BackendTestSuite) TestGetProof() { false, &rpctypes.AccountResult{}, }, + { + "fail - Block doesn't exist)", + address1, + []string{}, + rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid}, + func(bn rpctypes.BlockNumber, addr common.Address) { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockError(client, bn.Int64()) + }, + false, + &rpctypes.AccountResult{}, + }, { "pass", address1, @@ -351,6 +363,27 @@ func (suite *BackendTestSuite) TestGetTransactionCount() { true, hexutil.Uint64(0), }, + // TODO: Error mocking the GetAccount call - problem with Any type + //{ + // "pass - returns the number of transactions at the given address up to the given block number", + // true, + // rpctypes.NewBlockNumber(big.NewInt(1)), + // func(addr common.Address, bn rpctypes.BlockNumber) { + // client := suite.backend.clientCtx.Client.(*mocks.Client) + // account, err := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, suite.acc) + // suite.Require().NoError(err) + // request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(suite.acc.Bytes()).String()} + // requestMarshal, _ := request.Marshal() + // RegisterABCIQueryAccount( + // client, + // requestMarshal, + // tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false}, + // account, + // ) + // }, + // true, + // hexutil.Uint64(0), + //}, } for _, tc := range testCases { suite.Run(fmt.Sprintf("Case %s", tc.name), func() { diff --git a/rpc/backend/backend.go b/rpc/backend/backend.go index edc891ad34..3dd45e451a 100644 --- a/rpc/backend/backend.go +++ b/rpc/backend/backend.go @@ -6,7 +6,6 @@ import ( "time" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,12 +15,10 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/signer/core/apitypes" - "github.com/evmos/ethermint/crypto/hd" rpctypes "github.com/evmos/ethermint/rpc/types" "github.com/evmos/ethermint/server/config" ethermint "github.com/evmos/ethermint/types" evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/log" tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" ) @@ -162,23 +159,6 @@ func NewBackend( panic(err) } - algos, _ := clientCtx.Keyring.SupportedAlgorithms() - if !algos.Contains(hd.EthSecp256k1) { - kr, err := keyring.New( - sdk.KeyringServiceName(), - viper.GetString(flags.FlagKeyringBackend), - clientCtx.KeyringDir, - clientCtx.Input, - clientCtx.Codec, - hd.EthSecp256k1Option(), - ) - if err != nil { - panic(err) - } - - clientCtx = clientCtx.WithKeyring(kr) - } - return &Backend{ ctx: context.Background(), clientCtx: clientCtx, diff --git a/rpc/backend/backend_suite_test.go b/rpc/backend/backend_suite_test.go index 7bc798b99e..bdbb8f41a3 100644 --- a/rpc/backend/backend_suite_test.go +++ b/rpc/backend/backend_suite_test.go @@ -3,6 +3,7 @@ package backend import ( "bufio" "fmt" + "github.com/evmos/ethermint/crypto/ethsecp256k1" "math/big" "os" "path/filepath" @@ -33,6 +34,7 @@ type BackendTestSuite struct { suite.Suite backend *Backend acc sdk.AccAddress + signer keyring.Signer } func TestBackendTestSuite(t *testing.T) { @@ -61,6 +63,10 @@ func (suite *BackendTestSuite) SetupTest() { Seq: uint64(1), } + priv, err := ethsecp256k1.GenerateKey() + suite.signer = tests.NewSigner(priv) + suite.Require().NoError(err) + encodingConfig := encoding.MakeConfig(app.ModuleBasics) clientCtx := client.Context{}.WithChainID("ethermint_9000-1"). WithHeight(1). @@ -70,13 +76,18 @@ func (suite *BackendTestSuite) SetupTest() { WithAccountRetriever(client.TestAccountRetriever{Accounts: accounts}) allowUnprotectedTxs := false - idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx) suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer) suite.backend.queryClient.QueryClient = mocks.NewEVMQueryClient(suite.T()) suite.backend.clientCtx.Client = mocks.NewClient(suite.T()) + suite.backend.queryClient.FeeMarket = mocks.NewFeeMarketQueryClient(suite.T()) suite.backend.ctx = rpctypes.ContextWithHeight(1) + + // Add codec + encCfg := encoding.MakeConfig(app.ModuleBasics) + suite.backend.clientCtx.Codec = encCfg.Codec + } // buildEthereumTx returns an example legacy Ethereum transaction @@ -132,6 +143,7 @@ func (suite *BackendTestSuite) buildFormattedBlock( uint64(header.Height), uint64(0), baseFee, + suite.backend.chainID, ) suite.Require().NoError(err) ethRPCTxs = []interface{}{rpcTx} @@ -157,3 +169,25 @@ func (suite *BackendTestSuite) generateTestKeyring(clientDir string) (keyring.Ke encCfg := encoding.MakeConfig(app.ModuleBasics) return keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, encCfg.Codec, []keyring.Option{hd.EthSecp256k1Option()}...) } + +func (suite *BackendTestSuite) signAndEncodeEthTx(msgEthereumTx *evmtypes.MsgEthereumTx) []byte { + from, priv := tests.NewAddrKey() + signer := tests.NewSigner(priv) + + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParamsWithoutHeader(queryClient, 1) + + ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig()) + msgEthereumTx.From = from.String() + err := msgEthereumTx.Sign(ethSigner, signer) + suite.Require().NoError(err) + + tx, err := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") + suite.Require().NoError(err) + + txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder() + txBz, err := txEncoder(tx) + suite.Require().NoError(err) + + return txBz +} diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index b2cd8bd1a0..a28ae6ff73 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -376,6 +376,7 @@ func (b *Backend) RPCBlockFromTendermintBlock( uint64(block.Height), uint64(txIndex), baseFee, + b.chainID, ) if err != nil { b.logger.Debug("NewTransactionFromData for receipt failed", "hash", tx.Hash().Hex(), "error", err.Error()) diff --git a/rpc/backend/blocks_test.go b/rpc/backend/blocks_test.go index 7ac7aeca09..36d74d8b53 100644 --- a/rpc/backend/blocks_test.go +++ b/rpc/backend/blocks_test.go @@ -30,8 +30,8 @@ func (suite *BackendTestSuite) TestBlockNumber() { { "fail - invalid block header height", func() { - height := int64(1) var header metadata.MD + height := int64(1) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) RegisterParamsInvalidHeight(queryClient, &header, int64(height)) }, @@ -41,8 +41,8 @@ func (suite *BackendTestSuite) TestBlockNumber() { { "fail - invalid block header", func() { - height := int64(1) var header metadata.MD + height := int64(1) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) RegisterParamsInvalidHeader(queryClient, &header, int64(height)) }, @@ -52,8 +52,8 @@ func (suite *BackendTestSuite) TestBlockNumber() { { "pass - app state header height 1", func() { - height := int64(1) var header metadata.MD + height := int64(1) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) RegisterParams(queryClient, &header, int64(height)) }, @@ -552,8 +552,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() { "fail - blockNum < 0 with app state height error", ethrpc.BlockNumber(-1), func(_ ethrpc.BlockNumber) { - appHeight := int64(1) var header metadata.MD + appHeight := int64(1) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) RegisterParamsError(queryClient, &header, appHeight) }, @@ -564,8 +564,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() { "pass - blockNum < 0 with app state height >= 1", ethrpc.BlockNumber(-1), func(blockNum ethrpc.BlockNumber) { - appHeight := int64(1) var header metadata.MD + appHeight := int64(1) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) RegisterParams(queryClient, &header, appHeight) @@ -1088,6 +1088,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() { uint64(header.Height), uint64(0), tc.baseFee, + suite.backend.chainID, ) suite.Require().NoError(err) ethRPCTxs = []interface{}{rpcTx} diff --git a/rpc/backend/call_tx_test.go b/rpc/backend/call_tx_test.go new file mode 100644 index 0000000000..a83e226d12 --- /dev/null +++ b/rpc/backend/call_tx_test.go @@ -0,0 +1,484 @@ +package backend + +import ( + "encoding/json" + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rlp" + "github.com/evmos/ethermint/rpc/backend/mocks" + rpctypes "github.com/evmos/ethermint/rpc/types" + "github.com/evmos/ethermint/tests" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "google.golang.org/grpc/metadata" + "math/big" +) + +func (suite *BackendTestSuite) TestResend() { + txNonce := (hexutil.Uint64)(1) + baseFee := sdk.NewInt(1) + gasPrice := new(hexutil.Big) + toAddr := tests.GenerateAddress() + callArgs := evmtypes.TransactionArgs{ + From: nil, + To: &toAddr, + Gas: nil, + GasPrice: nil, + MaxFeePerGas: gasPrice, + MaxPriorityFeePerGas: gasPrice, + Value: gasPrice, + Nonce: nil, + Input: nil, + Data: nil, + AccessList: nil, + } + + testCases := []struct { + name string + registerMock func() + args evmtypes.TransactionArgs + gasPrice *hexutil.Big + gasLimit *hexutil.Uint64 + expHash common.Hash + expPass bool + }{ + { + "fail - Missing transaction nonce ", + func() {}, + evmtypes.TransactionArgs{ + Nonce: nil, + }, + nil, + nil, + common.Hash{}, + false, + }, + { + "pass - Can't set Tx defaults BaseFee disabled", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFeeDisabled(queryClient) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + }, + nil, + nil, + common.Hash{}, + true, + }, + { + "pass - Can't set Tx defaults ", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient) + RegisterParams(queryClient, &header, 1) + RegisterFeeMarketParams(feeMarketClient, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + }, + nil, + nil, + common.Hash{}, + true, + }, + { + "pass - MaxFeePerGas is nil", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFeeDisabled(queryClient) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + MaxPriorityFeePerGas: nil, + GasPrice: nil, + MaxFeePerGas: nil, + }, + nil, + nil, + common.Hash{}, + true, + }, + { + "fail - GasPrice and (MaxFeePerGas or MaxPriorityPerGas specified", + func() {}, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + MaxPriorityFeePerGas: nil, + GasPrice: gasPrice, + MaxFeePerGas: gasPrice, + }, + nil, + nil, + common.Hash{}, + false, + }, + { + "fail - Block error", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParams(queryClient, &header, 1) + RegisterBlockError(client, 1) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + }, + nil, + nil, + common.Hash{}, + false, + }, + { + "pass - MaxFeePerGas is nil", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + GasPrice: nil, + MaxPriorityFeePerGas: gasPrice, + MaxFeePerGas: gasPrice, + }, + nil, + nil, + common.Hash{}, + true, + }, + { + "pass - Chain Id is nil", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + MaxPriorityFeePerGas: gasPrice, + ChainID: nil, + }, + nil, + nil, + common.Hash{}, + true, + }, + { + "fail - Pending transactions error", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + RegisterEstimateGas(queryClient, callArgs) + RegisterParams(queryClient, &header, 1) + RegisterParamsWithoutHeader(queryClient, 1) + RegisterUnconfirmedTxsError(client, nil) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + To: &toAddr, + MaxFeePerGas: gasPrice, + MaxPriorityFeePerGas: gasPrice, + Gas: nil, + }, + gasPrice, + nil, + common.Hash{}, + false, + }, + { + "fail - Not Ethereum txs", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + RegisterEstimateGas(queryClient, callArgs) + RegisterParams(queryClient, &header, 1) + RegisterParamsWithoutHeader(queryClient, 1) + RegisterUnconfirmedTxsEmpty(client, nil) + }, + evmtypes.TransactionArgs{ + Nonce: &txNonce, + To: &toAddr, + MaxFeePerGas: gasPrice, + MaxPriorityFeePerGas: gasPrice, + Gas: nil, + }, + gasPrice, + nil, + common.Hash{}, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + hash, err := suite.backend.Resend(tc.args, tc.gasPrice, tc.gasLimit) + + if tc.expPass { + suite.Require().Equal(tc.expHash, hash) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestSendRawTransaction() { + ethTx, bz := suite.buildEthereumTx() + rlpEncodedBz, _ := rlp.EncodeToBytes(ethTx.AsTransaction()) + cosmosTx, _ := ethTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") + txBytes, _ := suite.backend.clientCtx.TxConfig.TxEncoder()(cosmosTx) + + testCases := []struct { + name string + registerMock func() + rawTx []byte + expHash common.Hash + expPass bool + }{ + { + "fail - empty bytes", + func() {}, + []byte{}, + common.Hash{}, + false, + }, + { + "fail - no RLP encoded bytes", + func() {}, + bz, + common.Hash{}, + false, + }, + { + "fail - unprotected transactions", + func() { + suite.backend.allowUnprotectedTxs = false + }, + rlpEncodedBz, + common.Hash{}, + false, + }, + { + "fail - failed to get evm params", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + suite.backend.allowUnprotectedTxs = true + RegisterParamsWithoutHeaderError(queryClient, 1) + }, + rlpEncodedBz, + common.Hash{}, + false, + }, + { + "fail - failed to broadcast transaction", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + suite.backend.allowUnprotectedTxs = true + RegisterParamsWithoutHeader(queryClient, 1) + RegisterBroadcastTxError(client, txBytes) + }, + rlpEncodedBz, + common.HexToHash(ethTx.Hash), + false, + }, + { + "pass - Gets the correct transaction hash of the eth transaction", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + suite.backend.allowUnprotectedTxs = true + RegisterParamsWithoutHeader(queryClient, 1) + RegisterBroadcastTx(client, txBytes) + }, + rlpEncodedBz, + common.HexToHash(ethTx.Hash), + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + hash, err := suite.backend.SendRawTransaction(tc.rawTx) + + if tc.expPass { + suite.Require().Equal(tc.expHash, hash) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestDoCall() { + _, bz := suite.buildEthereumTx() + gasPrice := (*hexutil.Big)(big.NewInt(1)) + toAddr := tests.GenerateAddress() + callArgs := evmtypes.TransactionArgs{ + From: nil, + To: &toAddr, + Gas: nil, + GasPrice: nil, + MaxFeePerGas: gasPrice, + MaxPriorityFeePerGas: gasPrice, + Value: gasPrice, + Input: nil, + Data: nil, + AccessList: nil, + } + argsBz, err := json.Marshal(callArgs) + suite.Require().NoError(err) + + testCases := []struct { + name string + registerMock func() + blockNum rpctypes.BlockNumber + callArgs evmtypes.TransactionArgs + expEthTx *evmtypes.MsgEthereumTxResponse + expPass bool + }{ + { + "fail - Invalid request", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, bz) + RegisterEthCallError(queryClient, &evmtypes.EthCallRequest{Args: argsBz}) + }, + + rpctypes.BlockNumber(1), + callArgs, + &evmtypes.MsgEthereumTxResponse{}, + false, + }, + { + "pass - Returned transaction response", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, bz) + RegisterEthCall(queryClient, &evmtypes.EthCallRequest{Args: argsBz}) + }, + + rpctypes.BlockNumber(1), + callArgs, + &evmtypes.MsgEthereumTxResponse{}, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + msgEthTx, err := suite.backend.DoCall(tc.callArgs, tc.blockNum) + + if tc.expPass { + suite.Require().Equal(tc.expEthTx, msgEthTx) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGasPrice() { + defaultGasPrice := (*hexutil.Big)(big.NewInt(1)) + + testCases := []struct { + name string + registerMock func() + expGas *hexutil.Big + expPass bool + }{ + { + "pass - get the default gas price", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient) + RegisterFeeMarketParams(feeMarketClient, 1) + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + }, + defaultGasPrice, + true, + }, + { + "fail - can't get gasFee, FeeMarketParams error", + func() { + var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient) + RegisterFeeMarketParamsError(feeMarketClient, 1) + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + }, + defaultGasPrice, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + gasPrice, err := suite.backend.GasPrice() + if tc.expPass { + suite.Require().Equal(tc.expGas, gasPrice) + } else { + suite.Require().Error(err) + } + }) + } + +} diff --git a/rpc/backend/chain_info.go b/rpc/backend/chain_info.go index 33954aa23a..75e485c001 100644 --- a/rpc/backend/chain_info.go +++ b/rpc/backend/chain_info.go @@ -153,11 +153,13 @@ func (b *Backend) FeeHistory( } blockEnd = int64(blockNumber) } + userBlockCountInt := int64(userBlockCount) maxBlockCount := int64(b.cfg.JSONRPC.FeeHistoryCap) if userBlockCountInt > maxBlockCount { return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", userBlockCountInt, maxBlockCount) } + blockStart := blockEnd - userBlockCountInt if blockStart < 0 { blockStart = 0 @@ -173,6 +175,7 @@ func (b *Backend) FeeHistory( for i := 0; i < int(blockCount); i++ { reward[i] = make([]*hexutil.Big, rewardCount) } + thisBaseFee := make([]*hexutil.Big, blockCount) thisGasUsedRatio := make([]float64, blockCount) diff --git a/rpc/backend/chain_info_test.go b/rpc/backend/chain_info_test.go index d30159cb08..2a45cbc1a5 100644 --- a/rpc/backend/chain_info_test.go +++ b/rpc/backend/chain_info_test.go @@ -4,6 +4,12 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/common/hexutil" + ethrpc "github.com/ethereum/go-ethereum/rpc" + rpc "github.com/evmos/ethermint/rpc/types" + "github.com/evmos/ethermint/tests" + "google.golang.org/grpc/metadata" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/abci/types" tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" @@ -144,3 +150,297 @@ func (suite *BackendTestSuite) TestBaseFee() { }) } } + +func (suite *BackendTestSuite) TestChainId() { + expChainId := (*hexutil.Big)(big.NewInt(9000)) + testCases := []struct { + name string + registerMock func() + expChainId *hexutil.Big + expPass bool + }{ + { + "pass - block is at or past the EIP-155 replay-protection fork block, return chainID from config ", + func() { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParamsInvalidHeight(queryClient, &header, int64(1)) + + }, + expChainId, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + chainId, err := suite.backend.ChainID() + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expChainId, chainId) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetCoinbase() { + validatorAcc := sdk.AccAddress(tests.GenerateAddress().Bytes()) + testCases := []struct { + name string + registerMock func() + accAddr sdk.AccAddress + expPass bool + }{ + { + "fail - Can't retrieve status from node", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterStatusError(client) + }, + validatorAcc, + false, + }, + { + "fail - Can't query validator account", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterStatus(client) + RegisterValidatorAccountError(queryClient) + }, + validatorAcc, + false, + }, + { + "pass - Gets coinbase account", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterStatus(client) + RegisterValidatorAccount(queryClient, validatorAcc) + }, + validatorAcc, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + accAddr, err := suite.backend.GetCoinbase() + + if tc.expPass { + suite.Require().Equal(tc.accAddr, accAddr) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestSuggestGasTipCap() { + testCases := []struct { + name string + registerMock func() + baseFee *big.Int + expGasTipCap *big.Int + expPass bool + }{ + { + "pass - London hardfork not enabled or feemarket not enabled ", + func() {}, + nil, + big.NewInt(0), + true, + }, + { + "pass - Gets the suggest gas tip cap ", + func() {}, + nil, + big.NewInt(0), + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + maxDelta, err := suite.backend.SuggestGasTipCap(tc.baseFee) + + if tc.expPass { + suite.Require().Equal(tc.expGasTipCap, maxDelta) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGlobalMinGasPrice() { + testCases := []struct { + name string + registerMock func() + expMinGasPrice sdk.Dec + expPass bool + }{ + { + "fail - Can't get FeeMarket params", + func() { + feeMarketCleint := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient) + RegisterFeeMarketParamsError(feeMarketCleint, int64(1)) + }, + sdk.ZeroDec(), + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + globalMinGasPrice, err := suite.backend.GlobalMinGasPrice() + + if tc.expPass { + suite.Require().Equal(tc.expMinGasPrice, globalMinGasPrice) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestFeeHistory() { + testCases := []struct { + name string + registerMock func(validator sdk.AccAddress) + userBlockCount ethrpc.DecimalOrHex + latestBlock ethrpc.BlockNumber + expFeeHistory *rpc.FeeHistoryResult + validator sdk.AccAddress + expPass bool + }{ + { + "fail - can't get params ", + func(validator sdk.AccAddress) { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + suite.backend.cfg.JSONRPC.FeeHistoryCap = 0 + RegisterParamsError(queryClient, &header, ethrpc.BlockNumber(1).Int64()) + }, + 1, + 0, + nil, + nil, + false, + }, + { + "fail - user block count higher than max block count ", + func(validator sdk.AccAddress) { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + suite.backend.cfg.JSONRPC.FeeHistoryCap = 0 + RegisterParams(queryClient, &header, ethrpc.BlockNumber(1).Int64()) + }, + 1, + 0, + nil, + nil, + false, + }, + { + "fail - Tendermint block fetching error ", + func(validator sdk.AccAddress) { + client := suite.backend.clientCtx.Client.(*mocks.Client) + suite.backend.cfg.JSONRPC.FeeHistoryCap = 2 + RegisterBlockError(client, ethrpc.BlockNumber(1).Int64()) + }, + 1, + 1, + nil, + nil, + false, + }, + { + "fail - Eth block fetching error", + func(validator sdk.AccAddress) { + client := suite.backend.clientCtx.Client.(*mocks.Client) + suite.backend.cfg.JSONRPC.FeeHistoryCap = 2 + RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil) + RegisterBlockResultsError(client, 1) + }, + 1, + 1, + nil, + nil, + true, + }, + { + "fail - Invalid base fee", + func(validator sdk.AccAddress) { + //baseFee := sdk.NewInt(1) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + suite.backend.cfg.JSONRPC.FeeHistoryCap = 2 + RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil) + RegisterBlockResults(client, 1) + RegisterBaseFeeError(queryClient) + RegisterValidatorAccount(queryClient, validator) + RegisterConsensusParams(client, 1) + }, + 1, + 1, + nil, + sdk.AccAddress(tests.GenerateAddress().Bytes()), + false, + }, + { + "pass - Valid FeeHistoryResults object", + func(validator sdk.AccAddress) { + baseFee := sdk.NewInt(1) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + suite.backend.cfg.JSONRPC.FeeHistoryCap = 2 + RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + RegisterValidatorAccount(queryClient, validator) + RegisterConsensusParams(client, 1) + }, + 1, + 1, + &rpc.FeeHistoryResult{ + OldestBlock: (*hexutil.Big)(big.NewInt(0)), + BaseFee: []*hexutil.Big{(*hexutil.Big)(big.NewInt(1))}, + GasUsedRatio: []float64{0}, + Reward: [][]*hexutil.Big{{(*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0))}}, + }, + sdk.AccAddress(tests.GenerateAddress().Bytes()), + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock(tc.validator) + + feeHistory, err := suite.backend.FeeHistory(tc.userBlockCount, tc.latestBlock, []float64{25, 50, 75, 100}) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(feeHistory, tc.expFeeHistory) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/rpc/backend/client_test.go b/rpc/backend/client_test.go index 4716e312fc..9fafb8bae6 100644 --- a/rpc/backend/client_test.go +++ b/rpc/backend/client_test.go @@ -2,12 +2,15 @@ package backend import ( "context" - "testing" - + "github.com/cosmos/cosmos-sdk/client" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" "github.com/evmos/ethermint/rpc/backend/mocks" rpc "github.com/evmos/ethermint/rpc/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" mock "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -15,6 +18,7 @@ import ( tmrpcclient "github.com/tendermint/tendermint/rpc/client" tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/types" + "testing" ) // Client defines a mocked object that implements the Tendermint JSON-RPC Client @@ -24,7 +28,74 @@ import ( // To use a mock method it has to be registered in a given test. var _ tmrpcclient.Client = &mocks.Client{} +// Tx Search +func RegisterTxSearch(client *mocks.Client, query string, txBz []byte) { + resulTxs := []*tmrpctypes.ResultTx{{Tx: txBz}} + client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), ""). + Return(&tmrpctypes.ResultTxSearch{Txs: resulTxs, TotalCount: 1}, nil) +} + +func RegisterTxSearchEmpty(client *mocks.Client, query string) { + client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), ""). + Return(&tmrpctypes.ResultTxSearch{}, nil) +} + +func RegisterTxSearchError(client *mocks.Client, query string) { + client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), ""). + Return(nil, errortypes.ErrInvalidRequest) +} + +// Broadcast Tx +func RegisterBroadcastTx(client *mocks.Client, tx types.Tx) { + client.On("BroadcastTxSync", context.Background(), tx). + Return(&tmrpctypes.ResultBroadcastTx{}, nil) +} + +func RegisterBroadcastTxError(client *mocks.Client, tx types.Tx) { + client.On("BroadcastTxSync", context.Background(), tx). + Return(nil, errortypes.ErrInvalidRequest) +} + +// Unconfirmed Transactions +func RegisterUnconfirmedTxs(client *mocks.Client, limit *int, txs []types.Tx) { + client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit). + Return(&tmrpctypes.ResultUnconfirmedTxs{Txs: txs}, nil) +} + +func RegisterUnconfirmedTxsEmpty(client *mocks.Client, limit *int) { + client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit). + Return(&tmrpctypes.ResultUnconfirmedTxs{ + Txs: make([]types.Tx, 2), + }, nil) +} + +func RegisterUnconfirmedTxsError(client *mocks.Client, limit *int) { + client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit). + Return(nil, errortypes.ErrInvalidRequest) +} + +// Status +func RegisterStatus(client *mocks.Client) { + client.On("Status", rpc.ContextWithHeight(1)). + Return(&tmrpctypes.ResultStatus{}, nil) +} + +func RegisterStatusError(client *mocks.Client) { + client.On("Status", rpc.ContextWithHeight(1)). + Return(nil, errortypes.ErrInvalidRequest) +} + // Block +func RegisterBlockMultipleTxs( + client *mocks.Client, + height int64, + txs []types.Tx, +) (*tmrpctypes.ResultBlock, error) { + block := types.MakeBlock(height, txs, nil, nil) + resBlock := &tmrpctypes.ResultBlock{Block: block} + client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil) + return resBlock, nil +} func RegisterBlock( client *mocks.Client, height int64, @@ -34,16 +105,14 @@ func RegisterBlock( if tx == nil { emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil) resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock} - client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")). - Return(resBlock, nil) + client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil) return resBlock, nil } // with tx block := types.MakeBlock(height, []types.Tx{tx}, nil, nil) resBlock := &tmrpctypes.ResultBlock{Block: block} - client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")). - Return(resBlock, nil) + client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil) return resBlock, nil } @@ -101,6 +170,26 @@ func TestRegisterConsensusParams(t *testing.T) { } // BlockResults + +func RegisterBlockResultsWithEventLog(client *mocks.Client, height int64) (*tmrpctypes.ResultBlockResults, error) { + res := &tmrpctypes.ResultBlockResults{ + Height: height, + TxsResults: []*abci.ResponseDeliverTx{ + {Code: 0, GasUsed: 0, Events: []abci.Event{{ + Type: evmtypes.EventTypeTxLog, + Attributes: []abci.EventAttribute{{ + Key: []byte(evmtypes.AttributeKeyTxLog), + Value: []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}, // Represents {"test": "hello"} + Index: true, + }}, + }}}, + }, + } + client.On("BlockResults", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")). + Return(res, nil) + return res, nil +} + func RegisterBlockResults( client *mocks.Client, height int64, @@ -167,3 +256,22 @@ func RegisterABCIQueryWithOptions(client *mocks.Client, height int64, path strin }, }, nil) } + +func RegisterABCIQueryWithOptionsError(clients *mocks.Client, path string, data bytes.HexBytes, opts tmrpcclient.ABCIQueryOptions) { + clients.On("ABCIQueryWithOptions", context.Background(), path, data, opts). + Return(nil, errortypes.ErrInvalidRequest) +} + +func RegisterABCIQueryAccount(clients *mocks.Client, data bytes.HexBytes, opts tmrpcclient.ABCIQueryOptions, acc client.Account) { + baseAccount := authtypes.NewBaseAccount(acc.GetAddress(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) + accAny, _ := codectypes.NewAnyWithValue(baseAccount) + accResponse := authtypes.QueryAccountResponse{Account: accAny} + respBz, _ := accResponse.Marshal() + clients.On("ABCIQueryWithOptions", context.Background(), "/cosmos.auth.v1beta1.Query/Account", data, opts). + Return(&tmrpctypes.ResultABCIQuery{ + Response: abci.ResponseQuery{ + Value: respBz, + Height: 1, + }, + }, nil) +} diff --git a/rpc/backend/evm_query_client_test.go b/rpc/backend/evm_query_client_test.go index 45585c8449..5e735cc0bb 100644 --- a/rpc/backend/evm_query_client_test.go +++ b/rpc/backend/evm_query_client_test.go @@ -1,10 +1,9 @@ package backend import ( + "context" + "encoding/json" "fmt" - "strconv" - "testing" - sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" @@ -19,6 +18,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "strconv" + "testing" ) // QueryClient defines a mocked object that implements the ethermint GRPC @@ -28,6 +29,38 @@ import ( // To use a mock method it has to be registered in a given test. var _ evmtypes.QueryClient = &mocks.EVMQueryClient{} +// TraceTransaction +func RegisterTraceTransactionWithPredecessors(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx, predecessors []*evmtypes.MsgEthereumTx) { + data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d} + queryClient.On("TraceTx", rpc.ContextWithHeight(1), + &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1, Predecessors: predecessors}). + Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil) +} + +func RegisterTraceTransaction(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx) { + data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d} + queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1}). + Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil) +} + +func RegisterTraceTransactionError(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx) { + queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1}). + Return(nil, errortypes.ErrInvalidRequest) +} + +// TraceBlock +func RegisterTraceBlock(queryClient *mocks.EVMQueryClient, txs []*evmtypes.MsgEthereumTx) { + data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d} + queryClient.On("TraceBlock", rpc.ContextWithHeight(1), + &evmtypes.QueryTraceBlockRequest{Txs: txs, BlockNumber: 1, TraceConfig: &evmtypes.TraceConfig{}}). + Return(&evmtypes.QueryTraceBlockResponse{Data: data}, nil) +} + +func RegisterTraceBlockError(queryClient *mocks.EVMQueryClient) { + queryClient.On("TraceBlock", rpc.ContextWithHeight(1), &evmtypes.QueryTraceBlockRequest{}). + Return(nil, errortypes.ErrInvalidRequest) +} + // Params func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) { queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)). @@ -41,6 +74,11 @@ func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, heig }) } +func RegisterParamsWithoutHeader(queryClient *mocks.EVMQueryClient, height int64) { + queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}). + Return(&evmtypes.QueryParamsResponse{Params: evmtypes.DefaultParams()}, nil) +} + func RegisterParamsInvalidHeader(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) { queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)). Return(&evmtypes.QueryParamsResponse{}, nil). @@ -64,6 +102,11 @@ func RegisterParamsInvalidHeight(queryClient *mocks.EVMQueryClient, header *meta }) } +func RegisterParamsWithoutHeaderError(queryClient *mocks.EVMQueryClient, height int64) { + queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}). + Return(nil, errortypes.ErrInvalidRequest) +} + // Params returns error func RegisterParamsError(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) { queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)). @@ -71,8 +114,9 @@ func RegisterParamsError(queryClient *mocks.EVMQueryClient, header *metadata.MD, } func TestRegisterParams(t *testing.T) { - queryClient := mocks.NewEVMQueryClient(t) var header metadata.MD + queryClient := mocks.NewEVMQueryClient(t) + height := int64(1) RegisterParams(queryClient, &header, height) @@ -91,6 +135,26 @@ func TestRegisterParamsError(t *testing.T) { require.Error(t, err) } +// ETH Call +func RegisterEthCall(queryClient *mocks.EVMQueryClient, request *evmtypes.EthCallRequest) { + ctx, _ := context.WithCancel(rpc.ContextWithHeight(1)) + queryClient.On("EthCall", ctx, request). + Return(&evmtypes.MsgEthereumTxResponse{}, nil) +} + +func RegisterEthCallError(queryClient *mocks.EVMQueryClient, request *evmtypes.EthCallRequest) { + ctx, _ := context.WithCancel(rpc.ContextWithHeight(1)) + queryClient.On("EthCall", ctx, request). + Return(nil, errortypes.ErrInvalidRequest) +} + +// Estimate Gas +func RegisterEstimateGas(queryClient *mocks.EVMQueryClient, args evmtypes.TransactionArgs) { + bz, _ := json.Marshal(args) + queryClient.On("EstimateGas", rpc.ContextWithHeight(1), &evmtypes.EthCallRequest{Args: bz}). + Return(&evmtypes.EstimateGasResponse{}, nil) +} + // BaseFee func RegisterBaseFee(queryClient *mocks.EVMQueryClient, baseFee sdk.Int) { queryClient.On("BaseFee", rpc.ContextWithHeight(1), &evmtypes.QueryBaseFeeRequest{}). @@ -137,12 +201,7 @@ func TestRegisterBaseFeeDisabled(t *testing.T) { // ValidatorAccount func RegisterValidatorAccount(queryClient *mocks.EVMQueryClient, validator sdk.AccAddress) { queryClient.On("ValidatorAccount", rpc.ContextWithHeight(1), &evmtypes.QueryValidatorAccountRequest{}). - Return( - &evmtypes.QueryValidatorAccountResponse{ - AccountAddress: validator.String(), - }, - nil, - ) + Return(&evmtypes.QueryValidatorAccountResponse{AccountAddress: validator.String()}, nil) } func RegisterValidatorAccountError(queryClient *mocks.EVMQueryClient) { diff --git a/rpc/backend/feemarket_query_client_test.go b/rpc/backend/feemarket_query_client_test.go new file mode 100644 index 0000000000..ac1e7cf113 --- /dev/null +++ b/rpc/backend/feemarket_query_client_test.go @@ -0,0 +1,21 @@ +package backend + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/evmos/ethermint/rpc/backend/mocks" + rpc "github.com/evmos/ethermint/rpc/types" + feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" +) + +var _ feemarkettypes.QueryClient = &mocks.FeeMarketQueryClient{} + +// Params +func RegisterFeeMarketParams(feeMarketClient *mocks.FeeMarketQueryClient, height int64) { + feeMarketClient.On("Params", rpc.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{}). + Return(&feemarkettypes.QueryParamsResponse{Params: feemarkettypes.DefaultParams()}, nil) +} + +func RegisterFeeMarketParamsError(feeMarketClient *mocks.FeeMarketQueryClient, height int64) { + feeMarketClient.On("Params", rpc.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{}). + Return(nil, sdkerrors.ErrInvalidRequest) +} diff --git a/rpc/backend/filters.go b/rpc/backend/filters.go index bf0b81f866..8495705f4f 100644 --- a/rpc/backend/filters.go +++ b/rpc/backend/filters.go @@ -15,7 +15,6 @@ func (b *Backend) GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) { if resBlock == nil { return nil, errors.Errorf("block not found for hash %s", hash) } - return b.GetLogsByHeight(&resBlock.Block.Header.Height) } diff --git a/rpc/backend/filters_test.go b/rpc/backend/filters_test.go new file mode 100644 index 0000000000..20dae61a6c --- /dev/null +++ b/rpc/backend/filters_test.go @@ -0,0 +1,117 @@ +package backend + +import ( + "encoding/json" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/evmos/ethermint/rpc/backend/mocks" + ethrpc "github.com/evmos/ethermint/rpc/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + tmtypes "github.com/tendermint/tendermint/types" +) + +func (suite *BackendTestSuite) TestGetLogs() { + + _, bz := suite.buildEthereumTx() + block := tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil) + logs := make([]*evmtypes.Log, 0, 1) + var log evmtypes.Log + json.Unmarshal([]byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}, &log) + logs = append(logs, &log) + + testCases := []struct { + name string + registerMock func(hash common.Hash) + blockHash common.Hash + expLogs [][]*ethtypes.Log + expPass bool + }{ + { + "fail - no block with that hash", + func(hash common.Hash) { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockByHashNotFound(client, hash, bz) + }, + common.Hash{}, + nil, + false, + }, + { + "fail - error fetching block by hash", + func(hash common.Hash) { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockByHashError(client, hash, bz) + }, + common.Hash{}, + nil, + false, + }, + { + "fail - error getting block results", + func(hash common.Hash) { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockByHash(client, hash, bz) + RegisterBlockResultsError(client, 1) + }, + common.Hash{}, + nil, + false, + }, + { + "success - getting logs with block hash", + func(hash common.Hash) { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockByHash(client, hash, bz) + RegisterBlockResultsWithEventLog(client, ethrpc.BlockNumber(1).Int64()) + }, + common.BytesToHash(block.Hash()), + [][]*ethtypes.Log{evmtypes.LogsToEthereum(logs)}, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + + tc.registerMock(tc.blockHash) + logs, err := suite.backend.GetLogs(tc.blockHash) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expLogs, logs) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestBloomStatus() { + testCases := []struct { + name string + registerMock func() + expResult uint64 + expPass bool + }{ + { + "pass - returns the BloomBitsBlocks and the number of processed sections maintained", + func() {}, + 4096, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + + tc.registerMock() + bloom, _ := suite.backend.BloomStatus() + + if tc.expPass { + suite.Require().Equal(tc.expResult, bloom) + } + }) + } +} diff --git a/rpc/backend/mocks/feemarket_query_client.go b/rpc/backend/mocks/feemarket_query_client.go new file mode 100644 index 0000000000..2536699fb0 --- /dev/null +++ b/rpc/backend/mocks/feemarket_query_client.go @@ -0,0 +1,123 @@ +// Code generated by mockery v2.14.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + grpc "google.golang.org/grpc" + + mock "github.com/stretchr/testify/mock" + + types "github.com/evmos/ethermint/x/feemarket/types" +) + +// FeeMarketQueryClient is an autogenerated mock type for the QueryClient type +type FeeMarketQueryClient struct { + mock.Mock +} + +// BaseFee provides a mock function with given fields: ctx, in, opts +func (_m *FeeMarketQueryClient) BaseFee(ctx context.Context, in *types.QueryBaseFeeRequest, opts ...grpc.CallOption) (*types.QueryBaseFeeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *types.QueryBaseFeeResponse + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBaseFeeRequest, ...grpc.CallOption) *types.QueryBaseFeeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryBaseFeeResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryBaseFeeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BlockGas provides a mock function with given fields: ctx, in, opts +func (_m *FeeMarketQueryClient) BlockGas(ctx context.Context, in *types.QueryBlockGasRequest, opts ...grpc.CallOption) (*types.QueryBlockGasResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *types.QueryBlockGasResponse + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBlockGasRequest, ...grpc.CallOption) *types.QueryBlockGasResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryBlockGasResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryBlockGasRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *FeeMarketQueryClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *types.QueryParamsResponse + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewQueryClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewQueryClient creates a new instance of QueryClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewFeeMarketQueryClient(t mockConstructorTestingTNewQueryClient) *FeeMarketQueryClient { + mock := &FeeMarketQueryClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/rpc/backend/node_info_test.go b/rpc/backend/node_info_test.go new file mode 100644 index 0000000000..dec4f43974 --- /dev/null +++ b/rpc/backend/node_info_test.go @@ -0,0 +1,355 @@ +package backend + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/evmos/ethermint/crypto/ethsecp256k1" + "github.com/evmos/ethermint/rpc/backend/mocks" + ethermint "github.com/evmos/ethermint/types" + "github.com/spf13/viper" + tmrpcclient "github.com/tendermint/tendermint/rpc/client" + "math/big" +) + +func (suite *BackendTestSuite) TestRPCMinGasPrice() { + testCases := []struct { + name string + registerMock func() + expMinGasPrice int64 + expPass bool + }{ + { + "pass - default gas price", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParamsWithoutHeaderError(queryClient, 1) + }, + ethermint.DefaultGasPrice, + true, + }, + { + "pass - min gas price is 0", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParamsWithoutHeader(queryClient, 1) + }, + ethermint.DefaultGasPrice, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + minPrice := suite.backend.RPCMinGasPrice() + if tc.expPass { + suite.Require().Equal(tc.expMinGasPrice, minPrice) + } else { + suite.Require().NotEqual(tc.expMinGasPrice, minPrice) + } + }) + } +} + +func (suite *BackendTestSuite) TestSetGasPrice() { + defaultGasPrice := (*hexutil.Big)(big.NewInt(1)) + testCases := []struct { + name string + registerMock func() + gasPrice hexutil.Big + expOutput bool + }{ + { + "pass - cannot get server config", + func() { + suite.backend.clientCtx.Viper = viper.New() + }, + *defaultGasPrice, + false, + }, + { + "pass - cannot find coin denom", + func() { + suite.backend.clientCtx.Viper = viper.New() + suite.backend.clientCtx.Viper.Set("telemetry.global-labels", []interface{}{}) + }, + *defaultGasPrice, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + output := suite.backend.SetGasPrice(tc.gasPrice) + suite.Require().Equal(tc.expOutput, output) + }) + } +} + +// TODO: Combine these 2 into one test since the code is identical +func (suite *BackendTestSuite) TestListAccounts() { + testCases := []struct { + name string + registerMock func() + expAddr []common.Address + expPass bool + }{ + { + "pass - returns empty address", + func() {}, + []common.Address{}, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + output, err := suite.backend.ListAccounts() + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expAddr, output) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestAccounts() { + testCases := []struct { + name string + registerMock func() + expAddr []common.Address + expPass bool + }{ + { + "pass - returns empty address", + func() {}, + []common.Address{}, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + output, err := suite.backend.Accounts() + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expAddr, output) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestSyncing() { + testCases := []struct { + name string + registerMock func() + expResponse interface{} + expPass bool + }{ + { + "fail - Can't get status", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterStatusError(client) + }, + false, + false, + }, + { + "pass - Node not catching up", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterStatus(client) + }, + false, + true, + }, + { + "pass - Node is catching up", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterStatus(client) + status, _ := client.Status(suite.backend.ctx) + status.SyncInfo.CatchingUp = true + + }, + map[string]interface{}{ + "startingBlock": hexutil.Uint64(0), + "currentBlock": hexutil.Uint64(0), + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + output, err := suite.backend.Syncing() + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expResponse, output) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestSetEtherbase() { + testCases := []struct { + name string + registerMock func() + etherbase common.Address + expResult bool + }{ + { + "pass - Failed to get coinbase address", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterStatusError(client) + }, + common.Address{}, + false, + }, + { + "pass - the minimum fee is not set", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterStatus(client) + RegisterValidatorAccount(queryClient, suite.acc) + }, + common.Address{}, + false, + }, + { + "fail - error querying for account ", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterStatus(client) + RegisterValidatorAccount(queryClient, suite.acc) + c := sdk.NewDecCoin("aphoton", sdk.NewIntFromBigInt(big.NewInt(1))) + suite.backend.cfg.SetMinGasPrices(sdk.DecCoins{c}) + delAddr, _ := suite.backend.GetCoinbase() + //account, _ := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, delAddr) + delCommonAddr := common.BytesToAddress(delAddr.Bytes()) + request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(delCommonAddr.Bytes()).String()} + requestMarshal, _ := request.Marshal() + RegisterABCIQueryWithOptionsError( + client, + "/cosmos.auth.v1beta1.Query/Account", + requestMarshal, + tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false}, + ) + }, + common.Address{}, + false, + }, + // TODO: Finish this test case once ABCIQuery GetAccount is fixed + //{ + // "pass - set the etherbase for the miner", + // func() { + // client := suite.backend.clientCtx.Client.(*mocks.Client) + // queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + // RegisterStatus(client) + // RegisterValidatorAccount(queryClient, suite.acc) + // c := sdk.NewDecCoin("aphoton", sdk.NewIntFromBigInt(big.NewInt(1))) + // suite.backend.cfg.SetMinGasPrices(sdk.DecCoins{c}) + // delAddr, _ := suite.backend.GetCoinbase() + // account, _ := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, delAddr) + // delCommonAddr := common.BytesToAddress(delAddr.Bytes()) + // request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(delCommonAddr.Bytes()).String()} + // requestMarshal, _ := request.Marshal() + // RegisterABCIQueryAccount( + // client, + // requestMarshal, + // tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false}, + // account, + // ) + // }, + // common.Address{}, + // false, + //}, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + output := suite.backend.SetEtherbase(tc.etherbase) + + suite.Require().Equal(tc.expResult, output) + }) + } +} + +func (suite *BackendTestSuite) TestImportRawKey() { + priv, _ := ethsecp256k1.GenerateKey() + privHex := common.Bytes2Hex(priv.Bytes()) + pubAddr := common.BytesToAddress(priv.PubKey().Address().Bytes()) + + testCases := []struct { + name string + registerMock func() + privKey string + password string + expAddr common.Address + expPass bool + }{ + { + "fail - not a valid private key", + func() {}, + "", + "", + common.Address{}, + false, + }, + { + "pass - returning correct address", + func() {}, + privHex, + "", + pubAddr, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + output, err := suite.backend.ImportRawKey(tc.privKey, tc.password) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expAddr, output) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/rpc/backend/sign_tx.go b/rpc/backend/sign_tx.go index b8052e1282..bb9c175155 100644 --- a/rpc/backend/sign_tx.go +++ b/rpc/backend/sign_tx.go @@ -1,6 +1,7 @@ package backend import ( + "errors" "fmt" "math/big" @@ -13,9 +14,8 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/signer/core/apitypes" - "github.com/evmos/ethermint/ethereum/eip712" + evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/pkg/errors" ) // SendTransaction sends transaction based on received args using Node's key to sign it @@ -27,6 +27,10 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e return common.Hash{}, fmt.Errorf("%s; %s", keystore.ErrNoMatch, err.Error()) } + if args.ChainID != nil && (b.chainID).Cmp((*big.Int)(args.ChainID)) != 0 { + return common.Hash{}, fmt.Errorf("chainId does not match node's (have=%v, want=%v)", args.ChainID, (*hexutil.Big)(b.chainID)) + } + args, err = b.SetTxDefaults(args) if err != nil { return common.Hash{}, err @@ -131,7 +135,7 @@ func (b *Backend) SignTypedData(address common.Address, typedData apitypes.Typed return nil, fmt.Errorf("%s; %s", keystore.ErrNoMatch, err.Error()) } - sigHash, err := eip712.ComputeTypedDataHash(typedData) + sigHash, _, err := apitypes.TypedDataAndHash(typedData) if err != nil { return nil, err } diff --git a/rpc/backend/sign_tx_test.go b/rpc/backend/sign_tx_test.go new file mode 100644 index 0000000000..d97dde9da1 --- /dev/null +++ b/rpc/backend/sign_tx_test.go @@ -0,0 +1,260 @@ +package backend + +import ( + "fmt" + "github.com/cosmos/cosmos-sdk/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + ethtypes "github.com/ethereum/go-ethereum/core/types" + goethcrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + "github.com/evmos/ethermint/crypto/ethsecp256k1" + "github.com/evmos/ethermint/rpc/backend/mocks" + "github.com/evmos/ethermint/tests" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "google.golang.org/grpc/metadata" +) + +func (suite *BackendTestSuite) TestSendTransaction() { + gasPrice := new(hexutil.Big) + gas := hexutil.Uint64(1) + zeroGas := hexutil.Uint64(0) + toAddr := tests.GenerateAddress() + priv, _ := ethsecp256k1.GenerateKey() + from := common.BytesToAddress(priv.PubKey().Address().Bytes()) + nonce := hexutil.Uint64(1) + baseFee := sdk.NewInt(1) + callArgsDefault := evmtypes.TransactionArgs{ + From: &from, + To: &toAddr, + GasPrice: gasPrice, + Gas: &gas, + Nonce: &nonce, + } + + hash := common.Hash{} + + testCases := []struct { + name string + registerMock func() + args evmtypes.TransactionArgs + expHash common.Hash + expPass bool + }{ + { + "fail - Can't find account in Keyring", + func() {}, + evmtypes.TransactionArgs{}, + hash, + false, + }, + { + "fail - Block error can't set Tx defaults", + func() { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1") + suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "") + RegisterParams(queryClient, &header, 1) + RegisterBlockError(client, 1) + }, + callArgsDefault, + hash, + false, + }, + { + "fail - Cannot validate transaction gas set to 0", + func() { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1") + suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "") + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + }, + evmtypes.TransactionArgs{ + From: &from, + To: &toAddr, + GasPrice: gasPrice, + Gas: &zeroGas, + Nonce: &nonce, + }, + hash, + false, + }, + { + "fail - Cannot broadcast transaction", + func() { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1") + suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "") + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + RegisterParamsWithoutHeader(queryClient, 1) + ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig()) + msg := callArgsDefault.ToTransaction() + msg.Sign(ethSigner, suite.backend.clientCtx.Keyring) + tx, _ := msg.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") + txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder() + txBytes, _ := txEncoder(tx) + RegisterBroadcastTxError(client, txBytes) + }, + callArgsDefault, + common.Hash{}, + false, + }, + { + "pass - Return the transaction hash", + func() { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1") + suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "") + RegisterParams(queryClient, &header, 1) + RegisterBlock(client, 1, nil) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, baseFee) + RegisterParamsWithoutHeader(queryClient, 1) + ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig()) + msg := callArgsDefault.ToTransaction() + msg.Sign(ethSigner, suite.backend.clientCtx.Keyring) + tx, _ := msg.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") + txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder() + txBytes, _ := txEncoder(tx) + RegisterBroadcastTx(client, txBytes) + }, + callArgsDefault, + hash, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + if tc.expPass { + // Sign the transaction and get the hash + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParamsWithoutHeader(queryClient, 1) + ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig()) + msg := callArgsDefault.ToTransaction() + msg.Sign(ethSigner, suite.backend.clientCtx.Keyring) + tc.expHash = msg.AsTransaction().Hash() + } + responseHash, err := suite.backend.SendTransaction(tc.args) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expHash, responseHash) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestSign() { + from, priv := tests.NewAddrKey() + testCases := []struct { + name string + registerMock func() + fromAddr common.Address + inputBz hexutil.Bytes + expPass bool + }{ + { + "fail - can't find key in Keyring", + func() {}, + from, + nil, + false, + }, + { + "pass - sign nil data", + func() { + armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1") + suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "") + }, + from, + nil, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + responseBz, err := suite.backend.Sign(tc.fromAddr, tc.inputBz) + if tc.expPass { + signature, _, err := suite.backend.clientCtx.Keyring.SignByAddress((sdk.AccAddress)(from.Bytes()), tc.inputBz) + signature[goethcrypto.RecoveryIDOffset] += 27 + suite.Require().NoError(err) + suite.Require().Equal((hexutil.Bytes)(signature), responseBz) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestSignTypedData() { + from, priv := tests.NewAddrKey() + testCases := []struct { + name string + registerMock func() + fromAddr common.Address + inputTypedData apitypes.TypedData + expPass bool + }{ + { + "fail - can't find key in Keyring", + func() {}, + from, + apitypes.TypedData{}, + false, + }, + { + "fail - empty TypeData", + func() { + armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1") + suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "") + }, + from, + apitypes.TypedData{}, + false, + }, + // TODO: Generate a TypedData msg + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + responseBz, err := suite.backend.SignTypedData(tc.fromAddr, tc.inputTypedData) + + if tc.expPass { + sigHash, _, err := apitypes.TypedDataAndHash(tc.inputTypedData) + signature, _, err := suite.backend.clientCtx.Keyring.SignByAddress((sdk.AccAddress)(from.Bytes()), sigHash) + signature[goethcrypto.RecoveryIDOffset] += 27 + suite.Require().NoError(err) + suite.Require().Equal((hexutil.Bytes)(signature), responseBz) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index 50cd771c06..b77ce4d982 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -112,7 +112,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return decodedResult, nil } -// traceBlock configures a new tracer according to the provided configuration, and +// TraceBlock configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requested tracer. func (b *Backend) TraceBlock(height rpctypes.BlockNumber, diff --git a/rpc/backend/tracing_test.go b/rpc/backend/tracing_test.go new file mode 100644 index 0000000000..aef0f46ce7 --- /dev/null +++ b/rpc/backend/tracing_test.go @@ -0,0 +1,247 @@ +package backend + +import ( + "fmt" + "github.com/cosmos/cosmos-sdk/crypto" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/evmos/ethermint/crypto/ethsecp256k1" + "github.com/evmos/ethermint/indexer" + "github.com/evmos/ethermint/rpc/backend/mocks" + evmtypes "github.com/evmos/ethermint/x/evm/types" + abci "github.com/tendermint/tendermint/abci/types" + tmlog "github.com/tendermint/tendermint/libs/log" + tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" + "github.com/tendermint/tendermint/types" + tmtypes "github.com/tendermint/tendermint/types" + dbm "github.com/tendermint/tm-db" +) + +func (suite *BackendTestSuite) TestTraceTransaction() { + msgEthereumTx, _ := suite.buildEthereumTx() + msgEthereumTx2, _ := suite.buildEthereumTx() + + txHash := msgEthereumTx.AsTransaction().Hash() + txHash2 := msgEthereumTx2.AsTransaction().Hash() + + priv, _ := ethsecp256k1.GenerateKey() + from := common.BytesToAddress(priv.PubKey().Address().Bytes()) + + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParamsWithoutHeader(queryClient, 1) + + armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1") + suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "") + ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig()) + + txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder() + + msgEthereumTx.From = from.String() + msgEthereumTx.Sign(ethSigner, suite.signer) + tx, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") + txBz, _ := txEncoder(tx) + + msgEthereumTx2.From = from.String() + msgEthereumTx2.Sign(ethSigner, suite.signer) + tx2, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") + txBz2, _ := txEncoder(tx2) + + testCases := []struct { + name string + registerMock func() + block *types.Block + responseBlock []*abci.ResponseDeliverTx + expResult interface{} + expPass bool + }{ + { + "fail - tx not found", + func() {}, + &types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{}}}, + []*abci.ResponseDeliverTx{ + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())}, + {Key: []byte("txIndex"), Value: []byte("0")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")}, + }}, + }, + }, + }, + nil, + false, + }, + { + "fail - block not found", + func() { + //var header metadata.MD + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockError(client, 1) + }, + &types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}}, + []*abci.ResponseDeliverTx{ + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())}, + {Key: []byte("txIndex"), Value: []byte("0")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")}, + }}, + }, + }, + }, + map[string]interface{}{"test": "hello"}, + false, + }, + { + "pass - transaction found in a block with multiple transactions", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockMultipleTxs(client, 1, []types.Tx{txBz, txBz2}) + RegisterTraceTransactionWithPredecessors(queryClient, msgEthereumTx, []*evmtypes.MsgEthereumTx{msgEthereumTx}) + }, + &types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz, txBz2}}}, + []*abci.ResponseDeliverTx{ + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())}, + {Key: []byte("txIndex"), Value: []byte("0")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")}, + }}, + }, + }, + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(txHash2.Hex())}, + {Key: []byte("txIndex"), Value: []byte("1")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")}, + }}, + }, + }, + }, + map[string]interface{}{"test": "hello"}, + true, + }, + { + "pass - transaction found", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlock(client, 1, txBz) + RegisterTraceTransaction(queryClient, msgEthereumTx) + }, + &types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}}, + []*abci.ResponseDeliverTx{ + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())}, + {Key: []byte("txIndex"), Value: []byte("0")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")}, + }}, + }, + }, + }, + map[string]interface{}{"test": "hello"}, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + db := dbm.NewMemDB() + suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx) + + err := suite.backend.indexer.IndexBlock(tc.block, tc.responseBlock) + txResult, err := suite.backend.TraceTransaction(txHash, nil) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expResult, txResult) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestTraceBlock() { + msgEthTx, bz := suite.buildEthereumTx() + emptyBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{}, nil, nil) + filledBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil) + resBlockEmpty := tmrpctypes.ResultBlock{Block: emptyBlock, BlockID: emptyBlock.LastBlockID} + resBlockFilled := tmrpctypes.ResultBlock{Block: filledBlock, BlockID: filledBlock.LastBlockID} + + testCases := []struct { + name string + registerMock func() + expTraceResults []*evmtypes.TxTraceResult + resBlock *tmrpctypes.ResultBlock + config *evmtypes.TraceConfig + expPass bool + }{ + { + "pass - no transaction returning empty array", + func() {}, + []*evmtypes.TxTraceResult{}, + &resBlockEmpty, + &evmtypes.TraceConfig{}, + true, + }, + { + "fail - cannot unmarshal data", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterTraceBlock(queryClient, []*evmtypes.MsgEthereumTx{msgEthTx}) + + }, + []*evmtypes.TxTraceResult{}, + &resBlockFilled, + &evmtypes.TraceConfig{}, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("case %s", tc.name), func() { + suite.SetupTest() // reset test and queries + tc.registerMock() + + traceResults, err := suite.backend.TraceBlock(1, tc.config, tc.resBlock) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expTraceResults, traceResults) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 7a49231da6..6872735b5b 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -74,6 +74,7 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac uint64(res.Height), uint64(res.EthTxIndex), baseFee, + b.chainID, ) } @@ -102,6 +103,7 @@ func (b *Backend) getTransactionByHashPending(txHash common.Hash) (*rpctypes.RPC uint64(0), uint64(0), nil, + b.chainID, ) if err != nil { return nil, err @@ -214,6 +216,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ // sender and receiver (contract or EOA) addreses "from": from, "to": txData.GetTo(), + "type": hexutil.Uint(ethMsg.AsTransaction().Type()), } if logs == nil { @@ -339,7 +342,7 @@ func (b *Backend) queryTendermintTxIndexer(query string, txGetter func(*rpctypes return rpctypes.ParseTxIndexerResult(txResult, tx, txGetter) } -// getTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`. +// GetTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`. func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height) if err != nil { @@ -386,5 +389,6 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, i uint64(block.Block.Height), uint64(idx), baseFee, + b.chainID, ) } diff --git a/rpc/backend/tx_info_test.go b/rpc/backend/tx_info_test.go new file mode 100644 index 0000000000..86d73bc33a --- /dev/null +++ b/rpc/backend/tx_info_test.go @@ -0,0 +1,600 @@ +package backend + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/evmos/ethermint/indexer" + "github.com/evmos/ethermint/rpc/backend/mocks" + rpctypes "github.com/evmos/ethermint/rpc/types" + ethermint "github.com/evmos/ethermint/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + abci "github.com/tendermint/tendermint/abci/types" + tmlog "github.com/tendermint/tendermint/libs/log" + tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" + "github.com/tendermint/tendermint/types" + dbm "github.com/tendermint/tm-db" + "google.golang.org/grpc/metadata" + "math/big" +) + +func (suite *BackendTestSuite) TestGetTransactionByHash() { + msgEthereumTx, _ := suite.buildEthereumTx() + txHash := msgEthereumTx.AsTransaction().Hash() + + txBz := suite.signAndEncodeEthTx(msgEthereumTx) + block := &types.Block{Header: types.Header{Height: 1, ChainID: "test"}, Data: types.Data{Txs: []types.Tx{txBz}}} + responseDeliver := []*abci.ResponseDeliverTx{ + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())}, + {Key: []byte("txIndex"), Value: []byte("0")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("")}, + }}, + }, + }, + } + + rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID) + + testCases := []struct { + name string + registerMock func() + tx *evmtypes.MsgEthereumTx + expRPCTx *rpctypes.RPCTransaction + expPass bool + }{ + { + "fail - Block error", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockError(client, 1) + }, + msgEthereumTx, + rpcTransaction, + false, + }, + { + "fail - Block Result error", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlock(client, 1, txBz) + RegisterBlockResultsError(client, 1) + }, + msgEthereumTx, + nil, + true, + }, + { + "pass - Base fee error", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, txBz) + RegisterBlockResults(client, 1) + RegisterBaseFeeError(queryClient) + }, + msgEthereumTx, + rpcTransaction, + true, + }, + { + "pass - Transaction found and returned", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, txBz) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + }, + msgEthereumTx, + rpcTransaction, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + db := dbm.NewMemDB() + suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx) + err := suite.backend.indexer.IndexBlock(block, responseDeliver) + suite.Require().NoError(err) + + rpcTx, err := suite.backend.GetTransactionByHash(common.HexToHash(tc.tx.Hash)) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(rpcTx, tc.expRPCTx) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetTransactionsByHashPending() { + msgEthereumTx, bz := suite.buildEthereumTx() + rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID) + + testCases := []struct { + name string + registerMock func() + tx *evmtypes.MsgEthereumTx + expRPCTx *rpctypes.RPCTransaction + expPass bool + }{ + { + "fail - Pending transactions returns error", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterUnconfirmedTxsError(client, nil) + }, + msgEthereumTx, + nil, + true, + }, + { + "fail - Tx not found return nil", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterUnconfirmedTxs(client, nil, nil) + }, + msgEthereumTx, + nil, + true, + }, + { + "pass - Tx found and returned", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterUnconfirmedTxs(client, nil, types.Txs{bz}) + }, + msgEthereumTx, + rpcTransaction, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + rpcTx, err := suite.backend.getTransactionByHashPending(common.HexToHash(tc.tx.Hash)) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(rpcTx, tc.expRPCTx) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetTxByEthHash() { + msgEthereumTx, bz := suite.buildEthereumTx() + rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID) + + testCases := []struct { + name string + registerMock func() + tx *evmtypes.MsgEthereumTx + expRPCTx *rpctypes.RPCTransaction + expPass bool + }{ + { + "fail - Indexer disabled can't find transaction", + func() { + suite.backend.indexer = nil + client := suite.backend.clientCtx.Client.(*mocks.Client) + query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, common.HexToHash(msgEthereumTx.Hash).Hex()) + RegisterTxSearch(client, query, bz) + }, + msgEthereumTx, + rpcTransaction, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + rpcTx, err := suite.backend.GetTxByEthHash(common.HexToHash(tc.tx.Hash)) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(rpcTx, tc.expRPCTx) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetTransactionByBlockHashAndIndex() { + _, bz := suite.buildEthereumTx() + + testCases := []struct { + name string + registerMock func() + blockHash common.Hash + expRPCTx *rpctypes.RPCTransaction + expPass bool + }{ + { + "pass - block not found", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockByHashError(client, common.Hash{}, bz) + }, + common.Hash{}, + nil, + true, + }, + { + "pass - Block results error", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockByHash(client, common.Hash{}, bz) + RegisterBlockResultsError(client, 1) + }, + common.Hash{}, + nil, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + rpcTx, err := suite.backend.GetTransactionByBlockHashAndIndex(tc.blockHash, 1) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(rpcTx, tc.expRPCTx) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetTransactionByBlockAndIndex() { + msgEthTx, bz := suite.buildEthereumTx() + + defaultBlock := types.MakeBlock(1, []types.Tx{bz}, nil, nil) + defaultResponseDeliverTx := []*abci.ResponseDeliverTx{ + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(common.HexToHash(msgEthTx.Hash).Hex())}, + {Key: []byte("txIndex"), Value: []byte("0")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("")}, + }}, + }, + }, + } + + txFromMsg, _ := rpctypes.NewTransactionFromMsg( + msgEthTx, + common.BytesToHash(defaultBlock.Hash().Bytes()), + 1, + 0, + big.NewInt(1), + suite.backend.chainID, + ) + testCases := []struct { + name string + registerMock func() + block *tmrpctypes.ResultBlock + idx hexutil.Uint + expRPCTx *rpctypes.RPCTransaction + expPass bool + }{ + { + "pass - block txs index out of bound ", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockResults(client, 1) + }, + &tmrpctypes.ResultBlock{Block: types.MakeBlock(1, []types.Tx{bz}, nil, nil)}, + 1, + nil, + true, + }, + { + "pass - Can't fetch base fee", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockResults(client, 1) + RegisterBaseFeeError(queryClient) + }, + &tmrpctypes.ResultBlock{Block: defaultBlock}, + 0, + txFromMsg, + true, + }, + { + "pass - Gets Tx by transaction index", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + db := dbm.NewMemDB() + suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx) + txBz := suite.signAndEncodeEthTx(msgEthTx) + block := &types.Block{Header: types.Header{Height: 1, ChainID: "test"}, Data: types.Data{Txs: []types.Tx{txBz}}} + err := suite.backend.indexer.IndexBlock(block, defaultResponseDeliverTx) + suite.Require().NoError(err) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + }, + &tmrpctypes.ResultBlock{Block: defaultBlock}, + 0, + txFromMsg, + true, + }, + { + "pass - returns the Ethereum format transaction by the Ethereum hash", + func() { + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + }, + &tmrpctypes.ResultBlock{Block: defaultBlock}, + 0, + txFromMsg, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + rpcTx, err := suite.backend.GetTransactionByBlockAndIndex(tc.block, tc.idx) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(rpcTx, tc.expRPCTx) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetTransactionByBlockNumberAndIndex() { + msgEthTx, bz := suite.buildEthereumTx() + defaultBlock := types.MakeBlock(1, []types.Tx{bz}, nil, nil) + txFromMsg, _ := rpctypes.NewTransactionFromMsg( + msgEthTx, + common.BytesToHash(defaultBlock.Hash().Bytes()), + 1, + 0, + big.NewInt(1), + suite.backend.chainID, + ) + testCases := []struct { + name string + registerMock func() + blockNum rpctypes.BlockNumber + idx hexutil.Uint + expRPCTx *rpctypes.RPCTransaction + expPass bool + }{ + { + "fail - block not found return nil", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterBlockError(client, 1) + }, + 0, + 0, + nil, + true, + }, + { + "pass - returns the transaction identified by block number and index", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, bz) + RegisterBlockResults(client, 1) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + }, + 0, + 0, + txFromMsg, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + rpcTx, err := suite.backend.GetTransactionByBlockNumberAndIndex(tc.blockNum, tc.idx) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(rpcTx, tc.expRPCTx) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetTransactionByTxIndex() { + _, bz := suite.buildEthereumTx() + + testCases := []struct { + name string + registerMock func() + height int64 + index uint + expTxResult *ethermint.TxResult + expPass bool + }{ + { + "fail - Ethereum tx with query not found", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + suite.backend.indexer = nil + RegisterTxSearch(client, "tx.height=0 AND ethereum_tx.txIndex=0", bz) + }, + 0, + 0, + ðermint.TxResult{}, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + txResults, err := suite.backend.GetTxByTxIndex(tc.height, tc.index) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(txResults, tc.expTxResult) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestQueryTendermintTxIndexer() { + testCases := []struct { + name string + registerMock func() + txGetter func(*rpctypes.ParsedTxs) *rpctypes.ParsedTx + query string + expTxResult *ethermint.TxResult + expPass bool + }{ + { + "fail - Ethereum tx with query not found", + func() { + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterTxSearchEmpty(client, "") + }, + func(txs *rpctypes.ParsedTxs) *rpctypes.ParsedTx { + return &rpctypes.ParsedTx{} + }, + "", + ðermint.TxResult{}, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + txResults, err := suite.backend.queryTendermintTxIndexer(tc.query, tc.txGetter) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(txResults, tc.expTxResult) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *BackendTestSuite) TestGetTransactionReceipt() { + msgEthereumTx, _ := suite.buildEthereumTx() + txHash := msgEthereumTx.AsTransaction().Hash() + + txBz := suite.signAndEncodeEthTx(msgEthereumTx) + + testCases := []struct { + name string + registerMock func() + tx *evmtypes.MsgEthereumTx + block *types.Block + blockResult []*abci.ResponseDeliverTx + expTxReceipt map[string]interface{} + expPass bool + }{ + { + "fail - Receipts do not match ", + func() { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + client := suite.backend.clientCtx.Client.(*mocks.Client) + RegisterParams(queryClient, &header, 1) + RegisterParamsWithoutHeader(queryClient, 1) + RegisterBlock(client, 1, txBz) + RegisterBlockResults(client, 1) + + }, + msgEthereumTx, + &types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}}, + []*abci.ResponseDeliverTx{ + { + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())}, + {Key: []byte("txIndex"), Value: []byte("0")}, + {Key: []byte("amount"), Value: []byte("1000")}, + {Key: []byte("txGasUsed"), Value: []byte("21000")}, + {Key: []byte("txHash"), Value: []byte("")}, + {Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")}, + }}, + }, + }, + }, + map[string]interface{}(nil), + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.registerMock() + + db := dbm.NewMemDB() + suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx) + err := suite.backend.indexer.IndexBlock(tc.block, tc.blockResult) + suite.Require().NoError(err) + + txReceipt, err := suite.backend.GetTransactionReceipt(common.HexToHash(tc.tx.Hash)) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(txReceipt, tc.expTxReceipt) + } else { + suite.Require().NotEqual(txReceipt, tc.expTxReceipt) + } + }) + } +} diff --git a/rpc/backend/utils.go b/rpc/backend/utils.go index afd52776d0..73dbce652e 100644 --- a/rpc/backend/utils.go +++ b/rpc/backend/utils.go @@ -261,7 +261,6 @@ func GetLogsFromBlockResults(blockRes *tmrpctypes.ResultBlockResults) ([][]*etht blockLogs = append(blockLogs, logs...) } - return blockLogs, nil } diff --git a/rpc/namespaces/ethereum/eth/api.go b/rpc/namespaces/ethereum/eth/api.go index c58a3357e8..c0e5d97889 100644 --- a/rpc/namespaces/ethereum/eth/api.go +++ b/rpc/namespaces/ethereum/eth/api.go @@ -499,6 +499,7 @@ func (e *PublicAPI) GetPendingTransactions() ([]*rpctypes.RPCTransaction, error) uint64(0), uint64(0), nil, + e.backend.ChainConfig().ChainID, ) if err != nil { return nil, err diff --git a/rpc/types/block.go b/rpc/types/block.go index 8918e77dff..3476359733 100644 --- a/rpc/types/block.go +++ b/rpc/types/block.go @@ -33,6 +33,7 @@ const ( BlockParamEarliest = "earliest" BlockParamLatest = "latest" BlockParamFinalized = "finalized" + BlockParamSafe = "safe" BlockParamPending = "pending" ) @@ -73,7 +74,7 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { case BlockParamEarliest: *bn = EthEarliestBlockNumber return nil - case BlockParamLatest, BlockParamFinalized: + case BlockParamLatest, BlockParamFinalized, BlockParamSafe: *bn = EthLatestBlockNumber return nil case BlockParamPending: diff --git a/rpc/types/utils.go b/rpc/types/utils.go index 9d12851d99..6ef4c9bc5a 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -145,15 +145,17 @@ func NewTransactionFromMsg( blockHash common.Hash, blockNumber, index uint64, baseFee *big.Int, + chainID *big.Int, ) (*RPCTransaction, error) { tx := msg.AsTransaction() - return NewRPCTransaction(tx, blockHash, blockNumber, index, baseFee) + return NewRPCTransaction(tx, blockHash, blockNumber, index, baseFee, chainID) } // NewTransactionFromData returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). func NewRPCTransaction( tx *ethtypes.Transaction, blockHash common.Hash, blockNumber, index uint64, baseFee *big.Int, + chainID *big.Int, ) (*RPCTransaction, error) { // Determine the signer. For replay-protected transactions, use the most permissive // signer, because we assume that signers are backwards-compatible with old @@ -180,6 +182,7 @@ func NewRPCTransaction( V: (*hexutil.Big)(v), R: (*hexutil.Big)(r), S: (*hexutil.Big)(s), + ChainID: (*hexutil.Big)(chainID), } if blockHash != (common.Hash{}) { result.BlockHash = &blockHash diff --git a/scripts/start-geth.sh b/scripts/start-geth.sh index 1d6eed606d..170139341a 100755 --- a/scripts/start-geth.sh +++ b/scripts/start-geth.sh @@ -33,7 +33,7 @@ print(Account.from_mnemonic('$VALIDATOR1_MNEMONIC').key.hex().replace('0x','')) cat > $tmpfile << EOF $validator_key EOF -geth --datadir $DATA account import $tmpfile --password $pwdfile +geth --datadir $DATA --password $pwdfile account import $tmpfile # import community key community_key=$(python -c """ @@ -45,14 +45,14 @@ print(Account.from_mnemonic('$COMMUNITY_MNEMONIC').key.hex().replace('0x','')) cat > $tmpfile << EOF $community_key EOF -geth --datadir $DATA account import $tmpfile --password $pwdfile +geth --datadir $DATA --password $pwdfile account import $tmpfile rm $tmpfile # start up geth --networkid 9000 --datadir $DATA --http --http.addr localhost --http.api 'personal,eth,net,web3,txpool,miner' \ -unlock '0x57f96e6b86cdefdb3d412547816a82e3e0ebf9d2' --password $pwdfile \ ---mine --allow-insecure-unlock \ +--mine --miner.threads 1 --allow-insecure-unlock --ipcdisable \ $@ rm $pwdfile diff --git a/tests/integration_tests/expected_constants.py b/tests/integration_tests/expected_constants.py index 85bee9b6e0..2f75f71581 100644 --- a/tests/integration_tests/expected_constants.py +++ b/tests/integration_tests/expected_constants.py @@ -2,30 +2,47 @@ "0x00000000000000000000000000000000000000000000000000120a0b063499d4" ) +# curl https://mainnet.infura.io/v3/YOUR_KEY_HERE \ +# -X POST \ +# -H "Content-Type: application/json" \ +# -d '{"jsonrpc": "2.0","method": "eth_getProof","params": +# ["0x7F0d15C7FAae65896648C8273B6d7E43f58Fa842",["0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"], +# "latest"],"id": 1}' EXPECTED_GET_PROOF = { - "address": "0x4CB06C43fcdABeA22541fcF1F856A6a296448B6c", - "accountProof": [ - "0xf90211a03841a7ddd65c70c94b8efa79190d00f0ab134b26f18dcad508f60a7e74559d0ba0464b07429a05039e22931492d6c6251a860c018ea390045d596b1ac11b5c7aa7a011f4b89823a03c9c4b5a8ab079ee1bc0e2a83a508bb7a5dc7d7fb4f2e95d3186a0b5f7c51c3b2d51d97f171d2b38a4df1a7c0acc5eb0de46beeff4d07f5ed20e19a0b591a2ce02367eda31cf2d16eca7c27fd44dbf0864b64ea8259ad36696eb2a04a02b646a7552b8392ae94263757f699a27d6e9176b4c06b9fc0a722f893b964795a02df05d68bceb88eebf68aafde61d10ab942097afc1c58b8435ffd3895358a742a0c2f16143c4d1db03276c433696dddb3e9f3b113bcd854b127962262e98f43147a0828820316cc02bfefd899aba41340659fd06df1e0a0796287ec2a4110239f6d2a050496598670b04df7bbff3718887fa36437d6d8c7afb4eff86f76c5c7097dcc4a0c14e9060c6b3784e35b9e6ae2ad2984142a75910ccc89eb89dc1e2f44b6c58c2a009804db571d0ce07913e1cbacc4f1dc4fb8265c936f5c612e3a47e91c64d8e9fa063d96f38b3cb51b1665c6641e25ffe24803f2941e5df79942f6a53b7169647e4a0899f71abb18c6c956118bf567fac629b75f7e9526873e429d3d8abb6dbb58021a00fd717235298742623c0b3cafb3e4bd86c0b5ab1f71097b4dd19f3d6925d758da0096437146c16097f2ccc1d3e910d65a4132803baee2249e72c8bf0bcaaeb37e580", # noqa: E501 - "0xf90151a097b17a89fd2c03ee98cb6459c08f51b269da5cee46650e84470f62bf83b43efe80a03b269d284a4c3cf8f8deacafb637c6d77f607eec8d75e8548d778e629612310480a01403217a7f1416830c870087c524dabade3985271f6f369a12b010883c71927aa0f592ac54c879817389663be677166f5022943e2fe1b52617a1d15c2f353f27dda0ac8d015a9e668f5877fcc391fae33981c00577096f0455b42df4f8e8089ece24a003ba34a13e2f2fb4bf7096540b42d4955c5269875b9cf0f7b87632585d44c9a580a0b179e3230b07db294473ae57f0170262798f8c551c755b5665ace1215cee10ca80a0552d24252639a6ae775aa1df700ffb92c2411daea7286f158d44081c8172d072a0772a87d08cf38c4c68bfde770968571abd16fd3835cb902486bd2e515d53c12d80a0413774f3d900d2d2be7a3ad999ffa859a471dc03a74fb9a6d8275455f5496a548080", # noqa: E501 - "0xf869a020d13b52a61d3c1325ce3626a51418adebd6323d4840f1bdd93906359d11c933b846f8440180a01ab7c0b0a2a4bbb5a1495da8c142150891fc64e0c321e1feb70bd5f881951f7ea0551332d96d085185ab4019ad8bcf89c45321e136c261eb6271e574a2edf1461f", # noqa: E501 - ], - "balance": 0, - "codeHash": "0x551332d96d085185ab4019ad8bcf89c45321e136c261eb6271e574a2edf1461f", # noqa: E501 - "nonce": 1, - "storageHash": "0x1ab7c0b0a2a4bbb5a1495da8c142150891fc64e0c321e1feb70bd5f881951f7e", # noqa: E501 - "storageProof": [ - { - "key": "0x00", - "value": "0x48656c6c6f00000000000000000000000000000000000000000000000000000a", # noqa: E501 - "proof": [ - "0xf9019180a01ace80e7bed79fbadbe390876bd1a7d9770edf9462049ef8f4b555d05715d53ea049347a3c2eac6525a3fd7e3454dab19d73b4adeb9aa27d29493b9843f3f88814a085079b4abcd07fd4a5d6c52d35f4c4574aecc85830e90c478ca8c18fcbe590de80a02e3f8ad7ea29e784007f51852b9c3e470aef06b11bac32586a8b691134e4c27da064d2157a14bc31f195f73296ea4dcdbe7698edbf3ca81c44bf7730179d98d94ca09e7dc2597c9b7f72ddf84d7eebb0fe2a2fa2ab54fe668cd14fee44d9b40b1a53a0aa5d4acc7ac636d16bc9655556770bc325e1901fb62dc53770ef9110009e080380a0d5fde962bd2fb5326ddc7a9ca7fe0ee47c5bb3227f838b6d73d3299c22457596a08691410eff46b88f929ef649ea25025f62a5362ca8dc8876e5e1f4fc8e79256d80a0673e88d3a8a4616f676793096b5ae87cff931bd20fb8dd466f97809a1126aad8a08b774a45c2273553e2daf4bbc3a8d44fb542ea29b6f125098f79a4d211b3309ca02fed3139c1791269acb9365eddece93e743900eba6b42a6a8614747752ba268f80", # noqa: E501 - "0xf891808080a0c7d094301e0c54da37b696d85f72de5520b224ab2cf4f045d8db1a3374caf0488080a0fc5581783bfe27fab9423602e1914d719fd71433e9d7dd63c95fe7e58d10c9c38080a0c64f346fc7a21f6679cba8abdf37ca2de8c4fcd8f8bcaedb261b5f77627c93908080808080a0ddef2936a67a3ac7d3d4ff15a935a45f2cc4976c8f0310aed85daf763780e2b480", # noqa: E501 - "0xf843a0200decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563a1a048656c6c6f00000000000000000000000000000000000000000000000000000a", # noqa: E501 - ], - } - ], + "jsonrpc": "2.0", + "id": 1, + "result": { + "accountProof": [ + "0xf90211a0d308f98795cbcc61d0520723e3361adc5513705272d90ee48ccd247246f7c349a010139d8b72e8086a732523b8905eabf1172c5202efc588a3c7cd22d86c01ccbda0faa34953c5e42eba596c0085082e7969a0fba937de89a482882f56c60eb61fbda00bb6a0aae1af594fabf4bb4be474fe7c99a3936b27b3ae838341d7ea31988df0a000fd250e61c6c9944d981d9ac2d1d3265239349bd82fd06ac5635fb3026ea3dea064625348caa521add14ff55a3efb5335d70c3a57c89ca74381b29c5e44bba22ca07c87aeff8d60769087900486cee0f400d4c73ac5f75e80ea7e419e3222493c61a0a85a1e93809071ab62ef124c05f71b33b5f3beb29a40d3362449589ad069f6c7a01e44cbe03b61463da0738947c35bfd6224f1a09c3c41da47f31d779b2c6a992fa0828a75c8da3f71e2df63ac7c0f19bb4b1c9dd861fc403823f189b588dd29eb75a0c0dfa1e4be056540e1a9524e3b060ab8f6d51bc688d84b7fcf7289cfaba1ceaba00865239fb25a3a83889326e8bc21f050b33c5181681c33b89e1d7ab883b3f3c5a0e148cdb3af3c738c1e53d1f85913b0accd46c45b34e3873abd6c98d5995d5f83a0044064693ce7d1a5888a1aca785ff1126c09cf83a00c4a3b386cb3da056eb432a0b5711def31905c703d958ae996321c9f8aefb12107acfa2dc20311801eb2558fa04005fcc01439852c004a84c6542d139b20ddac8c6e1e9684821d10e07cb4e33a80", # noqa: E501 + "0xf90211a0051fd734a1442d85238b82a7fd9ab58cac3b56728e0d07141ca30ea09c502fd4a03537903e89b73f84f80346827ccb523c9658a478e4fac51269c1064d5b74dccea0fa27fc86a7025b9928cbc55d7fc4ad42fc4974f8f69e6e2c780360510398a28da0752a52276798a12b712b0edde30a8308da6618b0f58b3199c78d0654561541caa09e64d6fa19e6dadf9b107059d5e9e1ba0f8dade4605e31d36d84a8661a18b9c1a06f724081c76cdb3eeba6c164c16eecc7ca85ab6d38bc3bce4983feead3df67f9a02c66343b11b10ba25c84e2f75dc1e2a995c32929312ff9a347536138162be1d7a0994e90111ec6af30851974a047dd7a227d235b2c6d0643199a5c3f6a685bf77aa0f844ea047a6e348f4cd8d0845e5e48b06ea033c6fd4d82eb534a8bfac990be83a0db9d470d492623fd2157320e0d658e4a46ee37c12211db9356b977e09aa01551a062efa94455c86e0e45691054225aa509acf08d97ab1253c6589b9a9f7f210f0aa057a857a358c0f0b4363ee793dc7393efdc19271ffe1dfec2650aac0b867d9729a0fc714453737c12b3b20f3ca7be1a2c4e56ba75806677a3b5a75922d54637127aa00580bfa435f851327f608f21dabab8b74658fb80dfa4ae090de30e4134a652c0a080a7b5f559e6941f1e29a3dbbdc1bd41aac866845366e9435c2048233e185816a093d7ddf2501324e5f3c0b64b41829b9c929743f5db178809b01a0b513d66ab0380", # noqa: E501 + "0xf90211a03ee5370675726aa9f895944a635a812819cd90853e34807e3763882b2f0dd978a03dcdfe595fb5b1c036e8c5618e75dc5dfbd20f4093b18f423d0c546a8841784fa0d181704ea7bcced784d9480abd6360e885657957e1eb596512b162cce3512433a0c75c61390552448a12958fd0fd51a88f7e5e6badd2c16b05f4c949f604b209e2a0bb24e0cc45c91c5d3f14c0a6eeb459db9447260696ba65e8a79f86170e2997e5a00870addc6060c3f528eacfabd6c52480f45f8e28ed3c7e58306daa37f7752205a0d9b904889003012fdafbfd6cae526bd627e6d6a8ccd0e1cecba8500649c9efcba0890f7bb42d79b87940acd735c61e6b8fe12b64c2aa7c162f62dfcb40b2a6bb26a09f8bb0d80d7f51b8803b12dd01bc77281f7d0746ae6d7331705d79be9ee676faa059f3d816f66dedd5ca93d54845d9fcbcd8a3b110c78c35629db79de7736d6181a0171aa28493b4a16cdaffb06ecdfc06f73bb5b2548426fdc0d1fc807fa734f219a0eedf3bd8db8007a360cb7ca38e7718e6c7de81244883caa3a276da03174e1697a086b32111c6000e06ae1d691588f96e589e00768aa3f8337633546ba3c5069694a06992a01de330340dba82add8897bf7bd9d1a4d89ee4f2c2e87407d5cd80b0a22a0a9aca4be841d84dfc3cfbcb492166d0a6a1bdf1bcd471c772eea60906da58da7a048439b7d9637e613a26f80ea269865dda9ceca2c5eea80e9a5acfb8ba83b1b7e80", # noqa: E501 + "0xf90211a07e164dfd7f1ae0e9c7a5276c54f44dde92965a6c2f33a6ab70f15837e7334846a08d1f58f0b8113267e9ae0b00cc2814bafd7abdf64ef092da4022252723ec4009a08e4bd9b065fa8dab94bac469f47a04f2c6cd269c5345de50566a54ec34ef21dba0f9a8d5511d60abf59d66a80a252ea86e3f3b6c325eeac5d861fca7e16c4e4111a006ad844c311fe3730f814ed96a75dd268f609c30bd4476c7842d877cb2baa0aaa076e6eedf4846cb47b5343708159de812ab27f6ad350e68ed70a936bcad30401fa0aa867723f3f21a5eb867ed5c5b99609ea535b967f710e547945e3ec2a212c68fa09d3e7fd8cd22ab508d079b58b40f75c3242f7c7704a82ec1c573f682e2168824a0aba33ff032dc7e10fc3a228adbcff47480580b292c4afee754394c6017872d5ca0ec2cd81c2048e35a4bedee1b27e077129edab50a40972c0f6ccd25bd864bedf2a0371c03a000f78dff313551c7afbf52a1348127ab17b737732191dbd64e68b700a0df0aad31c4c0887c6109cadb0d2341a65f18bc35f6e5583ebd417853b9f56329a07c6437031b7543922a3e6a74ae237a844226db3f632a16dffbedd8679b03b018a0538592d2b6933ab7f0d276e7509151632fbca90c10079ee0c9cce87925b19abaa0d79a8e5a546626e60d5d5c7bb839612a42b5724e880deae4bc282f42496a1ef4a03d172648e5e01d32748c96362e197e37a13aeffa0ae213a23b8898e6508bb6a380", # noqa: E501 + "0xf90211a07f77a654bce6a83ce5674a2936de6ea0768f4f11e19039c8b83ef62956d2ac15a0854518c708b71c9dfb97eaf4c300c0951108dc96ba9877e565cffced4224fbfca0d60083a3e2bdd537e16b3e2a6e62812fad9b7fbec0e56cb76676007fc1ac44eba0105b6a16896fc82d33f9c742890700b9a0312e37d15c7eb12dde2e015ce8920ea0f127c635dcde1f4898e8abcb45a1a8c07a32cc4d78f2f1fdc7386d26f41dc4aea06916ed562e2b84c6a4145a9a3c5716b5493db0637023347a883a3753522a57fea021b88faa7e7af0a40d03950f42abece8892452c3ce5d94266a36d444c8e84d73a0216e4a004f60aa058d227553b404ee93b5758f28d5bed24d6f3a34157b9a18bba0326b9ef2f85defffc61fc3561349969ff8aef23759ab4a4bd49b8dcd1453ee58a0649731f153d117e5ad56b07e3edfb911b3592009da413d952ff7fc2c1e0c8a25a077edfe281169e6425d0795670d9a33ea32ae11ee71896f9064d5a6189ed6693fa0f986846a0fff0ab469ae226de91e3f350757f49e21f48a57fc7c1e4142fa0c3aa0aae0a489f6e8142bce91638db238a1a2d32cc2c31d82eab86d20c89edca5ac3da04a789fc4610da58da2204e3c9f21e351b574b72c7a4194c996e2bc05d3086376a0184a75c2da01cbc27c48a0335318a60c9535ecd54a79bf96a9f821d8202a2080a0c22686c5baef46ef1364919c08a2cfe113cbc2ac0854d2a890df938538a5c36d80", # noqa: E501 + "0xf90211a00b5b38caa0b8e500946e01b36441c04b3932af0af937866756aea01208e630e5a0347a4bd5d736dc5dd178c724de94ca9f3cf351d6cc697f547e115ac955c12762a0fc12087179e3debe3505a5da9cb133650322b5846644289211785ad3ec8c2400a001ef26f67f5ff67e0480d40e9822329c834f2683cc4973d11276c1d252c67d07a0dab8a89872ab8887433393a58c6838f56dd33598c17bc65b67b3975909a1d7d9a0d8e72a6583ec2542c5153d46ff671efcf0e86d3dd6594148be6c8f45b962372aa05d3dfc9d0271fa2e17f1af8a36a105755d7c8ffcd75b523bc9e508d1e4a7f9c5a0367b15490f03ee256758187c63bff678de58c716b94fcee3c68de9b88d4d6d8da0557dd25a49b199b78d194b2c418afcf654415b2db9354b9836490117ac9d768ea0a58e109994f8dccbc777bdf9af2b756c62a1102aba71513f3cbd9aab76fe5d99a034bfcb38403a1a9f3409ea13cb8139f820b702ee757cf87d229949825180a89ea0e3f8b04c275387c6222b6536967f2f1e6fc76dc6ee0e705d3e505f3d07e8bdd4a0deaf89533b13c20ff50ff3f03ff3a2daa8d1329a6a6d17a58c422cbe5ee2f80aa0d0754b6fa85d507289806f64b5ce973e4ded8ec2afb631c2ee13b007eba090cda0a762a467cda2fb000a163abbde837a5d22dc526c8101ad9f32d93dfde1c67765a0508c8133b154fa93189918d82e1048ee0e4094064ddbcee9cfbecf6867546c2380", # noqa: E501 + "0xf90151a000595129cf1c67ce97ed615df7184fb47a0d018d9147a2a7952a639e464cdfd380a052081f67d885b439bee62a1c4e09c02a1ec729aef4d92be6584a29141a79c5c7a0d99cae2bc3b6fc3e8e2767b4d7a5884b9b2d9d20da7890318beefcdb9c7346d58080a0f63571735d99e763dafadb03d1abe3a93a98740ecddc8514d13df46a35a8d94680a081870f4697e57436ccdd8bdc1d624d7bc07861748ff8b3a352334df68f2c03ada0f0252504ee8753335ecf0ca1f73cf13d4505783ed5110bf4e9b384a68ad88f69a0d38a18ef7b993c9ad2d848453e7722c26998ff3d63e243b99cdab0dabf84157ea06e5ad479dbda7f1647ed613e35d837f5d2c697ef34160f3665173186553ee9c280a0bf8371cac505b6ea0cb0f67ef744713f306a2455f3f8844cfa527c62db59c69980a0d6d689405b1cf73786c5fdabb55ec22f9b5712d1ba9c0bfcd46d4b93721fcac780", # noqa: E501 + "0xf8669d37f29e142d49f8824d4e7f1735ec3da219687387629b5fccd86812df84b846f8440180a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a01d93f60f105899172f7255c030301c3af4564edd4a48577dbdc448aec7ddb0ac", # noqa: E501 + ], + "address": "0x7f0d15c7faae65896648c8273b6d7e43f58fa842", + "balance": "0x0", + "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", # noqa: E501 + "nonce": "0x0", + "storageHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", # noqa: E501 + "storageProof": [ + { + "key": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", # noqa: E501 + "proof": [], + "value": "0x0", + } + ], + }, } +# curl https://mainnet.infura.io/v3/YOUR_KEY_HERE \ +# -X POST \ +# -H "Content-Type: application/json" \ +# --data '{"method": "eth_getTransactionReceipt", +# "params": ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"], +# "id": 1,"jsonrpc": "2.0"}' EXPECTED_ACCOUNT_PROOF = [ "0x0ac1030a150157f96e6b86cdefdb3d412547816a82e3e0ebf9d212e8010a1e2f65746865726d696e742e74797065732e76312e4574684163636f756e7412c5010a7f0a2a63726331326c756b75367578656868616b303270793472637a36357a753073776837776a737277307070124f0a282f65746865726d696e742e63727970746f2e76312e657468736563703235366b312e5075624b657912230a21026e710a62a342de0ed4d7c4532dcbcbbafbf19652ed67b237efab70e8b207efac200112423078633564323436303138366637323333633932376537646232646363373033633065353030623635336361383232373362376266616438303435643835613437301a0b0801180120012a03000202222b08011204020402201a2120e2a580b805b8b4d1f80793092cefe57965d9582ba8e31505a72cf31a55fa173d222b08011204040802201a21206c0bd60f0d887a5f99dd023f133dfd12412b074c0c442ab8a25b17048ff34ae022290801122506100220a66ec49c8058aef1eabb21a9610e16227d95982482db0ab5b032f823d457c2b920222b080112040a2e02201a2120af3944b847407590f1b2a95edcd1c2c5408e27a404e0b22267bcc2d46df700ed", # noqa: E501 "0x0aff010a0361636312205632d1620b29d277324e7473898ac9e587a99a62022931b33ce6d0be3b19137b1a090801180120012a0100222708011201011a20f5b8da7f66d134e34242575499b1f125c07af21b36685c31f9a8999c71a21daf222708011201011a20b8ef619094b2b40ae87dd1d3413c5af70d9c43256dfea123ca835baa53ad54a4222708011201011a20b7d06a60784c017041761d99ed17a2d2d68ceb4eccf39bd9a527773f21e5b688222708011201011a20a54531b68a71accb459f478724bde077a82c9079ef2be7e0b8dc47764f1b96d2222708011201011a204f83dd3fed3f48e1dff2fe125c5d22f578b613ddb45bdc12d4bc1841232d9a8b", # noqa: E501 @@ -40,47 +57,106 @@ "jsonrpc": "2.0", "id": 0, "result": { - "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", # noqa: E501 "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", # noqa: E501 "blockNumber": "0x5daf3b", + "chainId": "0x1", "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", "gas": "0xc350", "gasPrice": "0x4a817c800", + "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", # noqa: E501 "input": "0x68656c6c6f21", "nonce": "0x15", "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", "transactionIndex": "0x41", + "type": "0x0", "v": "0x25", "value": "0xf3dbb76162000", }, } +# curl https://mainnet.infura.io/v3/YOUR_KEY_HERE \ +# -X POST \ +# -H "Content-Type: application/json" \ +# -d '{"jsonrpc": "2.0","method": "eth_feeHistory", +# "params": [4, "latest", [25, 75]],"id": 1}' + EXPECTED_FEE_HISTORY = { - "oldestBlock": 3, - "reward": [[220, 7145389], [1000000, 6000213], [550, 550], [125, 12345678]], - "baseFeePerGas": [202583058, 177634473, 155594425, 136217133, 119442408], - "gasUsedRatio": [ - 0.007390479689642084, - 0.0036988514889990873, - 0.0018512333048507866, - 0.00741217041320997, - ], + "jsonrpc": "2.0", + "id": 1, + "result": { + "baseFeePerGas": [ + "0x3043e3967", + "0x2ffe341bf", + "0x309363803", + "0x2b09095a4", + "0x2994cf12a", + ], + "gasUsedRatio": [0.4774405666666667, 0.5485699666666667, 0.0437691, 0.3648538], + "oldestBlock": "0xf15b41", + "reward": [ + ["0x3b9aca00", "0x77359400"], + ["0x59682f00", "0x9502f900"], + ["0x59682f00", "0x59682f00"], + ["0x21797ced", "0x59682f00"], + ], + }, } +# curl https://mainnet.infura.io/v3/YOUR_KEY_HERE \ +# -X POST \ +# -H "Content-Type: application/json" \ +# --data '{"method": "eth_getTransactionReceipt", +# "params": ["0xe25a4c707d3f981afa8ec103b1bc0bee9c6b7bea75e76ffa0a221d5239a7066a"]," +# id": 1,"jsonrpc": "2.0"}' EXPECTED_GET_TRANSACTION_RECEIPT = { - "blockHash": "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd", - "blockNumber": 46147, - "contractAddress": None, - "cumulativeGasUsed": 21000, - "from": "0xA1E4380A3B1f749673E270229993eE55F35663b4", - "gasUsed": 21000, - "logs": [], - "logsBloom": "0x000000000000000000000000000000000000000000000000...0000", - "status": 1, # 0 or 1 - "to": "0x5DF9B87991262F6BA471F09758CDE1c0FC1De734", - "transactionHash": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060", # noqa: E501 - "transactionIndex": 0, + "jsonrpc": "2.0", + "result": { + "blockHash": "0x42aa557e22141e0eba2d42258c010820ef080f2c7ecd0ad18cb53047b7e0421f", # noqa: E501 + "blockNumber": "0xa50131", + "contractAddress": None, + "cumulativeGasUsed": "0xb72e24", + # "effectiveGasPrice": "0x147d357000", + "from": "0x56ac35db407fe1fb4977edd41f712aa5d8e7eb08", + "gasUsed": "0x5208", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", # noqa: E501 + "status": "0x1", + "to": "0x56ac35db407fe1fb4977edd41f712aa5d8e7eb08", + "transactionHash": "0xe25a4c707d3f981afa8ec103b1bc0bee9c6b7bea75e76ffa0a221d5239a7066a", # noqa: E501 + "transactionIndex": "0x9a", + "type": "0x0", + }, + "id": 1, +} + +EXPECTED_CALLTRACERS = { + "from": "0x57f96e6b86cdefdb3d412547816a82e3e0ebf9d2", + "gas": "0x0", + "gasUsed": "0x0", + "input": "0x", + "output": "0x", + "to": "0x378c50d9264c63f3f92b806d4ee56e9d86ffb3ec", + "type": "CALL", + "value": "0x64", +} + +EXPECTED_STRUCT_TRACER = { + "failed": False, + "gas": 21000, + "returnValue": "", + "structLogs": [], +} + +EXPECTED_CONTRACT_CREATE_TRACER = { + "from": "0x57f96e6b86cdefdb3d412547816a82e3e0ebf9d2", + "gas": "0x810ee", + "gasUsed": "0x810ee", + "input": "0x608060405234801561001057600080fd5b50604080518082018252600981526805465737445524332360bc1b60208083019182528351808501909452600484526315195cdd60e21b90840152815191929161005c91600391610176565b508051610070906004906020840190610176565b50505061008e336a52b7d2dcc80cd2e400000061009360201b60201c565b610270565b6001600160a01b0382166100ed5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b80600260008282546100ff919061020f565b90915550506001600160a01b0382166000908152602081905260408120805483929061012c90849061020f565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b82805461018290610235565b90600052602060002090601f0160209004810192826101a457600085556101ea565b82601f106101bd57805160ff19168380011785556101ea565b828001600101855582156101ea579182015b828111156101ea5782518255916020019190600101906101cf565b506101f69291506101fa565b5090565b5b808211156101f657600081556001016101fb565b6000821982111561023057634e487b7160e01b600052601160045260246000fd5b500190565b600181811c9082168061024957607f821691505b6020821081141561026a57634e487b7160e01b600052602260045260246000fd5b50919050565b61088780620002806000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c391906106c4565b60405180910390f35b6100df6100da366004610735565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f36600461075f565b61024a565b604051601281526020016100c3565b6100df610131366004610735565b61026e565b6100f361014436600461079b565b6001600160a01b031660009081526020819052604090205490565b6100b6610290565b6100df610175366004610735565b61029f565b6100df610188366004610735565b61031f565b6100f361019b3660046107bd565b61032d565b6060600380546101af906107f0565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107f0565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b600033610240818585610358565b5060019392505050565b60003361025885828561047c565b6102638585856104f6565b506001949350505050565b600033610240818585610281838361032d565b61028b919061082b565b610358565b6060600480546101af906107f0565b600033816102ad828661032d565b9050838110156103125760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102638286868403610358565b6000336102408185856104f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103ba5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610309565b6001600160a01b03821661041b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610309565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610488848461032d565b905060001981146104f057818110156104e35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610309565b6104f08484848403610358565b50505050565b6001600160a01b03831661055a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610309565b6001600160a01b0382166105bc5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610309565b6001600160a01b038316600090815260208190526040902054818110156106345760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610309565b6001600160a01b0380851660009081526020819052604080822085850390559185168152908120805484929061066b90849061082b565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516106b791815260200190565b60405180910390a36104f0565b600060208083528351808285015260005b818110156106f1578581018301518582016040015282016106d5565b81811115610703576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461073057600080fd5b919050565b6000806040838503121561074857600080fd5b61075183610719565b946020939093013593505050565b60008060006060848603121561077457600080fd5b61077d84610719565b925061078b60208501610719565b9150604084013590509250925092565b6000602082840312156107ad57600080fd5b6107b682610719565b9392505050565b600080604083850312156107d057600080fd5b6107d983610719565b91506107e760208401610719565b90509250929050565b600181811c9082168061080457607f821691505b6020821081141561082557634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561084c57634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220c0d85a7786c0e64745bde36a97db64a8cb6d2d67c277d21b95a0c43bf2d1b86d64736f6c634300080a0033", # noqa: E501 + "output": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c391906106c4565b60405180910390f35b6100df6100da366004610735565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f36600461075f565b61024a565b604051601281526020016100c3565b6100df610131366004610735565b61026e565b6100f361014436600461079b565b6001600160a01b031660009081526020819052604090205490565b6100b6610290565b6100df610175366004610735565b61029f565b6100df610188366004610735565b61031f565b6100f361019b3660046107bd565b61032d565b6060600380546101af906107f0565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107f0565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b600033610240818585610358565b5060019392505050565b60003361025885828561047c565b6102638585856104f6565b506001949350505050565b600033610240818585610281838361032d565b61028b919061082b565b610358565b6060600480546101af906107f0565b600033816102ad828661032d565b9050838110156103125760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102638286868403610358565b6000336102408185856104f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103ba5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610309565b6001600160a01b03821661041b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610309565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610488848461032d565b905060001981146104f057818110156104e35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610309565b6104f08484848403610358565b50505050565b6001600160a01b03831661055a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610309565b6001600160a01b0382166105bc5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610309565b6001600160a01b038316600090815260208190526040902054818110156106345760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610309565b6001600160a01b0380851660009081526020819052604080822085850390559185168152908120805484929061066b90849061082b565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516106b791815260200190565b60405180910390a36104f0565b600060208083528351808285015260005b818110156106f1578581018301518582016040015282016106d5565b81811115610703576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461073057600080fd5b919050565b6000806040838503121561074857600080fd5b61075183610719565b946020939093013593505050565b60008060006060848603121561077457600080fd5b61077d84610719565b925061078b60208501610719565b9150604084013590509250925092565b6000602082840312156107ad57600080fd5b6107b682610719565b9392505050565b600080604083850312156107d057600080fd5b6107d983610719565b91506107e760208401610719565b90509250929050565b600181811c9082168061080457607f821691505b6020821081141561082557634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561084c57634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220c0d85a7786c0e64745bde36a97db64a8cb6d2d67c277d21b95a0c43bf2d1b86d64736f6c634300080a0033", # noqa: E501 + "to": "0x8c76cfc1934d5120cc673b6e5ddf7b88feb1c18c", + "type": "CREATE", + "value": "0x0", } diff --git a/tests/integration_tests/test_filters.py b/tests/integration_tests/test_filters.py index 132301061a..e4ec2fba91 100644 --- a/tests/integration_tests/test_filters.py +++ b/tests/integration_tests/test_filters.py @@ -43,7 +43,7 @@ def test_block_filter(cluster): def test_event_log_filter_by_contract(cluster): w3: Web3 = cluster.w3 - contract = deploy_contract(w3, CONTRACTS["Greeter"]) + contract, _ = deploy_contract(w3, CONTRACTS["Greeter"]) assert contract.caller.greet() == "Hello" # Create new filter from contract @@ -81,7 +81,7 @@ def test_event_log_filter_by_contract(cluster): def test_event_log_filter_by_address(cluster): w3: Web3 = cluster.w3 - contract = deploy_contract(w3, CONTRACTS["Greeter"]) + contract, _ = deploy_contract(w3, CONTRACTS["Greeter"]) assert contract.caller.greet() == "Hello" flt = w3.eth.filter({"address": contract.address}) @@ -103,7 +103,7 @@ def test_event_log_filter_by_address(cluster): def test_get_logs(cluster): w3: Web3 = cluster.w3 - contract = deploy_contract(w3, CONTRACTS["Greeter"]) + contract, _ = deploy_contract(w3, CONTRACTS["Greeter"]) # without tx assert w3.eth.get_logs({"address": contract.address}) == [] diff --git a/tests/integration_tests/test_pruned_node.py b/tests/integration_tests/test_pruned_node.py index 2b61752789..de21d12229 100644 --- a/tests/integration_tests/test_pruned_node.py +++ b/tests/integration_tests/test_pruned_node.py @@ -34,7 +34,7 @@ def test_pruned_node(pruned): test basic json-rpc apis works in pruned node """ w3 = pruned.w3 - erc20 = deploy_contract( + erc20, _ = deploy_contract( w3, CONTRACTS["TestERC20A"], key=KEYS["validator"], diff --git a/tests/integration_tests/test_tracers.py b/tests/integration_tests/test_tracers.py new file mode 100644 index 0000000000..7b30c9786a --- /dev/null +++ b/tests/integration_tests/test_tracers.py @@ -0,0 +1,52 @@ + +from web3 import Web3 + +from .expected_constants import ( + EXPECTED_CALLTRACERS, + EXPECTED_CONTRACT_CREATE_TRACER, + EXPECTED_STRUCT_TRACER, +) +from .utils import ( + ADDRS, + CONTRACTS, + KEYS, + deploy_contract, + send_transaction, + w3_wait_for_new_blocks, +) + + +def test_tracers(ethermint_rpc_ws): + w3: Web3 = ethermint_rpc_ws.w3 + eth_rpc = w3.provider + gas_price = w3.eth.gas_price + tx = {"to": ADDRS["community"], "value": 100, "gasPrice": gas_price} + tx_hash = send_transaction(w3, tx, KEYS["validator"])["transactionHash"].hex() + + tx_res = eth_rpc.make_request("debug_traceTransaction", [tx_hash]) + assert tx_res["result"] == EXPECTED_STRUCT_TRACER, "" + + tx_res = eth_rpc.make_request( + "debug_traceTransaction", [tx_hash, {"tracer": "callTracer"}] + ) + assert tx_res["result"] == EXPECTED_CALLTRACERS, "" + + tx_res = eth_rpc.make_request( + "debug_traceTransaction", + [tx_hash, {"tracer": "callTracer", "tracerConfig": "{'onlyTopCall':True}"}], + ) + assert tx_res["result"] == EXPECTED_CALLTRACERS, "" + + _, tx = deploy_contract( + w3, + CONTRACTS["TestERC20A"], + ) + tx_hash = tx["transactionHash"].hex() + + w3_wait_for_new_blocks(w3, 1) + + tx_res = eth_rpc.make_request( + "debug_traceTransaction", [tx_hash, {"tracer": "callTracer"}] + ) + tx_res["result"]["to"] = EXPECTED_CONTRACT_CREATE_TRACER["to"] + assert tx_res["result"] == EXPECTED_CONTRACT_CREATE_TRACER, "" diff --git a/tests/integration_tests/test_types.py b/tests/integration_tests/test_types.py index 2f41c66c03..9eb6a40add 100644 --- a/tests/integration_tests/test_types.py +++ b/tests/integration_tests/test_types.py @@ -49,8 +49,7 @@ def get_blocks(ethermint_rpc_ws, geth, with_transactions): with_transactions, ], ) - res, err = same_types(eth_rsp, geth_rsp) - assert res, err + compare_types(eth_rsp, geth_rsp) # Get not existing block make_same_rpc_calls( @@ -157,7 +156,7 @@ def test_balance(ethermint_rpc_ws, geth): def deploy_and_wait(w3, number=1): - contract = deploy_contract( + contract, _ = deploy_contract( w3, CONTRACTS["TestERC20A"], ) @@ -179,8 +178,7 @@ def test_get_storage_at(ethermint_rpc_ws, geth): contract = deploy_and_wait(w3) res = eth_rpc.make_request("eth_getStorageAt", [contract.address, "0x0", "latest"]) - res, err = same_types(res["result"], EXPECTED_GET_STORAGE_AT) - assert res, err + compare_types(res["result"], EXPECTED_GET_STORAGE_AT) def send_tnx(w3, tx_value=10): @@ -215,16 +213,15 @@ def test_get_proof(ethermint_rpc_ws, geth): proof = (eth_rpc.make_request( method, [validator, ["0x0"], hex(res["blockNumber"])] ))["result"] - res, err = same_types(proof, EXPECTED_GET_PROOF) - assert res, err + compare_types(proof, EXPECTED_GET_PROOF["result"]) assert proof["accountProof"], EXPECTED_ACCOUNT_PROOF assert proof["storageProof"][0]["proof"], EXPECTED_STORAGE_PROOF - proof = (geth_rpc.make_request( + _ = send_and_get_hash(w3) + proof = eth_rpc.make_request( method, [validator, ["0x0"], "latest"] - ))["result"] - res, err = same_types(proof, EXPECTED_GET_PROOF) - assert res, err + ) + compare_types(proof, EXPECTED_GET_PROOF) def test_get_code(ethermint_rpc_ws, geth): @@ -241,9 +238,8 @@ def test_get_code(ethermint_rpc_ws, geth): # Do an ethereum transfer contract = deploy_and_wait(w3) code = eth_rpc.make_request("eth_getCode", [contract.address, "latest"]) - expected = {"id": "4", "jsonrpc": "2.0", "result": "0x"} - res, err = same_types(code, expected) - assert res, err + expected = {"id": 4, "jsonrpc": "2.0", "result": "0x"} + compare_types(code, expected) def test_get_block_transaction_count(ethermint_rpc_ws, geth): @@ -255,7 +251,7 @@ def test_get_block_transaction_count(ethermint_rpc_ws, geth): ) make_same_rpc_calls( - eth_rpc, geth_rpc, "eth_getBlockTransactionCountByNumber", ["0x100"] + eth_rpc, geth_rpc, "eth_getBlockTransactionCountByNumber", ["0x1000"] ) tx_hash = send_and_get_hash(w3) @@ -267,9 +263,8 @@ def test_get_block_transaction_count(ethermint_rpc_ws, geth): "eth_getBlockTransactionCountByNumber", [block_number] ) - expected = {"id": "1", "jsonrpc": "2.0", "result": "0x1"} - res, err = same_types(block_res, expected) - assert res, err + expected = {"id": 1, "jsonrpc": "2.0", "result": "0x1"} + compare_types(block_res, expected) make_same_rpc_calls( eth_rpc, @@ -278,9 +273,8 @@ def test_get_block_transaction_count(ethermint_rpc_ws, geth): ["0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd"], ) block_res = eth_rpc.make_request("eth_getBlockTransactionCountByHash", [block_hash]) - expected = {"id": "1", "jsonrpc": "2.0", "result": "0x1"} - res, err = same_types(block_res, expected) - assert res, err + expected = {"id": 1, "jsonrpc": "2.0", "result": "0x1"} + compare_types(block_res, expected) def test_get_transaction(ethermint_rpc_ws, geth): @@ -297,8 +291,8 @@ def test_get_transaction(ethermint_rpc_ws, geth): tx_hash = send_and_get_hash(w3) tx_res = eth_rpc.make_request("eth_getTransactionByHash", [tx_hash]) - res, err = same_types(tx_res, EXPECTED_GET_TRANSACTION) - assert res, err + + compare_types(EXPECTED_GET_TRANSACTION, tx_res) def test_get_transaction_receipt(ethermint_rpc_ws, geth): @@ -315,8 +309,7 @@ def test_get_transaction_receipt(ethermint_rpc_ws, geth): tx_hash = send_and_get_hash(w3) tx_res = eth_rpc.make_request("eth_getTransactionReceipt", [tx_hash]) - res, err = same_types(tx_res["result"], EXPECTED_GET_TRANSACTION_RECEIPT) - assert res, err + compare_types(tx_res, EXPECTED_GET_TRANSACTION_RECEIPT) def test_fee_history(ethermint_rpc_ws, geth): @@ -327,10 +320,10 @@ def test_fee_history(ethermint_rpc_ws, geth): make_same_rpc_calls(eth_rpc, geth_rpc, "eth_feeHistory", [4, "0x5000", [10, 90]]) - fee_history = eth_rpc.make_request("eth_feeHistory", [4, "latest", [10, 90]]) + _ = send_and_get_hash(w3) + fee_history = eth_rpc.make_request("eth_feeHistory", [4, "latest", [100]]) - res, err = same_types(fee_history["result"], EXPECTED_FEE_HISTORY) - assert res, err + compare_types(fee_history, EXPECTED_FEE_HISTORY) def test_estimate_gas(ethermint_rpc_ws, geth): @@ -345,11 +338,19 @@ def test_estimate_gas(ethermint_rpc_ws, geth): make_same_rpc_calls(eth_rpc, geth_rpc, "eth_estimateGas", [{}]) +def compare_types(actual, expected): + res, err = same_types(actual, expected) + if not res: + print(err) + print(actual) + print(expected) + assert res, err + + def make_same_rpc_calls(rpc1, rpc2, method, params): res1 = rpc1.make_request(method, params) res2 = rpc2.make_request(method, params) - res, err = same_types(res1, res2) - assert res, err + compare_types(res1, res2) def test_incomplete_send_transaction(ethermint_rpc_ws, geth): @@ -362,37 +363,45 @@ def test_incomplete_send_transaction(ethermint_rpc_ws, geth): make_same_rpc_calls(eth_rpc, geth_rpc, "eth_sendTransaction", [tx]) -def same_types(object_a, object_b): - - if isinstance(object_a, dict): - if not isinstance(object_b, dict): +def same_types(given, expected): + if isinstance(given, dict): + if not isinstance(expected, dict): return False, "A is dict, B is not" - keys = list(set(list(object_a.keys()) + list(object_b.keys()))) + keys = list(set(list(given.keys()) + list(expected.keys()))) for key in keys: - if key in object_b and key in object_a: - if not same_types(object_a[key], object_b[key]): - return False, key + " key on dict are not of same type" - else: - return False, key + " key on json is not in both results" + if key not in expected or key not in given: + return False, key + " key not on both json" + res, err = same_types(given[key], expected[key]) + if not res: + return res, key + " key failed. Error: " + err return True, "" - elif isinstance(object_a, list): - if not isinstance(object_b, list): + elif isinstance(given, list): + if not isinstance(expected, list): return False, "A is list, B is not" - if len(object_a) == 0 and len(object_b) == 0: + if len(given) == 0 and len(expected) == 0: return True, "" - if len(object_a) > 0 and len(object_b) > 0: - return same_types(object_a[0], object_b[0]) + if len(given) > 0 and len(expected) > 0: + return same_types(given[0], expected[0]) else: - return True - elif object_a is None and object_b is None: + return True, "" + elif given is None and expected is None: + return True, "" + elif type(given) is type(expected): return True, "" - elif type(object_a) is type(object_b): + elif ( + type(given) is int + and type(expected) is float + and given == 0 + or type(expected) is int + and type(given) is float + and expected == 0 + ): return True, "" else: return ( False, - "different types. A is type " - + type(object_a).__name__ - + " B is type " - + type(object_b).__name__, + "different types. Given object is type " + + type(given).__name__ + + " expected object is type " + + type(expected).__name__, ) diff --git a/tests/integration_tests/test_upgrade.py b/tests/integration_tests/test_upgrade.py index 18f9d6c3e6..9ce3fbd259 100644 --- a/tests/integration_tests/test_upgrade.py +++ b/tests/integration_tests/test_upgrade.py @@ -97,7 +97,7 @@ def test_cosmovisor_upgrade(custom_ethermint: Ethermint): print("upgrade height", target_height) w3 = custom_ethermint.w3 - contract = deploy_contract(w3, CONTRACTS["TestERC20A"]) + contract, _ = deploy_contract(w3, CONTRACTS["TestERC20A"]) old_height = w3.eth.block_number old_balance = w3.eth.get_balance(ADDRS["validator"], block_identifier=old_height) old_base_fee = w3.eth.get_block(old_height).baseFeePerGas diff --git a/tests/integration_tests/utils.py b/tests/integration_tests/utils.py index 10e0ea5ab3..d53e610d9d 100644 --- a/tests/integration_tests/utils.py +++ b/tests/integration_tests/utils.py @@ -114,7 +114,7 @@ def wait_for_block_time(cli, t): print("wait for block time", t) while True: now = isoparse((cli.status())["SyncInfo"]["latest_block_time"]) - print("block time now:", now) + print("block time now: ", now) if now >= t: break time.sleep(0.5) @@ -131,7 +131,7 @@ def deploy_contract(w3, jsonfile, args=(), key=KEYS["validator"]): txreceipt = send_transaction(w3, tx, key) assert txreceipt.status == 1 address = txreceipt.contractAddress - return w3.eth.contract(address=address, abi=info["abi"]) + return w3.eth.contract(address=address, abi=info["abi"]), txreceipt def fill_defaults(w3, tx): diff --git a/tests/solidity/yarn.lock b/tests/solidity/yarn.lock index d7c6f6bd82..5548bbd216 100644 --- a/tests/solidity/yarn.lock +++ b/tests/solidity/yarn.lock @@ -11043,9 +11043,9 @@ loader-runner@^2.3.0: integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== loader-utils@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.1.tgz#278ad7006660bccc4d2c0c1578e17c5c78d5c0e0" - integrity sha512-1Qo97Y2oKaU+Ro2xnDMR26g1BwMT29jNbem1EvcujW2jqt+j5COXyscjM7bLQkM9HaxI7pkWeW7gnI072yMI9Q== + version "1.4.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3" + integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 5923987fc4..8b8791159b 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -420,7 +420,13 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ txConfig.TxIndex++ } - result, _, err := k.traceTx(ctx, cfg, txConfig, signer, tx, req.TraceConfig, false) + var tracerConfig json.RawMessage + if req.TraceConfig != nil && req.TraceConfig.TracerJsonConfig != "" { + // ignore error. default to no traceConfig + _ = json.Unmarshal([]byte(req.TraceConfig.TracerJsonConfig), &tracerConfig) + } + + result, _, err := k.traceTx(ctx, cfg, txConfig, signer, tx, req.TraceConfig, false, tracerConfig) if err != nil { // error will be returned with detail status from traceTx return nil, err @@ -473,7 +479,7 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) ethTx := tx.AsTransaction() txConfig.TxHash = ethTx.Hash() txConfig.TxIndex = uint(i) - traceResult, logIndex, err := k.traceTx(ctx, cfg, txConfig, signer, ethTx, req.TraceConfig, true) + traceResult, logIndex, err := k.traceTx(ctx, cfg, txConfig, signer, ethTx, req.TraceConfig, true, nil) if err != nil { result.Error = err.Error() continue @@ -502,6 +508,7 @@ func (k *Keeper) traceTx( tx *ethtypes.Transaction, traceConfig *types.TraceConfig, commitMessage bool, + tracerJSONConfig json.RawMessage, ) (*interface{}, uint, error) { // Assemble the structured logger or the JavaScript tracer var ( @@ -542,7 +549,7 @@ func (k *Keeper) traceTx( } if traceConfig.Tracer != "" { - if tracer, err = tracers.New(traceConfig.Tracer, tCtx); err != nil { + if tracer, err = tracers.New(traceConfig.Tracer, tCtx, tracerJSONConfig); err != nil { return nil, 0, status.Error(codes.Internal, err.Error()) } } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index 8629376cce..e887c92220 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -424,7 +424,8 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, return nil, errorsmod.Wrap(types.ErrGasOverflow, "apply message") } // refund gas - leftoverGas += GasToRefund(stateDB.GetRefund(), msg.Gas()-leftoverGas, refundQuotient) + temporaryGasUsed := msg.Gas() - leftoverGas + leftoverGas += GasToRefund(stateDB.GetRefund(), temporaryGasUsed, refundQuotient) // EVM execution error needs to be available for the JSON-RPC client var vmError string @@ -449,7 +450,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, if msg.Gas() < leftoverGas { return nil, errorsmod.Wrapf(types.ErrGasOverflow, "message gas limit < leftover gas (%d < %d)", msg.Gas(), leftoverGas) } - temporaryGasUsed := msg.Gas() - leftoverGas + gasUsed := sdk.MaxDec(minimumGasUsed, sdk.NewDec(int64(temporaryGasUsed))).TruncateInt().Uint64() // reset leftoverGas, to be used by the tracer leftoverGas = msg.Gas() - gasUsed diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index e10d3897c4..b22e3ea7af 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -35,6 +35,8 @@ func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig { ArrowGlacierBlock: getBlockValue(cc.ArrowGlacierBlock), GrayGlacierBlock: getBlockValue(cc.GrayGlacierBlock), MergeNetsplitBlock: getBlockValue(cc.MergeNetsplitBlock), + ShanghaiBlock: nil, // TODO: add shanghai block + CancunBlock: nil, // TODO: add cancun block TerminalTotalDifficulty: nil, Ethash: nil, Clique: nil, diff --git a/x/evm/types/evm.pb.go b/x/evm/types/evm.pb.go index 42580f92ce..73dd41780d 100644 --- a/x/evm/types/evm.pb.go +++ b/x/evm/types/evm.pb.go @@ -550,6 +550,8 @@ type TraceConfig struct { EnableMemory bool `protobuf:"varint,11,opt,name=enable_memory,json=enableMemory,proto3" json:"enableMemory"` // enable return data capture EnableReturnData bool `protobuf:"varint,12,opt,name=enable_return_data,json=enableReturnData,proto3" json:"enableReturnData"` + // tracer config + TracerJsonConfig string `protobuf:"bytes,13,opt,name=tracer_json_config,json=tracerJsonConfig,proto3" json:"tracerConfig"` } func (m *TraceConfig) Reset() { *m = TraceConfig{} } @@ -655,6 +657,13 @@ func (m *TraceConfig) GetEnableReturnData() bool { return false } +func (m *TraceConfig) GetTracerJsonConfig() string { + if m != nil { + return m.TracerJsonConfig + } + return "" +} + func init() { proto.RegisterType((*Params)(nil), "ethermint.evm.v1.Params") proto.RegisterType((*ChainConfig)(nil), "ethermint.evm.v1.ChainConfig") @@ -669,104 +678,105 @@ func init() { func init() { proto.RegisterFile("ethermint/evm/v1/evm.proto", fileDescriptor_d21ecc92c8c8583e) } var fileDescriptor_d21ecc92c8c8583e = []byte{ - // 1538 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0x5d, 0x4f, 0xdc, 0xca, - 0x19, 0x06, 0x76, 0x01, 0xef, 0xec, 0xb2, 0x6b, 0x86, 0x85, 0x6e, 0x88, 0x8a, 0xa9, 0x2f, 0x2a, - 0x2a, 0x25, 0x10, 0x88, 0x50, 0xa3, 0x44, 0x95, 0xca, 0x02, 0x49, 0xa0, 0x69, 0x8a, 0x06, 0xa2, - 0x4a, 0x95, 0x2a, 0x6b, 0xd6, 0x9e, 0x18, 0x17, 0xdb, 0xb3, 0x9a, 0x19, 0x6f, 0x76, 0xdb, 0xfe, - 0x80, 0x56, 0xbd, 0xe9, 0x4f, 0xe8, 0xcf, 0x89, 0xaa, 0x5e, 0xe4, 0xb2, 0x3a, 0x17, 0x56, 0x44, - 0xee, 0xb8, 0xdc, 0x5f, 0x70, 0x34, 0x1f, 0xfb, 0x09, 0x3a, 0xe7, 0xc0, 0x95, 0xe7, 0x79, 0x3f, - 0x9e, 0x67, 0x3e, 0x5e, 0xfb, 0x1d, 0x83, 0x75, 0x22, 0x2e, 0x09, 0x4b, 0xa2, 0x54, 0xec, 0x90, - 0x4e, 0xb2, 0xd3, 0xd9, 0x95, 0x8f, 0xed, 0x36, 0xa3, 0x82, 0x42, 0x7b, 0xe8, 0xdb, 0x96, 0xc6, - 0xce, 0xee, 0x7a, 0x3d, 0xa4, 0x21, 0x55, 0xce, 0x1d, 0x39, 0xd2, 0x71, 0xee, 0x3f, 0x0b, 0x60, - 0xe1, 0x0c, 0x33, 0x9c, 0x70, 0xb8, 0x0b, 0x4a, 0xa4, 0x93, 0x78, 0x01, 0x49, 0x69, 0xd2, 0x98, - 0xdd, 0x9c, 0xdd, 0x2a, 0x35, 0xeb, 0xfd, 0xdc, 0xb1, 0x7b, 0x38, 0x89, 0x5f, 0xba, 0x43, 0x97, - 0x8b, 0x2c, 0xd2, 0x49, 0x8e, 0xe4, 0x10, 0xfe, 0x06, 0x2c, 0x91, 0x14, 0xb7, 0x62, 0xe2, 0xf9, - 0x8c, 0x60, 0x41, 0x1a, 0x73, 0x9b, 0xb3, 0x5b, 0x56, 0xb3, 0xd1, 0xcf, 0x9d, 0xba, 0x49, 0x1b, - 0x77, 0xbb, 0xa8, 0xa2, 0xf1, 0xa1, 0x82, 0xf0, 0xd7, 0xa0, 0x3c, 0xf0, 0xe3, 0x38, 0x6e, 0x14, - 0x54, 0xf2, 0x5a, 0x3f, 0x77, 0xe0, 0x64, 0x32, 0x8e, 0x63, 0x17, 0x01, 0x93, 0x8a, 0xe3, 0x18, - 0x1e, 0x00, 0x40, 0xba, 0x82, 0x61, 0x8f, 0x44, 0x6d, 0xde, 0x28, 0x6e, 0x16, 0xb6, 0x0a, 0x4d, - 0xf7, 0x3a, 0x77, 0x4a, 0xc7, 0xd2, 0x7a, 0x7c, 0x72, 0xc6, 0xfb, 0xb9, 0xb3, 0x6c, 0x48, 0x86, - 0x81, 0x2e, 0x2a, 0x29, 0x70, 0x1c, 0xb5, 0x39, 0xfc, 0x33, 0xa8, 0xf8, 0x97, 0x38, 0x4a, 0x3d, - 0x9f, 0xa6, 0x1f, 0xa3, 0xb0, 0x31, 0xbf, 0x39, 0xbb, 0x55, 0xde, 0xfb, 0xf9, 0xf6, 0xf4, 0xbe, - 0x6d, 0x1f, 0xca, 0xa8, 0x43, 0x15, 0xd4, 0x7c, 0xfc, 0x39, 0x77, 0x66, 0xfa, 0xb9, 0xb3, 0xa2, - 0xa9, 0xc7, 0x09, 0x5c, 0x54, 0xf6, 0x47, 0x91, 0x70, 0x0f, 0xac, 0xe2, 0x38, 0xa6, 0x9f, 0xbc, - 0x2c, 0x95, 0x1b, 0x4d, 0x7c, 0x41, 0x02, 0x4f, 0x74, 0x79, 0x63, 0x41, 0x2e, 0x12, 0xad, 0x28, - 0xe7, 0x87, 0x91, 0xef, 0xa2, 0xcb, 0xdd, 0xff, 0xd5, 0x40, 0x79, 0x4c, 0x0d, 0x26, 0xa0, 0x76, - 0x49, 0x13, 0xc2, 0x05, 0xc1, 0x81, 0xd7, 0x8a, 0xa9, 0x7f, 0x65, 0x8e, 0xe5, 0xe8, 0xbb, 0xdc, - 0xf9, 0x65, 0x18, 0x89, 0xcb, 0xac, 0xb5, 0xed, 0xd3, 0x64, 0xc7, 0xa7, 0x3c, 0xa1, 0xdc, 0x3c, - 0x9e, 0xf2, 0xe0, 0x6a, 0x47, 0xf4, 0xda, 0x84, 0x6f, 0x9f, 0xa4, 0xa2, 0x9f, 0x3b, 0x6b, 0x7a, - 0xb2, 0x53, 0x54, 0x2e, 0xaa, 0x0e, 0x2d, 0x4d, 0x69, 0x80, 0x3d, 0x50, 0x0d, 0x30, 0xf5, 0x3e, - 0x52, 0x76, 0x65, 0xd4, 0xe6, 0x94, 0xda, 0xf9, 0x4f, 0x57, 0xbb, 0xce, 0x9d, 0xca, 0xd1, 0xc1, - 0x1f, 0x5e, 0x53, 0x76, 0xa5, 0x38, 0xfb, 0xb9, 0xb3, 0xaa, 0xd5, 0x27, 0x99, 0x5d, 0x54, 0x09, - 0x30, 0x1d, 0x86, 0xc1, 0x3f, 0x02, 0x7b, 0x18, 0xc0, 0xb3, 0x76, 0x9b, 0x32, 0x61, 0xaa, 0xe1, - 0xe9, 0x75, 0xee, 0x54, 0x0d, 0xe5, 0xb9, 0xf6, 0xf4, 0x73, 0xe7, 0x67, 0x53, 0xa4, 0x26, 0xc7, - 0x45, 0x55, 0x43, 0x6b, 0x42, 0x21, 0x07, 0x15, 0x12, 0xb5, 0x77, 0xf7, 0x9f, 0x99, 0x15, 0x15, - 0xd5, 0x8a, 0xce, 0xee, 0xb5, 0xa2, 0xf2, 0xf1, 0xc9, 0xd9, 0xee, 0xfe, 0xb3, 0xc1, 0x82, 0xcc, - 0xd9, 0x8f, 0xd3, 0xba, 0xa8, 0xac, 0xa1, 0x5e, 0xcd, 0x09, 0x30, 0xd0, 0xbb, 0xc4, 0xfc, 0x52, - 0x55, 0x56, 0xa9, 0xb9, 0x75, 0x9d, 0x3b, 0x40, 0x33, 0xbd, 0xc5, 0xfc, 0x72, 0x74, 0x2e, 0xad, - 0xde, 0x5f, 0x71, 0x2a, 0xa2, 0x2c, 0x19, 0x70, 0x01, 0x9d, 0x2c, 0xa3, 0x86, 0xf3, 0xdf, 0x37, - 0xf3, 0x5f, 0x78, 0xf0, 0xfc, 0xf7, 0xef, 0x9a, 0xff, 0xfe, 0xe4, 0xfc, 0x75, 0xcc, 0x50, 0xf4, - 0x85, 0x11, 0x5d, 0x7c, 0xb0, 0xe8, 0x8b, 0xbb, 0x44, 0x5f, 0x4c, 0x8a, 0xea, 0x18, 0x59, 0xec, - 0x53, 0x3b, 0xd1, 0xb0, 0x1e, 0x5e, 0xec, 0xb7, 0x36, 0xb5, 0x3a, 0xb4, 0x68, 0xb9, 0xbf, 0x83, - 0xba, 0x4f, 0x53, 0x2e, 0xa4, 0x2d, 0xa5, 0xed, 0x98, 0x18, 0xcd, 0x92, 0xd2, 0x3c, 0xb9, 0x97, - 0xe6, 0x63, 0xf3, 0x35, 0xb8, 0x83, 0xcf, 0x45, 0x2b, 0x93, 0x66, 0xad, 0xde, 0x06, 0x76, 0x9b, - 0x08, 0xc2, 0x78, 0x2b, 0x63, 0xa1, 0x51, 0x06, 0x4a, 0xf9, 0xf8, 0x5e, 0xca, 0xe6, 0x3d, 0x98, - 0xe6, 0x72, 0x51, 0x6d, 0x64, 0xd2, 0x8a, 0x7f, 0x01, 0xd5, 0x48, 0x4e, 0xa3, 0x95, 0xc5, 0x46, - 0xaf, 0xac, 0xf4, 0x0e, 0xef, 0xa5, 0x67, 0x5e, 0xe6, 0x49, 0x26, 0x17, 0x2d, 0x0d, 0x0c, 0x5a, - 0x2b, 0x03, 0x30, 0xc9, 0x22, 0xe6, 0x85, 0x31, 0xf6, 0x23, 0xc2, 0x8c, 0x5e, 0x45, 0xe9, 0xbd, - 0xb9, 0x97, 0xde, 0x23, 0xad, 0x77, 0x9b, 0xcd, 0x45, 0xb6, 0x34, 0xbe, 0xd1, 0x36, 0x2d, 0x1b, - 0x80, 0x4a, 0x8b, 0xb0, 0x38, 0x4a, 0x8d, 0xe0, 0x92, 0x12, 0x3c, 0xb8, 0x97, 0xa0, 0xa9, 0xd3, - 0x71, 0x1e, 0x17, 0x95, 0x35, 0x1c, 0xaa, 0xc4, 0x34, 0x0d, 0xe8, 0x40, 0x65, 0xf9, 0xe1, 0x2a, - 0xe3, 0x3c, 0x2e, 0x2a, 0x6b, 0xa8, 0x55, 0xba, 0x60, 0x05, 0x33, 0x46, 0x3f, 0x4d, 0xed, 0x21, - 0x54, 0x62, 0x6f, 0xef, 0x25, 0xb6, 0xae, 0xc5, 0xee, 0xa0, 0x73, 0xd1, 0xb2, 0xb2, 0x4e, 0xec, - 0x62, 0x06, 0x60, 0xc8, 0x70, 0x6f, 0x4a, 0xb8, 0xfe, 0xf0, 0xc3, 0xbb, 0xcd, 0xe6, 0x22, 0x5b, - 0x1a, 0x27, 0x64, 0xff, 0x06, 0xea, 0x09, 0x61, 0x21, 0xf1, 0x52, 0x22, 0x78, 0x3b, 0x8e, 0x84, - 0x11, 0x5e, 0x7d, 0xf8, 0xfb, 0x78, 0x17, 0x9f, 0x8b, 0xa0, 0x32, 0xbf, 0x37, 0x56, 0x25, 0x7e, - 0x5a, 0xb4, 0xaa, 0x76, 0xed, 0xb4, 0x68, 0xd5, 0x6c, 0xfb, 0xb4, 0x68, 0xd9, 0xf6, 0xf2, 0x69, - 0xd1, 0x5a, 0xb1, 0xeb, 0x68, 0xa9, 0x47, 0x63, 0xea, 0x75, 0x9e, 0xeb, 0x5c, 0x54, 0x26, 0x9f, - 0x30, 0x37, 0x5f, 0x14, 0x54, 0xf5, 0xb1, 0xc0, 0x71, 0x8f, 0x1b, 0x62, 0x64, 0x6b, 0xb9, 0xb1, - 0x1e, 0xb7, 0x03, 0xe6, 0xcf, 0x85, 0xbc, 0xe6, 0xd8, 0xa0, 0x70, 0x45, 0x7a, 0xba, 0x77, 0x23, - 0x39, 0x84, 0x75, 0x30, 0xdf, 0xc1, 0x71, 0xa6, 0xef, 0x4b, 0x25, 0xa4, 0x81, 0x7b, 0x06, 0x6a, - 0x17, 0x0c, 0xa7, 0x1c, 0xfb, 0x22, 0xa2, 0xe9, 0x3b, 0x1a, 0x72, 0x08, 0x41, 0x51, 0xf5, 0x10, - 0x9d, 0xab, 0xc6, 0xf0, 0x57, 0xa0, 0x18, 0xd3, 0x90, 0x37, 0xe6, 0x36, 0x0b, 0x5b, 0xe5, 0xbd, - 0xd5, 0xdb, 0x37, 0x96, 0x77, 0x34, 0x44, 0x2a, 0xc4, 0xfd, 0xef, 0x1c, 0x28, 0xbc, 0xa3, 0x21, - 0x6c, 0x80, 0x45, 0x1c, 0x04, 0x8c, 0x70, 0x6e, 0x98, 0x06, 0x10, 0xae, 0x81, 0x05, 0x41, 0xdb, - 0x91, 0xaf, 0xe9, 0x4a, 0xc8, 0x20, 0x29, 0x1c, 0x60, 0x81, 0x55, 0x17, 0xae, 0x20, 0x35, 0x86, - 0x7b, 0xa0, 0xa2, 0x56, 0xe6, 0xa5, 0x59, 0xd2, 0x22, 0x4c, 0x35, 0xd3, 0x62, 0xb3, 0x76, 0x93, - 0x3b, 0x65, 0x65, 0x7f, 0xaf, 0xcc, 0x68, 0x1c, 0xc0, 0x27, 0x60, 0x51, 0x74, 0xc7, 0xfb, 0xe0, - 0xca, 0x4d, 0xee, 0xd4, 0xc4, 0x68, 0x99, 0xb2, 0xcd, 0xa1, 0x05, 0xd1, 0x55, 0xed, 0x6e, 0x07, - 0x58, 0xa2, 0xeb, 0x45, 0x69, 0x40, 0xba, 0xaa, 0xd5, 0x15, 0x9b, 0xf5, 0x9b, 0xdc, 0xb1, 0xc7, - 0xc2, 0x4f, 0xa4, 0x0f, 0x2d, 0x8a, 0xae, 0x1a, 0xc0, 0x27, 0x00, 0xe8, 0x29, 0x29, 0x05, 0xdd, - 0xa8, 0x96, 0x6e, 0x72, 0xa7, 0xa4, 0xac, 0x8a, 0x7b, 0x34, 0x84, 0x2e, 0x98, 0xd7, 0xdc, 0x96, - 0xe2, 0xae, 0xdc, 0xe4, 0x8e, 0x15, 0xd3, 0x50, 0x73, 0x6a, 0x97, 0xdc, 0x2a, 0x46, 0x12, 0xda, - 0x21, 0x81, 0xea, 0x05, 0x16, 0x1a, 0x40, 0xf7, 0x5f, 0x73, 0xc0, 0xba, 0xe8, 0x22, 0xc2, 0xb3, - 0x58, 0xc0, 0xd7, 0xc0, 0xf6, 0x69, 0x2a, 0x18, 0xf6, 0x85, 0x37, 0xb1, 0xb5, 0xcd, 0xc7, 0xa3, - 0xef, 0xf2, 0x74, 0x84, 0x8b, 0x6a, 0x03, 0xd3, 0x81, 0xd9, 0xff, 0x3a, 0x98, 0x6f, 0xc5, 0x94, - 0x26, 0xaa, 0x12, 0x2a, 0x48, 0x03, 0x88, 0xd4, 0xae, 0xa9, 0x53, 0x2e, 0xa8, 0x7b, 0xe9, 0x2f, - 0x6e, 0x9f, 0xf2, 0x54, 0xa9, 0x34, 0xd7, 0xcc, 0xdd, 0xb4, 0xaa, 0xb5, 0x4d, 0xbe, 0x2b, 0xf7, - 0x56, 0x95, 0x92, 0x0d, 0x0a, 0x8c, 0x08, 0x75, 0x68, 0x15, 0x24, 0x87, 0x70, 0x1d, 0x58, 0x8c, - 0x74, 0x08, 0x13, 0x24, 0x50, 0x87, 0x63, 0xa1, 0x21, 0x86, 0x8f, 0x80, 0x15, 0x62, 0xee, 0x65, - 0x9c, 0x04, 0xfa, 0x24, 0xd0, 0x62, 0x88, 0xf9, 0x07, 0x4e, 0x82, 0x97, 0xc5, 0x7f, 0xfc, 0xc7, - 0x99, 0x71, 0x31, 0x28, 0x1f, 0xf8, 0x3e, 0xe1, 0xfc, 0x22, 0x6b, 0xc7, 0xe4, 0x07, 0x2a, 0x6c, - 0x0f, 0x54, 0xb8, 0xa0, 0x0c, 0x87, 0xc4, 0xbb, 0x22, 0x3d, 0x53, 0x67, 0xba, 0x6a, 0x8c, 0xfd, - 0x77, 0xa4, 0xc7, 0xd1, 0x38, 0x30, 0x12, 0x5f, 0x0b, 0xa0, 0x7c, 0xc1, 0xb0, 0x4f, 0xcc, 0x7d, - 0x58, 0xd6, 0xaa, 0x84, 0xcc, 0x48, 0x18, 0x24, 0xb5, 0x45, 0x94, 0x10, 0x9a, 0x09, 0xf3, 0x3e, - 0x0d, 0xa0, 0xcc, 0x60, 0x84, 0x74, 0x89, 0xaf, 0xb6, 0xb1, 0x88, 0x0c, 0x82, 0xfb, 0x60, 0x29, - 0x88, 0xb8, 0xfa, 0xb9, 0xe0, 0x02, 0xfb, 0x57, 0x7a, 0xf9, 0x4d, 0xfb, 0x26, 0x77, 0x2a, 0xc6, - 0x71, 0x2e, 0xed, 0x68, 0x02, 0xc1, 0x57, 0xa0, 0x36, 0x4a, 0x53, 0xb3, 0xd5, 0xd7, 0xf9, 0x26, - 0xbc, 0xc9, 0x9d, 0xea, 0x30, 0x54, 0x79, 0xd0, 0x14, 0x96, 0x27, 0x1d, 0x90, 0x56, 0x16, 0xaa, - 0xe2, 0xb3, 0x90, 0x06, 0xd2, 0x1a, 0x47, 0x49, 0x24, 0x54, 0xb1, 0xcd, 0x23, 0x0d, 0xe0, 0x2b, - 0x50, 0xa2, 0x1d, 0xc2, 0x58, 0x14, 0x10, 0xae, 0x2e, 0x06, 0x3f, 0xf6, 0x67, 0x82, 0x46, 0xf1, - 0x72, 0x71, 0xe6, 0xc7, 0x29, 0x21, 0x09, 0x65, 0x3d, 0xd5, 0xe9, 0xcd, 0xe2, 0xb4, 0xe3, 0xf7, - 0xca, 0x8e, 0x26, 0x10, 0x6c, 0x02, 0x68, 0xd2, 0x18, 0x11, 0x19, 0x4b, 0x3d, 0xf5, 0xfe, 0x57, - 0x54, 0xae, 0x7a, 0x0b, 0xb5, 0x17, 0x29, 0xe7, 0x11, 0x16, 0x18, 0xdd, 0xb2, 0x9c, 0x16, 0xad, - 0xa2, 0x3d, 0x7f, 0x5a, 0xb4, 0x16, 0x6d, 0x6b, 0xb8, 0x7e, 0x33, 0x0b, 0xb4, 0x32, 0xc0, 0x63, - 0xf4, 0xcd, 0xdf, 0x7e, 0xbe, 0xde, 0x98, 0xfd, 0x72, 0xbd, 0x31, 0xfb, 0xf5, 0x7a, 0x63, 0xf6, - 0xdf, 0xdf, 0x36, 0x66, 0xbe, 0x7c, 0xdb, 0x98, 0xf9, 0xff, 0xb7, 0x8d, 0x99, 0x3f, 0x8d, 0x7f, - 0xee, 0x49, 0x47, 0x7e, 0xed, 0x47, 0x7f, 0xbb, 0x5d, 0xf5, 0xbf, 0xab, 0x3e, 0xf9, 0xad, 0x05, - 0xf5, 0x1f, 0xfb, 0xfc, 0xfb, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x44, 0xf1, 0x35, 0x0d, 0x0f, - 0x00, 0x00, + // 1565 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdd, 0x4e, 0x23, 0xc9, + 0x15, 0x06, 0xdc, 0x40, 0xbb, 0x6c, 0xec, 0xa6, 0x30, 0xc4, 0xcb, 0x28, 0x34, 0xe9, 0x8b, 0x88, + 0x48, 0xbb, 0xb0, 0xb0, 0x42, 0x19, 0xed, 0x2a, 0x51, 0x30, 0xb0, 0x33, 0x90, 0xc9, 0x04, 0x15, + 0x8c, 0x22, 0x45, 0x8a, 0x5a, 0xe5, 0xee, 0x9a, 0xa6, 0x87, 0xee, 0x2e, 0xab, 0xaa, 0xda, 0x63, + 0x27, 0x79, 0x80, 0x44, 0xb9, 0xc9, 0x23, 0xcc, 0xe3, 0x8c, 0xa2, 0x5c, 0xcc, 0x65, 0x94, 0x8b, + 0x56, 0xc4, 0xdc, 0x71, 0xe9, 0x27, 0x88, 0xea, 0xc7, 0xbf, 0xa0, 0x64, 0xe1, 0xca, 0xf5, 0x9d, + 0x73, 0xea, 0xfb, 0xaa, 0x4e, 0x9d, 0xf6, 0xa9, 0x02, 0x9b, 0x44, 0x5c, 0x13, 0x96, 0xc6, 0x99, + 0xd8, 0x23, 0xdd, 0x74, 0xaf, 0xbb, 0x2f, 0x7f, 0x76, 0x3b, 0x8c, 0x0a, 0x0a, 0x9d, 0x91, 0x6f, + 0x57, 0x1a, 0xbb, 0xfb, 0x9b, 0x8d, 0x88, 0x46, 0x54, 0x39, 0xf7, 0xe4, 0x48, 0xc7, 0x79, 0x7f, + 0x2d, 0x81, 0xa5, 0x0b, 0xcc, 0x70, 0xca, 0xe1, 0x3e, 0x28, 0x93, 0x6e, 0xea, 0x87, 0x24, 0xa3, + 0x69, 0x73, 0x7e, 0x7b, 0x7e, 0xa7, 0xdc, 0x6a, 0x0c, 0x0a, 0xd7, 0xe9, 0xe3, 0x34, 0xf9, 0xd6, + 0x1b, 0xb9, 0x3c, 0x64, 0x93, 0x6e, 0x7a, 0x22, 0x87, 0xf0, 0x17, 0x60, 0x85, 0x64, 0xb8, 0x9d, + 0x10, 0x3f, 0x60, 0x04, 0x0b, 0xd2, 0x5c, 0xd8, 0x9e, 0xdf, 0xb1, 0x5b, 0xcd, 0x41, 0xe1, 0x36, + 0xcc, 0xb4, 0x49, 0xb7, 0x87, 0xaa, 0x1a, 0x1f, 0x2b, 0x08, 0x7f, 0x0e, 0x2a, 0x43, 0x3f, 0x4e, + 0x92, 0x66, 0x49, 0x4d, 0xde, 0x18, 0x14, 0x2e, 0x9c, 0x9e, 0x8c, 0x93, 0xc4, 0x43, 0xc0, 0x4c, + 0xc5, 0x49, 0x02, 0x8f, 0x00, 0x20, 0x3d, 0xc1, 0xb0, 0x4f, 0xe2, 0x0e, 0x6f, 0x5a, 0xdb, 0xa5, + 0x9d, 0x52, 0xcb, 0xbb, 0x2d, 0xdc, 0xf2, 0xa9, 0xb4, 0x9e, 0x9e, 0x5d, 0xf0, 0x41, 0xe1, 0xae, + 0x1a, 0x92, 0x51, 0xa0, 0x87, 0xca, 0x0a, 0x9c, 0xc6, 0x1d, 0x0e, 0xff, 0x00, 0xaa, 0xc1, 0x35, + 0x8e, 0x33, 0x3f, 0xa0, 0xd9, 0xdb, 0x38, 0x6a, 0x2e, 0x6e, 0xcf, 0xef, 0x54, 0x0e, 0x7e, 0xbc, + 0x3b, 0x9b, 0xb7, 0xdd, 0x63, 0x19, 0x75, 0xac, 0x82, 0x5a, 0xcf, 0x3e, 0x16, 0xee, 0xdc, 0xa0, + 0x70, 0xd7, 0x34, 0xf5, 0x24, 0x81, 0x87, 0x2a, 0xc1, 0x38, 0x12, 0x1e, 0x80, 0x75, 0x9c, 0x24, + 0xf4, 0xbd, 0x9f, 0x67, 0x32, 0xd1, 0x24, 0x10, 0x24, 0xf4, 0x45, 0x8f, 0x37, 0x97, 0xe4, 0x26, + 0xd1, 0x9a, 0x72, 0xbe, 0x19, 0xfb, 0xae, 0x7a, 0xdc, 0xfb, 0x67, 0x1d, 0x54, 0x26, 0xd4, 0x60, + 0x0a, 0xea, 0xd7, 0x34, 0x25, 0x5c, 0x10, 0x1c, 0xfa, 0xed, 0x84, 0x06, 0x37, 0xe6, 0x58, 0x4e, + 0xfe, 0x5d, 0xb8, 0x3f, 0x8d, 0x62, 0x71, 0x9d, 0xb7, 0x77, 0x03, 0x9a, 0xee, 0x05, 0x94, 0xa7, + 0x94, 0x9b, 0x9f, 0xaf, 0x78, 0x78, 0xb3, 0x27, 0xfa, 0x1d, 0xc2, 0x77, 0xcf, 0x32, 0x31, 0x28, + 0xdc, 0x0d, 0xbd, 0xd8, 0x19, 0x2a, 0x0f, 0xd5, 0x46, 0x96, 0x96, 0x34, 0xc0, 0x3e, 0xa8, 0x85, + 0x98, 0xfa, 0x6f, 0x29, 0xbb, 0x31, 0x6a, 0x0b, 0x4a, 0xed, 0xf2, 0x87, 0xab, 0xdd, 0x16, 0x6e, + 0xf5, 0xe4, 0xe8, 0xb7, 0xdf, 0x53, 0x76, 0xa3, 0x38, 0x07, 0x85, 0xbb, 0xae, 0xd5, 0xa7, 0x99, + 0x3d, 0x54, 0x0d, 0x31, 0x1d, 0x85, 0xc1, 0xdf, 0x01, 0x67, 0x14, 0xc0, 0xf3, 0x4e, 0x87, 0x32, + 0x61, 0xaa, 0xe1, 0xab, 0xdb, 0xc2, 0xad, 0x19, 0xca, 0x4b, 0xed, 0x19, 0x14, 0xee, 0x8f, 0x66, + 0x48, 0xcd, 0x1c, 0x0f, 0xd5, 0x0c, 0xad, 0x09, 0x85, 0x1c, 0x54, 0x49, 0xdc, 0xd9, 0x3f, 0xfc, + 0xda, 0xec, 0xc8, 0x52, 0x3b, 0xba, 0x78, 0xd4, 0x8e, 0x2a, 0xa7, 0x67, 0x17, 0xfb, 0x87, 0x5f, + 0x0f, 0x37, 0x64, 0xce, 0x7e, 0x92, 0xd6, 0x43, 0x15, 0x0d, 0xf5, 0x6e, 0xce, 0x80, 0x81, 0xfe, + 0x35, 0xe6, 0xd7, 0xaa, 0xb2, 0xca, 0xad, 0x9d, 0xdb, 0xc2, 0x05, 0x9a, 0xe9, 0x25, 0xe6, 0xd7, + 0xe3, 0x73, 0x69, 0xf7, 0xff, 0x88, 0x33, 0x11, 0xe7, 0xe9, 0x90, 0x0b, 0xe8, 0xc9, 0x32, 0x6a, + 0xb4, 0xfe, 0x43, 0xb3, 0xfe, 0xa5, 0x27, 0xaf, 0xff, 0xf0, 0xa1, 0xf5, 0x1f, 0x4e, 0xaf, 0x5f, + 0xc7, 0x8c, 0x44, 0x9f, 0x1b, 0xd1, 0xe5, 0x27, 0x8b, 0x3e, 0x7f, 0x48, 0xf4, 0xf9, 0xb4, 0xa8, + 0x8e, 0x91, 0xc5, 0x3e, 0x93, 0x89, 0xa6, 0xfd, 0xf4, 0x62, 0xbf, 0x97, 0xd4, 0xda, 0xc8, 0xa2, + 0xe5, 0xfe, 0x0c, 0x1a, 0x01, 0xcd, 0xb8, 0x90, 0xb6, 0x8c, 0x76, 0x12, 0x62, 0x34, 0xcb, 0x4a, + 0xf3, 0xec, 0x51, 0x9a, 0xcf, 0xcc, 0xbf, 0xc1, 0x03, 0x7c, 0x1e, 0x5a, 0x9b, 0x36, 0x6b, 0xf5, + 0x0e, 0x70, 0x3a, 0x44, 0x10, 0xc6, 0xdb, 0x39, 0x8b, 0x8c, 0x32, 0x50, 0xca, 0xa7, 0x8f, 0x52, + 0x36, 0xdf, 0xc1, 0x2c, 0x97, 0x87, 0xea, 0x63, 0x93, 0x56, 0x7c, 0x07, 0x6a, 0xb1, 0x5c, 0x46, + 0x3b, 0x4f, 0x8c, 0x5e, 0x45, 0xe9, 0x1d, 0x3f, 0x4a, 0xcf, 0x7c, 0xcc, 0xd3, 0x4c, 0x1e, 0x5a, + 0x19, 0x1a, 0xb4, 0x56, 0x0e, 0x60, 0x9a, 0xc7, 0xcc, 0x8f, 0x12, 0x1c, 0xc4, 0x84, 0x19, 0xbd, + 0xaa, 0xd2, 0x7b, 0xf1, 0x28, 0xbd, 0x2f, 0xb4, 0xde, 0x7d, 0x36, 0x0f, 0x39, 0xd2, 0xf8, 0x42, + 0xdb, 0xb4, 0x6c, 0x08, 0xaa, 0x6d, 0xc2, 0x92, 0x38, 0x33, 0x82, 0x2b, 0x4a, 0xf0, 0xe8, 0x51, + 0x82, 0xa6, 0x4e, 0x27, 0x79, 0x3c, 0x54, 0xd1, 0x70, 0xa4, 0x92, 0xd0, 0x2c, 0xa4, 0x43, 0x95, + 0xd5, 0xa7, 0xab, 0x4c, 0xf2, 0x78, 0xa8, 0xa2, 0xa1, 0x56, 0xe9, 0x81, 0x35, 0xcc, 0x18, 0x7d, + 0x3f, 0x93, 0x43, 0xa8, 0xc4, 0x5e, 0x3e, 0x4a, 0x6c, 0x53, 0x8b, 0x3d, 0x40, 0xe7, 0xa1, 0x55, + 0x65, 0x9d, 0xca, 0x62, 0x0e, 0x60, 0xc4, 0x70, 0x7f, 0x46, 0xb8, 0xf1, 0xf4, 0xc3, 0xbb, 0xcf, + 0xe6, 0x21, 0x47, 0x1a, 0xa7, 0x64, 0xff, 0x04, 0x1a, 0x29, 0x61, 0x11, 0xf1, 0x33, 0x22, 0x78, + 0x27, 0x89, 0x85, 0x11, 0x5e, 0x7f, 0xfa, 0xf7, 0xf8, 0x10, 0x9f, 0x87, 0xa0, 0x32, 0xbf, 0x36, + 0x56, 0x25, 0x7e, 0x6e, 0xd9, 0x35, 0xa7, 0x7e, 0x6e, 0xd9, 0x75, 0xc7, 0x39, 0xb7, 0x6c, 0xc7, + 0x59, 0x3d, 0xb7, 0xec, 0x35, 0xa7, 0x81, 0x56, 0xfa, 0x34, 0xa1, 0x7e, 0xf7, 0x1b, 0x3d, 0x17, + 0x55, 0xc8, 0x7b, 0xcc, 0xcd, 0x3f, 0x0a, 0xaa, 0x05, 0x58, 0xe0, 0xa4, 0xcf, 0x0d, 0x31, 0x72, + 0xb4, 0xdc, 0x44, 0x8f, 0xdb, 0x03, 0x8b, 0x97, 0x42, 0x5e, 0x73, 0x1c, 0x50, 0xba, 0x21, 0x7d, + 0xdd, 0xbb, 0x91, 0x1c, 0xc2, 0x06, 0x58, 0xec, 0xe2, 0x24, 0xd7, 0xf7, 0xa5, 0x32, 0xd2, 0xc0, + 0xbb, 0x00, 0xf5, 0x2b, 0x86, 0x33, 0x8e, 0x03, 0x11, 0xd3, 0xec, 0x15, 0x8d, 0x38, 0x84, 0xc0, + 0x52, 0x3d, 0x44, 0xcf, 0x55, 0x63, 0xf8, 0x33, 0x60, 0x25, 0x34, 0xe2, 0xcd, 0x85, 0xed, 0xd2, + 0x4e, 0xe5, 0x60, 0xfd, 0xfe, 0x8d, 0xe5, 0x15, 0x8d, 0x90, 0x0a, 0xf1, 0xfe, 0xb1, 0x00, 0x4a, + 0xaf, 0x68, 0x04, 0x9b, 0x60, 0x19, 0x87, 0x21, 0x23, 0x9c, 0x1b, 0xa6, 0x21, 0x84, 0x1b, 0x60, + 0x49, 0xd0, 0x4e, 0x1c, 0x68, 0xba, 0x32, 0x32, 0x48, 0x0a, 0x87, 0x58, 0x60, 0xd5, 0x85, 0xab, + 0x48, 0x8d, 0xe1, 0x01, 0xa8, 0xaa, 0x9d, 0xf9, 0x59, 0x9e, 0xb6, 0x09, 0x53, 0xcd, 0xd4, 0x6a, + 0xd5, 0xef, 0x0a, 0xb7, 0xa2, 0xec, 0xaf, 0x95, 0x19, 0x4d, 0x02, 0xf8, 0x25, 0x58, 0x16, 0xbd, + 0xc9, 0x3e, 0xb8, 0x76, 0x57, 0xb8, 0x75, 0x31, 0xde, 0xa6, 0x6c, 0x73, 0x68, 0x49, 0xf4, 0x54, + 0xbb, 0xdb, 0x03, 0xb6, 0xe8, 0xf9, 0x71, 0x16, 0x92, 0x9e, 0x6a, 0x75, 0x56, 0xab, 0x71, 0x57, + 0xb8, 0xce, 0x44, 0xf8, 0x99, 0xf4, 0xa1, 0x65, 0xd1, 0x53, 0x03, 0xf8, 0x25, 0x00, 0x7a, 0x49, + 0x4a, 0x41, 0x37, 0xaa, 0x95, 0xbb, 0xc2, 0x2d, 0x2b, 0xab, 0xe2, 0x1e, 0x0f, 0xa1, 0x07, 0x16, + 0x35, 0xb7, 0xad, 0xb8, 0xab, 0x77, 0x85, 0x6b, 0x27, 0x34, 0xd2, 0x9c, 0xda, 0x25, 0x53, 0xc5, + 0x48, 0x4a, 0xbb, 0x24, 0x54, 0xbd, 0xc0, 0x46, 0x43, 0xe8, 0xfd, 0x6d, 0x01, 0xd8, 0x57, 0x3d, + 0x44, 0x78, 0x9e, 0x08, 0xf8, 0x3d, 0x70, 0x02, 0x9a, 0x09, 0x86, 0x03, 0xe1, 0x4f, 0xa5, 0xb6, + 0xf5, 0x6c, 0xfc, 0xbf, 0x3c, 0x1b, 0xe1, 0xa1, 0xfa, 0xd0, 0x74, 0x64, 0xf2, 0xdf, 0x00, 0x8b, + 0xed, 0x84, 0xd2, 0x54, 0x55, 0x42, 0x15, 0x69, 0x00, 0x91, 0xca, 0x9a, 0x3a, 0xe5, 0x92, 0xba, + 0x97, 0xfe, 0xe4, 0xfe, 0x29, 0xcf, 0x94, 0x4a, 0x6b, 0xc3, 0xdc, 0x4d, 0x6b, 0x5a, 0xdb, 0xcc, + 0xf7, 0x64, 0x6e, 0x55, 0x29, 0x39, 0xa0, 0xc4, 0x88, 0x50, 0x87, 0x56, 0x45, 0x72, 0x08, 0x37, + 0x81, 0xcd, 0x48, 0x97, 0x30, 0x41, 0x42, 0x75, 0x38, 0x36, 0x1a, 0x61, 0xf8, 0x05, 0xb0, 0x23, + 0xcc, 0xfd, 0x9c, 0x93, 0x50, 0x9f, 0x04, 0x5a, 0x8e, 0x30, 0x7f, 0xc3, 0x49, 0xf8, 0xad, 0xf5, + 0x97, 0x0f, 0xee, 0x9c, 0x87, 0x41, 0xe5, 0x28, 0x08, 0x08, 0xe7, 0x57, 0x79, 0x27, 0x21, 0xff, + 0xa3, 0xc2, 0x0e, 0x40, 0x95, 0x0b, 0xca, 0x70, 0x44, 0xfc, 0x1b, 0xd2, 0x37, 0x75, 0xa6, 0xab, + 0xc6, 0xd8, 0x7f, 0x4d, 0xfa, 0x1c, 0x4d, 0x02, 0x23, 0xf1, 0xc1, 0x02, 0x95, 0x2b, 0x86, 0x03, + 0x62, 0xee, 0xc3, 0xb2, 0x56, 0x25, 0x64, 0x46, 0xc2, 0x20, 0xa9, 0x2d, 0xe2, 0x94, 0xd0, 0x5c, + 0x98, 0xef, 0x69, 0x08, 0xe5, 0x0c, 0x46, 0x48, 0x8f, 0x04, 0x2a, 0x8d, 0x16, 0x32, 0x08, 0x1e, + 0x82, 0x95, 0x30, 0xe6, 0xea, 0x71, 0xc1, 0x05, 0x0e, 0x6e, 0xf4, 0xf6, 0x5b, 0xce, 0x5d, 0xe1, + 0x56, 0x8d, 0xe3, 0x52, 0xda, 0xd1, 0x14, 0x82, 0xdf, 0x81, 0xfa, 0x78, 0x9a, 0x5a, 0xad, 0xbe, + 0xce, 0xb7, 0xe0, 0x5d, 0xe1, 0xd6, 0x46, 0xa1, 0xca, 0x83, 0x66, 0xb0, 0x3c, 0xe9, 0x90, 0xb4, + 0xf3, 0x48, 0x15, 0x9f, 0x8d, 0x34, 0x90, 0xd6, 0x24, 0x4e, 0x63, 0xa1, 0x8a, 0x6d, 0x11, 0x69, + 0x00, 0xbf, 0x03, 0x65, 0xda, 0x25, 0x8c, 0xc5, 0x21, 0xe1, 0xea, 0x62, 0xf0, 0xff, 0x5e, 0x26, + 0x68, 0x1c, 0x2f, 0x37, 0x67, 0x1e, 0x4e, 0x29, 0x49, 0x29, 0xeb, 0xab, 0x4e, 0x6f, 0x36, 0xa7, + 0x1d, 0xbf, 0x51, 0x76, 0x34, 0x85, 0x60, 0x0b, 0x40, 0x33, 0x8d, 0x11, 0x91, 0xb3, 0xcc, 0x57, + 0xdf, 0x7f, 0x55, 0xcd, 0x55, 0x5f, 0xa1, 0xf6, 0x22, 0xe5, 0x3c, 0xc1, 0x02, 0xa3, 0x7b, 0x16, + 0xf8, 0x4b, 0x00, 0xf5, 0x99, 0xf8, 0xef, 0x38, 0x1d, 0x3d, 0xad, 0x74, 0x23, 0x56, 0xfa, 0xda, + 0x6b, 0xd6, 0xec, 0x68, 0x74, 0xce, 0xa9, 0xd9, 0xc5, 0xb9, 0x65, 0x5b, 0xce, 0xe2, 0xb9, 0x65, + 0x2f, 0x3b, 0xf6, 0x28, 0x7f, 0x66, 0x17, 0x68, 0x6d, 0x88, 0x27, 0x96, 0xd7, 0xfa, 0xd5, 0xc7, + 0xdb, 0xad, 0xf9, 0x4f, 0xb7, 0x5b, 0xf3, 0xff, 0xb9, 0xdd, 0x9a, 0xff, 0xfb, 0xe7, 0xad, 0xb9, + 0x4f, 0x9f, 0xb7, 0xe6, 0xfe, 0xf5, 0x79, 0x6b, 0xee, 0xf7, 0x93, 0xed, 0x82, 0x74, 0x65, 0xb7, + 0x18, 0xbf, 0x96, 0x7b, 0xea, 0xbd, 0xac, 0x5a, 0x46, 0x7b, 0x49, 0xbd, 0x83, 0xbf, 0xf9, 0x6f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xc5, 0xf8, 0x3d, 0xb7, 0x4d, 0x0f, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -1380,6 +1390,13 @@ func (m *TraceConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.TracerJsonConfig) > 0 { + i -= len(m.TracerJsonConfig) + copy(dAtA[i:], m.TracerJsonConfig) + i = encodeVarintEvm(dAtA, i, uint64(len(m.TracerJsonConfig))) + i-- + dAtA[i] = 0x6a + } if m.EnableReturnData { i-- if m.EnableReturnData { @@ -1753,6 +1770,10 @@ func (m *TraceConfig) Size() (n int) { if m.EnableReturnData { n += 2 } + l = len(m.TracerJsonConfig) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } return n } @@ -3777,6 +3798,38 @@ func (m *TraceConfig) Unmarshal(dAtA []byte) error { } } m.EnableReturnData = bool(v != 0) + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TracerJsonConfig", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TracerJsonConfig = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvm(dAtA[iNdEx:])