From 227b488827f376c84e6c0a792f6c4de2b1fbfcf9 Mon Sep 17 00:00:00 2001 From: lcmmhcc <37269413+lcmmhcc@users.noreply.github.com> Date: Mon, 7 Feb 2022 18:53:09 +0800 Subject: [PATCH] Merge PR: support for debug trace tx (#1427) Co-authored-by: KamiD <44460798+KamiD@users.noreply.github.com> --- app/ante/eth.go | 3 +- app/rpc/apis.go | 11 +++ app/rpc/config.go | 7 +- app/rpc/namespaces/debug/api.go | 50 ++++++++++ cmd/client/flags.go | 1 + go.mod | 6 +- go.sum | 36 ++++++-- libs/cosmos-sdk/baseapp/abci.go | 22 +++++ libs/cosmos-sdk/baseapp/baseapp.go | 48 +++++++++- libs/cosmos-sdk/baseapp/baseapp_mod_trace.go | 3 + libs/cosmos-sdk/baseapp/baseapp_mode_base.go | 7 ++ libs/cosmos-sdk/baseapp/baseapp_runtx.go | 24 +++-- libs/cosmos-sdk/baseapp/helpers_okchain.go | 97 +++++++++++++++++++- libs/cosmos-sdk/types/context.go | 18 ++++ x/evm/handler.go | 25 ++++- x/evm/types/state_transition.go | 63 +++++++++---- x/evm/types/tracer.go | 78 +++++++++++++++- 17 files changed, 450 insertions(+), 49 deletions(-) create mode 100644 app/rpc/namespaces/debug/api.go create mode 100644 libs/cosmos-sdk/baseapp/baseapp_mod_trace.go diff --git a/app/ante/eth.go b/app/ante/eth.go index 3a30e364b3..6a0303b756 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -438,7 +438,8 @@ func (issd IncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk. // when mempool is not in enableRecheck mode, we should not increment the nonce // when IsCheckTx() is true, it will means checkTx and recheckTx mode, but IsReCheckTx() is true it must be recheckTx mode - if ctx.IsCheckTx() && !ctx.IsReCheckTx() && !baseapp.IsMempoolEnableRecheck() { + // if IsTraceMode is true, sequence must be set. + if ctx.IsCheckTx() && !ctx.IsReCheckTx() && !baseapp.IsMempoolEnableRecheck() && !ctx.IsTraceTx() { return next(ctx, tx, simulate) } diff --git a/app/rpc/apis.go b/app/rpc/apis.go index 0eae7a442d..07cf64efda 100644 --- a/app/rpc/apis.go +++ b/app/rpc/apis.go @@ -19,6 +19,7 @@ import ( "github.com/okex/exchain/app/crypto/ethsecp256k1" "github.com/okex/exchain/app/rpc/backend" "github.com/okex/exchain/app/rpc/monitor" + "github.com/okex/exchain/app/rpc/namespaces/debug" "github.com/okex/exchain/app/rpc/namespaces/eth" "github.com/okex/exchain/app/rpc/namespaces/eth/filters" "github.com/okex/exchain/app/rpc/namespaces/net" @@ -34,6 +35,7 @@ const ( PersonalNamespace = "personal" NetNamespace = "net" TxpoolNamespace = "txpool" + DebugNamespace = "debug" apiVersion = "1.0" ) @@ -99,6 +101,15 @@ func GetAPIs(clientCtx context.CLIContext, log log.Logger, keys ...ethsecp256k1. }) } + if viper.GetBool(FlagDebugAPI) { + apis = append(apis, rpc.API{ + Namespace: DebugNamespace, + Version: apiVersion, + Service: debug.NewAPI(clientCtx, log, ethBackend), + Public: true, + }) + } + if viper.GetBool(FlagEnableMonitor) { for _, api := range apis { makeMonitorMetrics(api.Namespace, api.Service) diff --git a/app/rpc/config.go b/app/rpc/config.go index b9c0a81e8a..87366ba786 100644 --- a/app/rpc/config.go +++ b/app/rpc/config.go @@ -19,14 +19,15 @@ import ( cmserver "github.com/okex/exchain/libs/cosmos-sdk/server" sdk "github.com/okex/exchain/libs/cosmos-sdk/types" "github.com/okex/exchain/libs/tendermint/libs/log" + "github.com/spf13/viper" ) const ( - flagUnlockKey = "unlock-key" - flagWebsocket = "wsport" - + flagUnlockKey = "unlock-key" + flagWebsocket = "wsport" FlagPersonalAPI = "personal-api" + FlagDebugAPI = "debug-api" FlagRateLimitAPI = "rpc.rate-limit-api" FlagRateLimitCount = "rpc.rate-limit-count" FlagRateLimitBurst = "rpc.rate-limit-burst" diff --git a/app/rpc/namespaces/debug/api.go b/app/rpc/namespaces/debug/api.go new file mode 100644 index 0000000000..8a25390629 --- /dev/null +++ b/app/rpc/namespaces/debug/api.go @@ -0,0 +1,50 @@ +package debug + +import ( + "encoding/json" + + sdk "github.com/okex/exchain/libs/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common" + clientcontext "github.com/okex/exchain/libs/cosmos-sdk/client/context" + + "github.com/okex/exchain/app/rpc/backend" + "github.com/okex/exchain/libs/tendermint/libs/log" +) + +// PublicTxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential. +type PublicDebugAPI struct { + clientCtx clientcontext.CLIContext + logger log.Logger + backend backend.Backend +} + +// NewPublicTxPoolAPI creates a new tx pool service that gives information about the transaction pool. +func NewAPI(clientCtx clientcontext.CLIContext, log log.Logger, backend backend.Backend) *PublicDebugAPI { + api := &PublicDebugAPI{ + clientCtx: clientCtx, + backend: backend, + logger: log.With("module", "json-rpc", "namespace", "debug"), + } + return api +} + +// TraceTransaction returns the structured logs created during the execution of EVM +// and returns them as a JSON object. +func (api *PublicDebugAPI) TraceTransaction(txHash common.Hash) (interface{}, error) { + resTrace, _, err := api.clientCtx.QueryWithData("app/trace", txHash.Bytes()) + if err != nil { + return nil, err + } + + var res sdk.Result + if err := api.clientCtx.Codec.UnmarshalBinaryBare(resTrace, &res); err != nil { + return nil, err + } + var decodedResult interface{} + if err := json.Unmarshal(res.Data, &decodedResult); err != nil { + return nil, err + } + + return decodedResult, nil +} diff --git a/cmd/client/flags.go b/cmd/client/flags.go index 94cdeb9632..c3cf65a776 100644 --- a/cmd/client/flags.go +++ b/cmd/client/flags.go @@ -23,6 +23,7 @@ func RegisterAppFlag(cmd *cobra.Command) { cmd.Flags().Int(watcher.FlagFastQueryLru, 1000, "Set the size of LRU cache under fast-query mode") cmd.Flags().Bool(watcher.FlagCheckWd, false, "Enable check watchDB in log") cmd.Flags().Bool(rpc.FlagPersonalAPI, true, "Enable the personal_ prefixed set of APIs in the Web3 JSON-RPC spec") + cmd.Flags().Bool(rpc.FlagDebugAPI, false, "Enable the debug_ prefixed set of APIs in the Web3 JSON-RPC spec") cmd.Flags().Bool(evmtypes.FlagEnableBloomFilter, false, "Enable bloom filter for event logs") cmd.Flags().Int64(filters.FlagGetLogsHeightSpan, 2000, "config the block height span for get logs") // register application rpc to nacos diff --git a/go.mod b/go.mod index 9686f67e5a..e1eeb51bdc 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/go-kit/kit v0.10.0 github.com/go-logfmt/logfmt v0.5.0 github.com/go-redis/redis/v8 v8.11.4 - github.com/gogo/protobuf v1.3.1 + github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.3.1 github.com/golang/protobuf v1.5.2 github.com/google/btree v1.0.0 @@ -63,11 +63,11 @@ require ( github.com/tendermint/go-amino v0.15.1 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/willf/bitset v1.1.11 - go.etcd.io/bbolt v1.3.4 + go.etcd.io/bbolt v1.3.6 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba - google.golang.org/grpc v1.29.1 + google.golang.org/grpc v1.42.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 370d6ec6ea..7de74aee63 100644 --- a/go.sum +++ b/go.sum @@ -77,6 +77,7 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -152,6 +153,11 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= @@ -210,6 +216,8 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -271,8 +279,9 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= @@ -316,6 +325,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= @@ -330,6 +340,7 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -352,6 +363,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= @@ -446,6 +458,7 @@ github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM5 github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= @@ -648,6 +661,7 @@ github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1 github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -761,6 +775,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= @@ -768,14 +783,15 @@ github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -839,6 +855,7 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -865,6 +882,7 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -926,12 +944,12 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -995,7 +1013,9 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1039,6 +1059,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1053,8 +1074,10 @@ google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1063,6 +1086,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= diff --git a/libs/cosmos-sdk/baseapp/abci.go b/libs/cosmos-sdk/baseapp/abci.go index 17ab95290f..3d1a4c1ed4 100644 --- a/libs/cosmos-sdk/baseapp/abci.go +++ b/libs/cosmos-sdk/baseapp/abci.go @@ -371,6 +371,28 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res Height: req.Height, Value: codec.Cdc.MustMarshalBinaryBare(simRes), } + case "trace": + tmtx, err := GetABCITx(req.Data) + if err != nil { + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "invalid trace tx bytes")) + } + tx, err := app.txDecoder(tmtx.Tx, tmtx.Height) + if err != nil { + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx")) + } + block, err := GetABCIBlock(tmtx.Height) + if err != nil { + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "invalid trace tx block header")) + } + res, err := app.TraceTx(req.Data, tx, tmtx.Index, block.Block) + if err != nil { + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to trace tx")) + } + return abci.ResponseQuery{ + Codespace: sdkerrors.RootCodespace, + Height: req.Height, + Value: codec.Cdc.MustMarshalBinaryBare(res), + } case "version": return abci.ResponseQuery{ diff --git a/libs/cosmos-sdk/baseapp/baseapp.go b/libs/cosmos-sdk/baseapp/baseapp.go index 50d030a0f8..2e6ed3d484 100644 --- a/libs/cosmos-sdk/baseapp/baseapp.go +++ b/libs/cosmos-sdk/baseapp/baseapp.go @@ -22,6 +22,7 @@ import ( "github.com/okex/exchain/libs/tendermint/libs/log" "github.com/okex/exchain/libs/tendermint/mempool" tmhttp "github.com/okex/exchain/libs/tendermint/rpc/client/http" + ctypes "github.com/okex/exchain/libs/tendermint/rpc/core/types" tmtypes "github.com/okex/exchain/libs/tendermint/types" dbm "github.com/okex/exchain/libs/tm-db" "github.com/spf13/viper" @@ -33,6 +34,7 @@ const ( runTxModeSimulate // Simulate a transaction runTxModeDeliver // Deliver a transaction runTxModeDeliverInAsync //Deliver a transaction in Aysnc + runTxModeTrace // Trace a transaction runTxModeWrappedCheck // MainStoreKey is the string representation of the main store @@ -511,6 +513,20 @@ func (app *BaseApp) setDeliverState(header abci.Header) { } } +// setTraceState sets the BaseApp's traceState with a cache-wrapped multi-store +// (i.e. a CacheMultiStore) and a new Context with the cache-wrapped multi-store, +// and provided header. It is set at the start of trace tx +func (app *BaseApp) newTraceState(header abci.Header, height int64) (*state, error) { + ms, err := app.cms.CacheMultiStoreWithVersion(height) + if err != nil { + return nil, err + } + return &state{ + ms: ms, + ctx: sdk.NewContext(ms, header, false, app.logger), + }, nil +} + // setConsensusParams memoizes the consensus params. func (app *BaseApp) setConsensusParams(consensusParams *abci.ConsensusParams) { app.consensusParams = consensusParams @@ -641,24 +657,48 @@ func (app *BaseApp) getContextForSimTx(txBytes []byte, height int64) (sdk.Contex return ctx, nil } +func GetABCITx(hash []byte) (*ctypes.ResultTx, error) { + laddr := viper.GetString("rpc.laddr") + splits := strings.Split(laddr, ":") + if len(splits) < 2 { + return nil, fmt.Errorf("get tx failed!") + } -func GetABCIHeader(height int64) (abci.Header, error) { + rpcCli, err := tmhttp.New(fmt.Sprintf("tcp://127.0.0.1:%s", splits[len(splits)-1]), "/websocket") + if err != nil { + return nil, fmt.Errorf("get tx failed!") + } + + tx, err := rpcCli.Tx(hash, false) + if err != nil { + return nil, fmt.Errorf("get ABCI tx failed!") + } + + return tx, nil +} +func GetABCIBlock(height int64) (*ctypes.ResultBlock, error) { laddr := viper.GetString("rpc.laddr") splits := strings.Split(laddr, ":") if len(splits) < 2 { - return abci.Header{}, fmt.Errorf("get ABCI header failed!") + return nil, fmt.Errorf("get tendermint Block failed!") } rpcCli, err := tmhttp.New(fmt.Sprintf("tcp://127.0.0.1:%s", splits[len(splits)-1]), "/websocket") if err != nil { - return abci.Header{}, fmt.Errorf("get ABCI header failed!") + return nil, fmt.Errorf("get tendermint Block failed!") } block, err := rpcCli.Block(&height) + if err != nil { + return nil, fmt.Errorf("get tendermint Block failed!") + } + return block, nil +} +func GetABCIHeader(height int64) (abci.Header, error) { + block, err := GetABCIBlock(height) if err != nil { return abci.Header{}, fmt.Errorf("get ABCI header failed!") } - return blockHeaderToABCIHeader(block.Block.Header), nil } diff --git a/libs/cosmos-sdk/baseapp/baseapp_mod_trace.go b/libs/cosmos-sdk/baseapp/baseapp_mod_trace.go new file mode 100644 index 0000000000..c05ccb554c --- /dev/null +++ b/libs/cosmos-sdk/baseapp/baseapp_mod_trace.go @@ -0,0 +1,3 @@ +package baseapp + +func (m *modeHandlerTrace) handleStartHeight(info *runTxInfo, height int64) (err error) { return } diff --git a/libs/cosmos-sdk/baseapp/baseapp_mode_base.go b/libs/cosmos-sdk/baseapp/baseapp_mode_base.go index 628edec1c1..175f41afd7 100644 --- a/libs/cosmos-sdk/baseapp/baseapp_mode_base.go +++ b/libs/cosmos-sdk/baseapp/baseapp_mode_base.go @@ -29,6 +29,8 @@ func (app *BaseApp) getModeHandler(mode runTxMode) modeHandler { h = &modeHandlerCheck{&modeHandlerBase{mode: mode, app: app}} case runTxModeReCheck: h = &modeHandlerRecheck{&modeHandlerBase{mode: mode, app: app}} + case runTxModeTrace: + h = &modeHandlerTrace{&modeHandlerDeliver{&modeHandlerBase{mode: mode, app: app}}} case runTxModeDeliver: h = &modeHandlerDeliver{&modeHandlerBase{mode: mode, app: app}} case runTxModeSimulate: @@ -66,6 +68,11 @@ type modeHandlerSimulate struct { *modeHandlerBase } +//modeHandlerTrace derived from modeHandlerDeliver +type modeHandlerTrace struct { + *modeHandlerDeliver +} + func (m *modeHandlerBase) getMode() runTxMode { return m.mode } diff --git a/libs/cosmos-sdk/baseapp/baseapp_runtx.go b/libs/cosmos-sdk/baseapp/baseapp_runtx.go index ec21eb578b..a7e9784ca5 100644 --- a/libs/cosmos-sdk/baseapp/baseapp_runtx.go +++ b/libs/cosmos-sdk/baseapp/baseapp_runtx.go @@ -39,17 +39,28 @@ func (app *BaseApp) runTx(mode runTxMode, func (app *BaseApp) runtx(mode runTxMode, txBytes []byte, tx sdk.Tx, height int64, from ...string) (info *runTxInfo, err error) { info = &runTxInfo{} + err = app.runtxWithInfo(info, mode, txBytes, tx, height, from...) + return +} +func (app *BaseApp) runtxWithInfo(info *runTxInfo, mode runTxMode, txBytes []byte, tx sdk.Tx, height int64, from ...string) (err error) { info.handler = app.getModeHandler(mode) info.tx = tx info.txBytes = txBytes handler := info.handler app.pin(ValTxMsgs, true, mode) + //init info context err = handler.handleStartHeight(info, height) if err != nil { - return info, err + return err + } + //info with cache saved in app to load predesessor tx state + if mode != runTxModeTrace { + //in trace mode, info ctx cache was already set to traceBlockCache instead of app.blockCache in app.tracetx() + //to prevent modifying the deliver state + //traceBlockCache was created with different root(chainCache) with app.blockCache in app.BeginBlockForTrace() + info.ctx = info.ctx.WithCache(sdk.NewCache(app.blockCache, useCache(mode))) } - info.ctx = info.ctx.WithCache(sdk.NewCache(app.blockCache, useCache(mode))) for _, addr := range from { // cache from if exist if addr != "" { @@ -60,7 +71,7 @@ func (app *BaseApp) runtx(mode runTxMode, txBytes []byte, tx sdk.Tx, height int6 err = handler.handleGasConsumed(info) if err != nil { - return info, err + return err } defer func() { @@ -81,7 +92,7 @@ func (app *BaseApp) runtx(mode runTxMode, txBytes []byte, tx sdk.Tx, height int6 }() if err := validateBasicTxMsgs(info.tx.GetMsgs()); err != nil { - return info, err + return err } app.pin(ValTxMsgs, false, mode) @@ -90,7 +101,7 @@ func (app *BaseApp) runtx(mode runTxMode, txBytes []byte, tx sdk.Tx, height int6 if app.anteHandler != nil { err = app.runAnte(info, mode) if err != nil { - return info, err + return err } } app.pin(AnteHandler, false, mode) @@ -98,8 +109,7 @@ func (app *BaseApp) runtx(mode runTxMode, txBytes []byte, tx sdk.Tx, height int6 app.pin(RunMsgs, true, mode) err = handler.handleRunMsg(info) app.pin(RunMsgs, false, mode) - - return info, err + return err } func (app *BaseApp) runAnte(info *runTxInfo, mode runTxMode) error { diff --git a/libs/cosmos-sdk/baseapp/helpers_okchain.go b/libs/cosmos-sdk/baseapp/helpers_okchain.go index 87a23c0974..86488f5471 100644 --- a/libs/cosmos-sdk/baseapp/helpers_okchain.go +++ b/libs/cosmos-sdk/baseapp/helpers_okchain.go @@ -2,6 +2,9 @@ package baseapp import ( sdk "github.com/okex/exchain/libs/cosmos-sdk/types" + sdkerrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors" + abci "github.com/okex/exchain/libs/tendermint/abci/types" + tmtypes "github.com/okex/exchain/libs/tendermint/types" ) func (app *BaseApp) PushAnteHandler(ah sdk.AnteHandler) { @@ -10,4 +13,96 @@ func (app *BaseApp) PushAnteHandler(ah sdk.AnteHandler) { func (app *BaseApp) GetDeliverStateCtx() sdk.Context { return app.deliverState.ctx -} \ No newline at end of file +} + +//TraceTx returns the trace log for the target tx +//To trace the target tx, the context must be set to the specific block at first, +//and the predesessors in the same block must be run before tracing the tx. +//The runtx procedure for TraceTx is nearly same with that for DeliverTx, but the +//state was saved in different Cache in app. +func (app *BaseApp) TraceTx(targetTxData []byte, targetTx sdk.Tx, txIndex uint32, block *tmtypes.Block) (*sdk.Result, error) { + + //get first tx + var initialTxBytes []byte + predesessors := block.Txs[:txIndex] + if len(predesessors) == 0 { + initialTxBytes = targetTxData + } else { + initialTxBytes = predesessors[0] + } + + //begin trace block to init traceState and traceBlockCache + traceState, err := app.beginBlockForTracing(initialTxBytes, block) + if err != nil { + return nil, sdkerrors.Wrap(err, "failed to beginblock for tracing") + } + + traceState.ctx = traceState.ctx.WithIsTraceTxLog(false) + //pre deliver prodesessor tx to get the right state + for _, predesessor := range block.Txs[:txIndex] { + tx, err := app.txDecoder(predesessor, block.Height) + if err != nil { + return nil, sdkerrors.Wrap(err, "invalid prodesessor") + } + app.tracetx(predesessor, tx, block.Height, traceState) + //ignore the err when run prodesessor + } + + //trace tx + traceState.ctx = traceState.ctx.WithIsTraceTxLog(true) + info, err := app.tracetx(targetTxData, targetTx, block.Height, traceState) + if info == nil { + return nil, err + } + return info.result, err +} +func (app *BaseApp) tracetx(txBytes []byte, tx sdk.Tx, height int64, traceState *state) (info *runTxInfo, err error) { + + mode := runTxModeTrace + //prepare runTxInfo to runtx + info = &runTxInfo{} + //init info.ctx + info.ctx = traceState.ctx. + WithTxBytes(txBytes). + WithVoteInfos(app.voteInfos). + WithConsensusParams(app.consensusParams) + + err = app.runtxWithInfo(info, mode, txBytes, tx, height) + return info, err +} +func (app *BaseApp) beginBlockForTracing(firstTx []byte, block *tmtypes.Block) (*state, error) { + + req := abci.RequestBeginBlock{ + Hash: block.Hash(), + Header: tmtypes.TM2PB.Header(&block.Header), + } + + //set traceState instead of app.deliverState + //need to reset to version = req.Header.Height-1 + traceState, err := app.newTraceState(req.Header, req.Header.Height-1) + if err != nil { + return nil, err + } + + // use the same block gas meter with deliver mode + var gasMeter sdk.GasMeter + if maxGas := app.getMaximumBlockGas(); maxGas > 0 { + gasMeter = sdk.NewGasMeter(maxGas) + } else { + gasMeter = sdk.NewInfiniteGasMeter() + } + + traceState.ctx = traceState.ctx.WithBlockGasMeter(gasMeter) + + //set the trace mode to prevent the ante handler to check the nounce + traceState.ctx = traceState.ctx.WithIsTraceTx(true) + traceState.ctx = traceState.ctx.WithIsCheckTx(true) + + //app begin block + if app.beginBlocker != nil { + _ = app.beginBlocker(traceState.ctx, req) + } + + // No need to set the signed validators for addition to context in deliverTx + return traceState, nil +} diff --git a/libs/cosmos-sdk/types/context.go b/libs/cosmos-sdk/types/context.go index 86f8a4b96c..1294fb30f8 100644 --- a/libs/cosmos-sdk/types/context.go +++ b/libs/cosmos-sdk/types/context.go @@ -34,6 +34,8 @@ type Context struct { checkTx bool recheckTx bool // if recheckTx == true, then checkTx must also be true wrappedCheckTx bool // if wrappedCheckTx == true, then checkTx must also be true + traceTx bool // traceTx is set true for trace tx and its predesessors , traceTx was set in app.beginBlockForTrace() + traceTxLog bool // traceTxLog is used to create trace logger for evm , traceTxLog is set to true when only tracing target tx (its predesessors will set false), traceTxLog is set before runtx minGasPrice DecCoins consParams *abci.ConsensusParams eventManager *EventManager @@ -60,6 +62,8 @@ func (c Context) GasMeter() GasMeter { return c.gasMeter } func (c Context) BlockGasMeter() GasMeter { return c.blockGasMeter } func (c Context) IsCheckTx() bool { return c.checkTx } func (c Context) IsReCheckTx() bool { return c.recheckTx } +func (c Context) IsTraceTx() bool { return c.traceTx } +func (c Context) IsTraceTxLog() bool { return c.traceTxLog } func (c Context) IsWrappedCheckTx() bool { return c.wrappedCheckTx } func (c Context) MinGasPrices() DecCoins { return c.minGasPrice } func (c Context) EventManager() *EventManager { return c.eventManager } @@ -187,6 +191,20 @@ func (c Context) WithIsReCheckTx(isRecheckTx bool) Context { c.recheckTx = isRecheckTx return c } +func (c Context) WithIsTraceTxLog(isTraceTxLog bool) Context { + if isTraceTxLog { + c.checkTx = true + } + c.traceTxLog = isTraceTxLog + return c +} +func (c Context) WithIsTraceTx(isTraceTx bool) Context { + if isTraceTx { + c.checkTx = true + } + c.traceTx = isTraceTx + return c +} // WithIsWrappedCheckTx called with true will also set true on checkTx in order to // enforce the invariant that if recheckTx = true then checkTx = true as well. diff --git a/x/evm/handler.go b/x/evm/handler.go index c3b2531edd..f39a4ab737 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -147,6 +147,8 @@ func handleMsgEthereumTx(ctx sdk.Context, k *Keeper, msg types.MsgEthereumTx) (* TxHash: ðHash, Sender: sender, Simulate: ctx.IsCheckTx(), + TraceTx: ctx.IsTraceTx(), + TraceTxLog: ctx.IsTraceTxLog(), } // since the txCount is used by the stateDB, and a simulated tx is run only on the node it's submitted to, @@ -215,6 +217,11 @@ func handleMsgEthereumTx(ctx sdk.Context, k *Keeper, msg types.MsgEthereumTx) (* if !st.Simulate { k.Watcher.SaveTransactionReceipt(watcher.TransactionFailed, msg, common.BytesToHash(txHash), uint64(k.TxCount-1), &types.ResultData{}, ctx.GasMeter().GasConsumed()) } + if ctx.IsTraceTxLog() { + // the result was replaced to trace logs when trace tx even if err != nil + executionResult.Result.Data = executionResult.TraceLogs + return executionResult.Result, nil + } return nil, err } @@ -267,13 +274,17 @@ func handleMsgEthereumTx(ctx sdk.Context, k *Keeper, msg types.MsgEthereumTx) (* // set the events to the result executionResult.Result.Events = ctx.EventManager().Events() StopTxLog(bam.TransitionDb) + if ctx.IsTraceTxLog() { + // the result was replaced to trace logs when trace tx + executionResult.Result.Data = executionResult.TraceLogs + } return executionResult.Result, nil } // handleMsgEthermint handles an sdk.StdTx for an Ethereum state transition func handleMsgEthermint(ctx sdk.Context, k *Keeper, msg types.MsgEthermint) (*sdk.Result, error) { - if !ctx.IsCheckTx() && !ctx.IsReCheckTx() { + if !ctx.IsCheckTx() && !ctx.IsReCheckTx() && !ctx.IsTraceTx() { return nil, sdkerrors.Wrap(ethermint.ErrInvalidMsgType, "Ethermint type message is not allowed.") } @@ -297,6 +308,8 @@ func handleMsgEthermint(ctx sdk.Context, k *Keeper, msg types.MsgEthermint) (*sd TxHash: ðHash, Sender: common.BytesToAddress(msg.From.Bytes()), Simulate: ctx.IsCheckTx(), + TraceTx: ctx.IsTraceTx(), + TraceTxLog: ctx.IsTraceTxLog(), } if msg.Recipient != nil { @@ -318,6 +331,11 @@ func handleMsgEthermint(ctx sdk.Context, k *Keeper, msg types.MsgEthermint) (*sd executionResult, _, err, innerTxs, erc20s := st.TransitionDb(ctx, config) if err != nil { + if ctx.IsTraceTxLog() { + // the result was replaced to trace logs when trace tx even if err != nil + executionResult.Result.Data = executionResult.TraceLogs + return executionResult.Result, nil + } return nil, err } @@ -359,5 +377,10 @@ func handleMsgEthermint(ctx sdk.Context, k *Keeper, msg types.MsgEthermint) (*sd // set the events to the result executionResult.Result.Events = ctx.EventManager().Events() + + if ctx.IsTraceTxLog() { + // the result was replaced to trace logs when trace tx + executionResult.Result.Data = executionResult.TraceLogs + } return executionResult.Result, nil } diff --git a/x/evm/types/state_transition.go b/x/evm/types/state_transition.go index f2dfbd4521..7acb234723 100644 --- a/x/evm/types/state_transition.go +++ b/x/evm/types/state_transition.go @@ -28,11 +28,13 @@ type StateTransition struct { Amount *big.Int Payload []byte - ChainID *big.Int - Csdb *CommitStateDB - TxHash *common.Hash - Sender common.Address - Simulate bool // i.e CheckTx execution + ChainID *big.Int + Csdb *CommitStateDB + TxHash *common.Hash + Sender common.Address + Simulate bool // i.e CheckTx execution + TraceTx bool // reexcute tx or its predesessors + TraceTxLog bool // trace tx for its evm logs (predesessors are set to false) } // GasInfo returns the gas limit, gas consumed and gas refunded from the EVM transition @@ -45,10 +47,11 @@ type GasInfo struct { // ExecutionResult represents what's returned from a transition type ExecutionResult struct { - Logs []*ethtypes.Log - Bloom *big.Int - Result *sdk.Result - GasInfo GasInfo + Logs []*ethtypes.Log + Bloom *big.Int + Result *sdk.Result + GasInfo GasInfo + TraceLogs []byte } // GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases: @@ -156,18 +159,22 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (exe params := csdb.GetParams() - var tracer vm.Tracer - tracer = vm.NewStructLogger(evmLogConfig) - to := "" if st.Recipient != nil { to = st.Recipient.String() } enableDebug := checkTracesSegment(ctx.BlockHeight(), st.Sender.String(), to) + var tracer vm.Tracer + if st.TraceTxLog || enableDebug { + tracer = vm.NewStructLogger(evmLogConfig) + } else { + tracer = NewNoOpTracer() + } + vmConfig := vm.Config{ ExtraEips: params.ExtraEIPs, - Debug: enableDebug, + Debug: st.TraceTxLog || enableDebug, Tracer: tracer, ContractVerifier: NewContractVerifier(params), } @@ -236,7 +243,7 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (exe }() defer func() { - if !st.Simulate && enableDebug { + if !st.Simulate && enableDebug && !st.TraceTx { result := &core.ExecutionResult{ UsedGas: gasConsumed, Err: err, @@ -245,7 +252,27 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (exe saveTraceResult(ctx, tracer, result) } }() - + // return trace log if tracetxlog no matter err = nil or not nil + defer func() { + var traceLogs []byte + if st.TraceTxLog { + result := &core.ExecutionResult{ + UsedGas: gasConsumed, + Err: err, + ReturnData: ret, + } + traceLogs, err = GetTracerResult(tracer, result) + if err != nil { + traceLogs = []byte(err.Error()) + } + if exeRes == nil { + exeRes = &ExecutionResult{ + Result: &sdk.Result{}, + } + } + exeRes.TraceLogs = traceLogs + } + }() if err != nil { // Consume gas before returning return exeRes, resData, newRevertError(ret, err), innerTxs, erc20Contracts @@ -272,8 +299,8 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (exe bloomFilter = ethtypes.BytesToBloom(bloomInt.Bytes()) } - if !st.Simulate { - // Finalise state if not a simulated transaction + if !st.Simulate || st.TraceTx { + // Finalise state if not a simulated transaction or a trace tx // TODO: change to depend on config if err = csdb.Finalise(true); err != nil { return @@ -304,7 +331,6 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (exe resultLog := fmt.Sprintf( "executed EVM state transition; sender address %s; %s", st.Sender.String(), recipientLog, ) - exeRes = &ExecutionResult{ Logs: logs, Bloom: bloomInt, @@ -318,7 +344,6 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (exe GasRefunded: leftOverGas, }, } - return } diff --git a/x/evm/types/tracer.go b/x/evm/types/tracer.go index 4643c71cee..c14e4feb43 100644 --- a/x/evm/types/tracer.go +++ b/x/evm/types/tracer.go @@ -2,9 +2,11 @@ package types import ( "fmt" + "math/big" "path/filepath" "strconv" "strings" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -115,8 +117,7 @@ func checkTracesSegment(height int64, from, to string) bool { (len(traceFromAddrs) == 0 || (len(traceFromAddrs) > 0 && fromOk)) && (len(traceToAddrs) == 0 || to == "" || (len(traceToAddrs) > 0 && toOk)) } - -func saveTraceResult(ctx sdk.Context, tracer vm.Tracer, result *core.ExecutionResult) { +func GetTracerResult(tracer vm.Tracer, result *core.ExecutionResult) ([]byte, error) { var ( res []byte err error @@ -129,7 +130,6 @@ func saveTraceResult(ctx sdk.Context, tracer vm.Tracer, result *core.ExecutionRe if len(result.Revert()) > 0 { returnVal = fmt.Sprintf("%x", result.Revert()) } - res, err = json.ConfigFastest.Marshal(&TraceExecutionResult{ Gas: result.UsedGas, Failed: result.Failed(), @@ -141,11 +141,14 @@ func saveTraceResult(ctx sdk.Context, tracer vm.Tracer, result *core.ExecutionRe default: res = []byte(fmt.Sprintf("bad tracer type %T", tracer)) } + return res, err +} +func saveTraceResult(ctx sdk.Context, tracer vm.Tracer, result *core.ExecutionResult) { + res, err := GetTracerResult(tracer, result) if err != nil { res = []byte(err.Error()) } - saveToDB(tmtypes.Tx(ctx.TxBytes()).Hash(ctx.BlockHeight()), res) } @@ -176,3 +179,70 @@ func DeleteTracesFromDB(txHash []byte) error { } return tracesDB.Delete(txHash) } + +// NoOpTracer is an empty implementation of vm.Tracer interface +type NoOpTracer struct{} + +// NewNoOpTracer creates a no-op vm.Tracer +func NewNoOpTracer() *NoOpTracer { + return &NoOpTracer{} +} + +// CaptureStart implements vm.Tracer interface +func (dt NoOpTracer) CaptureStart( + env *vm.EVM, + from, to common.Address, + create bool, + input []byte, + gas uint64, + value *big.Int, +) { +} + +// CaptureEnter implements vm.Tracer interface +func (dt NoOpTracer) CaptureEnter( + typ vm.OpCode, + from common.Address, + to common.Address, + input []byte, + gas uint64, + value *big.Int, +) { +} + +// CaptureExit implements vm.Tracer interface +func (dt NoOpTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} + +// CaptureState implements vm.Tracer interface +func (dt NoOpTracer) CaptureState( + env *vm.EVM, + pc uint64, + op vm.OpCode, + gas, cost uint64, + scope *vm.ScopeContext, + rData []byte, + depth int, + err error, +) { +} + +// CaptureFault implements vm.Tracer interface +func (dt NoOpTracer) CaptureFault( + env *vm.EVM, + pc uint64, + op vm.OpCode, + gas, cost uint64, + scope *vm.ScopeContext, + depth int, + err error, +) { +} + +// CaptureEnd implements vm.Tracer interface +func (dt NoOpTracer) CaptureEnd( + output []byte, + gasUsed uint64, + t time.Duration, + err error, +) { +}