diff --git a/CHANGELOG.md b/CHANGELOG.md index 810844e1..41656c54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking +* (app, evm) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) EVM `Keeper` struct and `NewEVM` function now have a new `trace` field to define +the Tracer type used to collect execution traces from the EVM transaction execution. * (evm) [tharsis#175](https://github.com/tharsis/ethermint/issues/175) The msg `TxData` field is now represented as a `*proto.Any`. * (evm) [tharsis#84](https://github.com/tharsis/ethermint/pull/84) Remove `journal`, `CommitStateDB` and `stateObjects`. * (rpc, evm) [tharsis#81](https://github.com/tharsis/ethermint/pull/81) Remove tx `Receipt` from store and replace it with fields obtained from the Tendermint RPC client. @@ -53,6 +55,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (server) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) `evm-rpc` flags and app config have been renamed to `json-rpc`. * (proto, evm) [tharsis#207](https://github.com/tharsis/ethermint/issues/207) Replace `big.Int` in favor of `sdk.Int` for `TxData` fields * (proto, evm) [tharsis#81](https://github.com/tharsis/ethermint/pull/81) gRPC Query and Tx service changes: * The `TxReceipt`, `TxReceiptsByBlockHeight` endpoints have been removed from the Query service. @@ -65,6 +68,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (evm) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) Support different `Tracer` types for the EVM. * (deps) [tharsis#427](https://github.com/tharsis/ethermint/pull/427) Bump ibc-go to [`v1.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v1.0.0) * (gRPC) [tharsis#239](https://github.com/tharsis/ethermint/pull/239) Query `ChainConfig` via gRPC. * (rpc) [tharsis#181](https://github.com/tharsis/ethermint/pull/181) Use evm denomination for params on tx fee. diff --git a/app/ante/eth.go b/app/ante/eth.go index 06dc292b..9d81b14a 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -27,7 +27,7 @@ type EVMKeeper interface { WithContext(ctx sdk.Context) ResetRefundTransient(ctx sdk.Context) GetCoinbaseAddress() (common.Address, error) - NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address) *vm.EVM + NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer string) *vm.EVM GetCodeHash(addr common.Address) common.Hash } @@ -389,8 +389,8 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate ) } - // NOTE: pass in an empty coinbase address as we don't need it for the check below - evm := ctd.evmKeeper.NewEVM(coreMsg, ethCfg, params, common.Address{}) + // NOTE: pass in an empty coinbase address and tracer as we don't need them for the check below + evm := ctd.evmKeeper.NewEVM(coreMsg, ethCfg, params, common.Address{}, "") // check that caller has enough balance to cover asset transfer for **topmost** call // NOTE: here the gas consumed is from the context with the infinite gas meter diff --git a/app/app.go b/app/app.go index 02261d73..7d999b4b 100644 --- a/app/app.go +++ b/app/app.go @@ -96,6 +96,7 @@ import ( _ "github.com/tharsis/ethermint/client/docs/statik" "github.com/tharsis/ethermint/app/ante" + srvflags "github.com/tharsis/ethermint/server/flags" ethermint "github.com/tharsis/ethermint/types" "github.com/tharsis/ethermint/x/evm" evmrest "github.com/tharsis/ethermint/x/evm/client/rest" @@ -333,11 +334,13 @@ func NewEthermintApp( app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter()) + tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer)) + // Create Ethermint keepers app.EvmKeeper = evmkeeper.NewKeeper( appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName), app.AccountKeeper, app.BankKeeper, app.StakingKeeper, - bApp.Trace(), // debug EVM based on Baseapp options + tracer, bApp.Trace(), // debug EVM based on Baseapp options ) // Create IBC Keeper @@ -388,7 +391,7 @@ func NewEthermintApp( // NOTE: we may consider parsing `appOpts` inside module constructors. For the moment // we prefer to be more strict in what arguments the modules expect. - var skipGenesisInvariants = cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. diff --git a/cmd/ethermintd/root.go b/cmd/ethermintd/root.go index 8b532339..471965dc 100644 --- a/cmd/ethermintd/root.go +++ b/cmd/ethermintd/root.go @@ -38,6 +38,7 @@ import ( "github.com/tharsis/ethermint/encoding" "github.com/tharsis/ethermint/server" servercfg "github.com/tharsis/ethermint/server/config" + srvflags "github.com/tharsis/ethermint/server/flags" ethermint "github.com/tharsis/ethermint/types" ) @@ -115,7 +116,7 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { txCommand(), ethermintclient.KeyCommands(app.DefaultNodeHome), ) - rootCmd = server.AddTxFlags(rootCmd) + rootCmd = srvflags.AddTxFlags(rootCmd) // add rosetta rootCmd.AddCommand(sdkserver.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) diff --git a/config.yml b/config.yml index 191fbece..32ffb0f7 100644 --- a/config.yml +++ b/config.yml @@ -14,7 +14,7 @@ build: init: home: "$HOME/.ethermintd" app: - evm-rpc: + json-rpc: address: "0.0.0.0:8545" # change the JSON-RPC address and port ws-address: "0.0.0.0:8546" # change the JSON-RPC websocket address and port genesis: diff --git a/docs/api/json-rpc/events.md b/docs/api/json-rpc/events.md index 47995b90..4c6671ce 100644 --- a/docs/api/json-rpc/events.md +++ b/docs/api/json-rpc/events.md @@ -111,11 +111,11 @@ compatibility for websockets of the [Ethereum's PubSubAPI](https://geth.ethereum.org/docs/rpc/pubsub), Ethermint needs to cast the Tendermint responses retreived into the Ethereum types. -You can start a connection with the Ethereum websocket using the `--evm-rpc.ws-address` flag when starting +You can start a connection with the Ethereum websocket using the `--json-rpc.ws-address` flag when starting the node (default `"0.0.0.0:8546"`): ```bash -ethermintd start --evm-rpc.address"0.0.0.0:8545" --evm-rpc.ws-address="0.0.0.0:8546" --evm.rpc.api="eth,web3,net,txpool,debug" --evm-rpc.enable +ethermintd start --json-rpc.address"0.0.0.0:8545" --json-rpc.ws-address="0.0.0.0:8546" --evm.rpc.api="eth,web3,net,txpool,debug" --json-rpc.enable ``` Then, start a websocket subscription with [`ws`](https://github.com/hashrocket/ws) diff --git a/docs/api/json-rpc/running_server.md b/docs/api/json-rpc/running_server.md index f527c774..6a702b07 100644 --- a/docs/api/json-rpc/running_server.md +++ b/docs/api/json-rpc/running_server.md @@ -11,15 +11,15 @@ Learn how to run and setup the JSON-RPC server on Ethermint. {synopsis} To enable RPC server use the following flag (set to true by default). ```bash -ethermintd start --evm-rpc.enable +ethermintd start --json-rpc.enable ``` ## Defining Namespaces -`Eth`,`Net` and `Web3` [namespaces](./namespaces) are enabled by default. In order to enable other namespaces use flag `--evm-rpc.api`. +`Eth`,`Net` and `Web3` [namespaces](./namespaces) are enabled by default. In order to enable other namespaces use flag `--json-rpc.api`. ```bash -ethermintd start --evm-rpc.api eth,txpool,personal,net,debug,web3,miner +ethermintd start --json-rpc.api eth,txpool,personal,net,debug,web3,miner ``` ### CORS @@ -27,5 +27,5 @@ ethermintd start --evm-rpc.api eth,txpool,personal,net,debug,web3,miner If accessing the RPC from a browser, CORS will need to be enabled with the appropriate domain set. Otherwise, JavaScript calls are limit by the same-origin policy and requests will fail: ```bash -ethermintd start --evm-rpc.enable-unsafe-cors +ethermintd start --json-rpc.enable-unsafe-cors ``` diff --git a/docs/intro/clients.md b/docs/intro/clients.md index d28d3ac4..1ae2085e 100644 --- a/docs/intro/clients.md +++ b/docs/intro/clients.md @@ -24,6 +24,6 @@ APIs](./../api/JSON-RPC/running_server) to connect with existing web3 tooling. See the list of supported JSON-RPC API [endpoints](./../api/JSON-RPC/endpoints) and [namespaces](./../api/JSON-RPC/namespaces). ::: -To connect to the JSON-PRC server, start the node with the `--evm-rpc.enable=true` flag and define the namespaces that you would like to run using the `--evm.rpc.api` flag (e.g. `"txpool,eth,web3,net,personal"`. Then, you can point any Ethereum development tooling to `http://localhost:8545` or whatever port you choose with the listen address flag (`--evm-rpc.address`). +To connect to the JSON-PRC server, start the node with the `--json-rpc.enable=true` flag and define the namespaces that you would like to run using the `--evm.rpc.api` flag (e.g. `"txpool,eth,web3,net,personal"`. Then, you can point any Ethereum development tooling to `http://localhost:8545` or whatever port you choose with the listen address flag (`--json-rpc.address`). \ No newline at end of file diff --git a/docs/quickstart/run_node.md b/docs/quickstart/run_node.md index 4715b1e8..a201c8ce 100644 --- a/docs/quickstart/run_node.md +++ b/docs/quickstart/run_node.md @@ -38,7 +38,7 @@ The instructions for setting up a brand new full node from scratch are the the s To start your node, just type: ```bash -ethermintd start --evm-rpc.enable=true --evm-rpc.api="eth,web3,net,txpool,debug" +ethermintd start --json-rpc.enable=true --json-rpc.api="eth,web3,net,txpool,debug" ``` ## Key Management diff --git a/init.sh b/init.sh index 4d8d0f1d..e4de7272 100755 --- a/init.sh +++ b/init.sh @@ -86,4 +86,4 @@ if [[ $1 == "pending" ]]; then fi # Start the node (remove the --pruning=nothing flag if historical queries are not needed) -ethermintd start --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --evm-rpc.api eth,txpool,personal,net,debug,web3,miner +ethermintd start --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --json-rpc.api eth,txpool,personal,net,debug,web3,miner diff --git a/scripts/contract-test.sh b/scripts/contract-test.sh index 1f543941..76c9c88e 100644 --- a/scripts/contract-test.sh +++ b/scripts/contract-test.sh @@ -35,7 +35,7 @@ cat $HOME/.ethermint/config/genesis.json | jq '.app_state["mint"]["params"]["min "$PWD"/build/ethermintd validate-genesis # Start the node (remove the --pruning=nothing flag if historical queries are not needed) in background and log to file -"$PWD"/build/ethermintd start --pruning=nothing --rpc.unsafe --evm-rpc.address="0.0.0.0:8545" --keyring-backend test > ethermintd.log 2>&1 & +"$PWD"/build/ethermintd start --pruning=nothing --rpc.unsafe --json-rpc.address="0.0.0.0:8545" --keyring-backend test > ethermintd.log 2>&1 & # Give ethermintd node enough time to launch sleep 5 diff --git a/scripts/integration-test-all.sh b/scripts/integration-test-all.sh index 3c581ad9..95eb3231 100755 --- a/scripts/integration-test-all.sh +++ b/scripts/integration-test-all.sh @@ -106,7 +106,7 @@ start_func() { echo "starting ethermint node $i in background ..." "$PWD"/build/ethermintd start --pruning=nothing --rpc.unsafe \ --p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" --address tcp://$IP_ADDR:$NODE_PORT"$i" --rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ - --evm-rpc.address=$IP_ADDR:$RPC_PORT"$i" \ + --json-rpc.address=$IP_ADDR:$RPC_PORT"$i" \ --keyring-backend test --home "$DATA_DIR$i" \ >"$DATA_DIR"/node"$i".log 2>&1 & disown diff --git a/scripts/start.sh b/scripts/start.sh index bac7b3ff..fbe2d919 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -92,7 +92,7 @@ start_func() { echo "starting ethermint node $i in background ..." "$PWD"/build/ethermintd start --pruning=nothing --rpc.unsafe \ --p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" --address tcp://$IP_ADDR:$NODE_PORT"$i" --rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ - --evm-rpc.address=$IP_ADDR:$RPC_PORT"$i" \ + --json-rpc.address=$IP_ADDR:$RPC_PORT"$i" \ --keyring-backend test --home "$DATA_DIR$i" \ >"$DATA_DIR"/node"$i".log 2>&1 & disown diff --git a/server/config/config.go b/server/config/config.go index c323fe0e..971e968b 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -1,19 +1,33 @@ package config import ( - "github.com/cosmos/cosmos-sdk/server/config" + "fmt" + "github.com/spf13/viper" + + "github.com/tendermint/tendermint/libs/strings" + + "github.com/cosmos/cosmos-sdk/server/config" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( // DefaultGRPCAddress is the default address the gRPC server binds to. DefaultGRPCAddress = "0.0.0.0:9900" - // DefaultEVMAddress is the default address the EVM JSON-RPC server binds to. - DefaultEVMAddress = "0.0.0.0:8545" + // DefaultJSONRPCAddress is the default address the JSON-RPC server binds to. + DefaultJSONRPCAddress = "0.0.0.0:8545" - // DefaultEVMWSAddress is the default address the EVM WebSocket server binds to. - DefaultEVMWSAddress = "0.0.0.0:8546" + // DefaultJSONRPCWsAddress is the default address the JSON-RPC WebSocket server binds to. + DefaultJSONRPCWsAddress = "0.0.0.0:8546" + + // DefaultEVMTracer is the default vm.Tracer type + DefaultEVMTracer = "json" +) + +var ( + evmTracers = []string{DefaultEVMTracer, "markdown", "struct", "access_list"} ) // GetDefaultAPINamespaces returns the default list of JSON-RPC namespaces that should be enabled @@ -45,8 +59,9 @@ func AppConfig(denom string) (string, interface{}) { } customAppConfig := Config{ - Config: *srvCfg, - EVMRPC: *DefaultEVMConfig(), + Config: *srvCfg, + EVM: *DefaultEVMConfig(), + JSONRPC: *DefaultJSONRPCConfig(), } customAppTemplate := config.DefaultConfigTemplate + DefaultConfigTemplate @@ -57,15 +72,39 @@ func AppConfig(denom string) (string, interface{}) { // DefaultConfig returns server's default configuration. func DefaultConfig() *Config { return &Config{ - Config: *config.DefaultConfig(), - EVMRPC: *DefaultEVMConfig(), + Config: *config.DefaultConfig(), + EVM: *DefaultEVMConfig(), + JSONRPC: *DefaultJSONRPCConfig(), } } -// EVMRPCConfig defines configuration for the EVM RPC server. -type EVMRPCConfig struct { - // RPCAddress defines the HTTP server to listen on - RPCAddress string `mapstructure:"address"` +// EVMConfig defines the application configuration values for the EVM. +type EVMConfig struct { + // Tracer defines vm.Tracer type that the EVM will use if the node is run in + // trace mode. Default: 'json'. + Tracer string `mapstructure:"tracer"` +} + +// DefaultEVMConfig returns the default EVM configuration +func DefaultEVMConfig() *EVMConfig { + return &EVMConfig{ + Tracer: DefaultEVMTracer, + } +} + +// Validate returns an error if the tracer type is invalid. +func (c EVMConfig) Validate() error { + if !strings.StringInSlice(c.Tracer, evmTracers) { + return fmt.Errorf("invalid tracer type %s, available types: %v", c.Tracer, evmTracers) + } + + return nil +} + +// JSONRPCConfig defines configuration for the EVM RPC server. +type JSONRPCConfig struct { + // Address defines the HTTP server to listen on + Address string `mapstructure:"address"` // WsAddress defines the WebSocket server to listen on WsAddress string `mapstructure:"ws-address"` // API defines a list of JSON-RPC namespaces that should be enabled @@ -76,13 +115,13 @@ type EVMRPCConfig struct { EnableUnsafeCORS bool `mapstructure:"enable-unsafe-cors"` } -// DefaultEVMConfig returns an EVM config with the JSON-RPC API enabled by default -func DefaultEVMConfig() *EVMRPCConfig { - return &EVMRPCConfig{ +// DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default +func DefaultJSONRPCConfig() *JSONRPCConfig { + return &JSONRPCConfig{ Enable: true, API: GetDefaultAPINamespaces(), - RPCAddress: DefaultEVMAddress, - WsAddress: DefaultEVMWSAddress, + Address: DefaultJSONRPCAddress, + WsAddress: DefaultJSONRPCWsAddress, EnableUnsafeCORS: false, } } @@ -92,7 +131,8 @@ func DefaultEVMConfig() *EVMRPCConfig { type Config struct { config.Config - EVMRPC EVMRPCConfig `mapstructure:"evm-rpc"` + EVM EVMConfig `mapstructure:"evm"` + JSONRPC JSONRPCConfig `mapstructure:"json-rpc"` } // GetConfig returns a fully parsed Config object. @@ -101,12 +141,26 @@ func GetConfig(v *viper.Viper) Config { return Config{ Config: cfg, - EVMRPC: EVMRPCConfig{ - Enable: v.GetBool("evm-rpc.enable"), - API: v.GetStringSlice("evm-rpc.api"), - RPCAddress: v.GetString("evm-rpc.address"), - WsAddress: v.GetString("evm-rpc.ws-address"), - EnableUnsafeCORS: v.GetBool("evm-rpc.enable-unsafe-cors"), + EVM: EVMConfig{ + Tracer: v.GetString("evm.tracer"), + }, + JSONRPC: JSONRPCConfig{ + Enable: v.GetBool("json-rpc.enable"), + API: v.GetStringSlice("json-rpc.api"), + Address: v.GetString("json-rpc.address"), + WsAddress: v.GetString("json-rpc.ws-address"), + EnableUnsafeCORS: v.GetBool("json-rpc.enable-unsafe-cors"), }, } } + +// ValidateBasic returns an error any of the application configuration fields are invalid +func (c Config) ValidateBasic() error { + if err := c.EVM.Validate(); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrAppConfig, "invalid evm config value: %s", err.Error()) + } + + // TODO: validate JSON-RPC APIs + + return c.Config.ValidateBasic() +} diff --git a/server/config/config_test.go b/server/config/config_test.go index 3bb36bd3..9a19e3e9 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -7,8 +7,8 @@ import ( ) func TestDefaultConfig(t *testing.T) { - cfg := DefaultEVMConfig() - require.True(t, cfg.Enable) - require.Equal(t, cfg.RPCAddress, DefaultEVMAddress) - require.Equal(t, cfg.WsAddress, DefaultEVMWSAddress) + cfg := DefaultConfig() + require.True(t, cfg.JSONRPC.Enable) + require.Equal(t, cfg.JSONRPC.Address, DefaultJSONRPCAddress) + require.Equal(t, cfg.JSONRPC.WsAddress, DefaultJSONRPCWsAddress) } diff --git a/server/config/toml.go b/server/config/toml.go index 7312d9bf..98ddcd13 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -3,24 +3,35 @@ package config // DefaultConfigTemplate defines the configuration template for the EVM RPC configuration const DefaultConfigTemplate = ` ############################################################################### -### EVM RPC Configuration ### +### EVM Configuration ### ############################################################################### -[evm-rpc] +[evm] + +# Tracer defines the 'vm.Tracer' type that the EVM will use when the node is run in +# debug mode. To enable tracing use the '--trace' flag when starting your node. +# Valid types are: json|struct|access_list|markdown +tracer = "{{ .EVM.Tracer }}" + +############################################################################### +### JSON RPC Configuration ### +############################################################################### + +[json-rpc] # Enable defines if the gRPC server should be enabled. -enable = {{ .EVMRPC.Enable }} +enable = {{ .JSONRPC.Enable }} # Address defines the EVM RPC HTTP server address to bind to. -address = "{{ .EVMRPC.RPCAddress }}" +address = "{{ .JSONRPC.Address }}" # Address defines the EVM WebSocket server address to bind to. -ws-address = "{{ .EVMRPC.WsAddress }}" +ws-address = "{{ .JSONRPC.WsAddress }}" # API defines a list of JSON-RPC namespaces that should be enabled # Example: "eth,txpool,personal,net,debug,web3" -api = "{{range $index, $elmt := .EVMRPC.API}}{{if $index}},{{$elmt}}{{else}}{{$elmt}}{{end}}{{end}}" +api = "{{range $index, $elmt := .JSONRPC.API}}{{if $index}},{{$elmt}}{{else}}{{$elmt}}{{end}}{{end}}" # EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk) -enable-unsafe-cors = "{{ .EVMRPC.EnableUnsafeCORS }}" +enable-unsafe-cors = "{{ .JSONRPC.EnableUnsafeCORS }}" ` diff --git a/server/flags.go b/server/flags/flags.go similarity index 74% rename from server/flags.go rename to server/flags/flags.go index 27095d46..5460c602 100644 --- a/server/flags.go +++ b/server/flags/flags.go @@ -1,4 +1,4 @@ -package server +package flags import ( "github.com/cosmos/cosmos-sdk/client/flags" @@ -7,6 +7,37 @@ import ( "github.com/spf13/viper" ) +// Tendermint full-node start flags +const ( + WithTendermint = "with-tendermint" + Address = "address" + Transport = "transport" + TraceStore = "trace-store" + CPUProfile = "cpu-profile" +) + +// GRPC-related flags. +const ( + GRPCEnable = "grpc.enable" + GRPCAddress = "grpc.address" + GRPCWebEnable = "grpc-web.enable" + GRPCWebAddress = "grpc-web.address" +) + +// JSON-RPC flags +const ( + JSONRPCEnable = "json-rpc.enable" + JSONRPCAPI = "json-rpc.api" + JSONRPCAddress = "json-rpc.address" + JSONWsAddress = "json-rpc.ws-address" + JSONEnableUnsafeCORS = "json-rpc.enable-unsafe-cors" +) + +// EVM flags +const ( + EVMTracer = "evm.tracer" +) + // AddTxFlags adds common flags for commands to post tx func AddTxFlags(cmd *cobra.Command) *cobra.Command { cmd.PersistentFlags().String(flags.FlagChainID, "testnet", "Specify Chain ID for sending Tx") diff --git a/server/evmrpc.go b/server/json_rpc.go similarity index 62% rename from server/evmrpc.go rename to server/json_rpc.go index 225ca51d..2ae61705 100644 --- a/server/evmrpc.go +++ b/server/json_rpc.go @@ -17,19 +17,19 @@ import ( "github.com/tharsis/ethermint/server/config" ) -// StartEVMRPC start evm rpc server -func StartEVMRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr string, tmEndpoint string, config config.Config) (*http.Server, chan struct{}, error) { +// StartJSONRPC starts the JSON-RPC server +func StartJSONRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr string, tmEndpoint string, config config.Config) (*http.Server, chan struct{}, error) { tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint) rpcServer := ethrpc.NewServer() - rpcAPIArr := config.EVMRPC.API + rpcAPIArr := config.JSONRPC.API apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient, rpcAPIArr) for _, api := range apis { if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil { ctx.Logger.Error( - "failed to register service in EVM RPC namespace", + "failed to register service in JSON RPC namespace", "namespace", api.Namespace, "service", api.Service, ) @@ -41,43 +41,43 @@ func StartEVMRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr string r.HandleFunc("/", rpcServer.ServeHTTP).Methods("POST") handlerWithCors := cors.Default() - if config.EVMRPC.EnableUnsafeCORS { + if config.JSONRPC.EnableUnsafeCORS { handlerWithCors = cors.AllowAll() } httpSrv := &http.Server{ - Addr: config.EVMRPC.RPCAddress, + Addr: config.JSONRPC.Address, Handler: handlerWithCors.Handler(r), } httpSrvDone := make(chan struct{}, 1) errCh := make(chan error) go func() { - ctx.Logger.Info("Starting EVM RPC server", "address", config.EVMRPC.RPCAddress) + ctx.Logger.Info("Starting JSON-RPC server", "address", config.JSONRPC.Address) if err := httpSrv.ListenAndServe(); err != nil { if err == http.ErrServerClosed { close(httpSrvDone) return } - ctx.Logger.Error("failed to start EVM RPC server", "error", err.Error()) + ctx.Logger.Error("failed to start JSON-RPC server", "error", err.Error()) errCh <- err } }() select { case err := <-errCh: - ctx.Logger.Error("failed to boot EVM RPC server", "error", err.Error()) + ctx.Logger.Error("failed to boot JSON-RPC server", "error", err.Error()) return nil, nil, err - case <-time.After(types.ServerStartTime): // assume EVM RPC server started successfully + case <-time.After(types.ServerStartTime): // assume JSON RPC server started successfully } - ctx.Logger.Info("Starting EVM WebSocket server", "address", config.EVMRPC.WsAddress) - _, port, _ := net.SplitHostPort(config.EVMRPC.RPCAddress) + ctx.Logger.Info("Starting JSON WebSocket server", "address", config.JSONRPC.WsAddress) + _, port, _ := net.SplitHostPort(config.JSONRPC.Address) // allocate separate WS connection to Tendermint tmWsClient = ConnectTmWS(tmRPCAddr, tmEndpoint) - wsSrv := rpc.NewWebsocketsServer(ctx.Logger, tmWsClient, "localhost:"+port, config.EVMRPC.WsAddress) + wsSrv := rpc.NewWebsocketsServer(ctx.Logger, tmWsClient, "localhost:"+port, config.JSONRPC.WsAddress) wsSrv.Start() return httpSrv, httpSrvDone, nil } diff --git a/server/start.go b/server/start.go index b314461b..2c0e3efd 100644 --- a/server/start.go +++ b/server/start.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "runtime/pprof" + "strings" "time" "github.com/cosmos/cosmos-sdk/codec" @@ -42,48 +43,7 @@ import ( ethdebug "github.com/tharsis/ethermint/ethereum/rpc/namespaces/debug" "github.com/tharsis/ethermint/server/config" -) - -// Tendermint full-node start flags -const ( - flagWithTendermint = "with-tendermint" - flagAddress = "address" - flagTransport = "transport" - flagTraceStore = "trace-store" - flagCPUProfile = "cpu-profile" - FlagMinGasPrices = "minimum-gas-prices" - FlagHaltHeight = "halt-height" - FlagHaltTime = "halt-time" - FlagInterBlockCache = "inter-block-cache" - FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades" - FlagTrace = "trace" - FlagInvCheckPeriod = "inv-check-period" - - FlagPruning = "pruning" - FlagPruningKeepRecent = "pruning-keep-recent" - FlagPruningKeepEvery = "pruning-keep-every" - FlagPruningInterval = "pruning-interval" - FlagIndexEvents = "index-events" - FlagMinRetainBlocks = "min-retain-blocks" -) - -// GRPC-related flags. -const ( - flagGRPCEnable = "grpc.enable" - flagGRPCAddress = "grpc.address" - flagEVMRPCEnable = "evm-rpc.enable" - flagEVMRPCAPI = "evm-rpc.api" - flagEVMRPCAddress = "evm-rpc.address" - flagEVMWSAddress = "evm-rpc.ws-address" - flagEVMEnableUnsafeCORS = "evm-rpc.enable-unsafe-cors" - flagGRPCWebEnable = "grpc-web.enable" - flagGRPCWebAddress = "grpc-web.address" -) - -// State sync-related flags. -const ( - FlagStateSyncSnapshotInterval = "state-sync.snapshot-interval" - FlagStateSyncSnapshotKeepRecent = "state-sync.snapshot-keep-recent" + srvflags "github.com/tharsis/ethermint/server/flags" ) // StartCmd runs the service passed in, either stand-alone or in-process with @@ -134,7 +94,7 @@ which accepts a path for the resulting pprof file. return err } - withTM, _ := cmd.Flags().GetBool(flagWithTendermint) + withTM, _ := cmd.Flags().GetBool(srvflags.WithTendermint) if !withTM { serverCtx.Logger.Info("starting ABCI without Tendermint") return startStandAlone(serverCtx, appCreator) @@ -155,38 +115,39 @@ which accepts a path for the resulting pprof file. } cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") - cmd.Flags().Bool(flagWithTendermint, true, "Run abci app embedded in-process with tendermint") - cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address") - cmd.Flags().String(flagTransport, "socket", "Transport protocol: socket, grpc") - cmd.Flags().String(flagTraceStore, "", "Enable KVStore tracing to an output file") - cmd.Flags().String(FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") - cmd.Flags().IntSlice(FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary") - cmd.Flags().Uint64(FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node") - cmd.Flags().Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node") - cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching") - cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file") - cmd.Flags().Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log") - cmd.Flags().String(FlagPruning, storetypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") - cmd.Flags().Uint64(FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')") - cmd.Flags().Uint64(FlagPruningKeepEvery, 0, "Offset heights to keep on disk after 'keep-every' (ignored if pruning is not 'custom')") - cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") - cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") - cmd.Flags().Uint64(FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks") + cmd.Flags().Bool(srvflags.WithTendermint, true, "Run abci app embedded in-process with tendermint") + cmd.Flags().String(srvflags.Address, "tcp://0.0.0.0:26658", "Listen address") + cmd.Flags().String(srvflags.Transport, "socket", "Transport protocol: socket, grpc") + cmd.Flags().String(srvflags.TraceStore, "", "Enable KVStore tracing to an output file") + cmd.Flags().String(server.FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") + cmd.Flags().IntSlice(server.FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary") + cmd.Flags().Uint64(server.FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node") + cmd.Flags().Uint64(server.FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node") + cmd.Flags().Bool(server.FlagInterBlockCache, true, "Enable inter-block caching") + cmd.Flags().String(srvflags.CPUProfile, "", "Enable CPU profiling and write to the provided file") + cmd.Flags().Bool(server.FlagTrace, false, "Provide full stack traces for errors in ABCI Log") + cmd.Flags().String(server.FlagPruning, storetypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") + cmd.Flags().Uint64(server.FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')") + cmd.Flags().Uint64(server.FlagPruningKeepEvery, 0, "Offset heights to keep on disk after 'keep-every' (ignored if pruning is not 'custom')") + cmd.Flags().Uint64(server.FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") + cmd.Flags().Uint(server.FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") + cmd.Flags().Uint64(server.FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks") - cmd.Flags().Bool(flagGRPCEnable, true, "Define if the gRPC server should be enabled") - cmd.Flags().String(flagGRPCAddress, serverconfig.DefaultGRPCAddress, "the gRPC server address to listen on") + cmd.Flags().Bool(srvflags.GRPCEnable, true, "Define if the gRPC server should be enabled") + cmd.Flags().String(srvflags.GRPCAddress, serverconfig.DefaultGRPCAddress, "the gRPC server address to listen on") + cmd.Flags().Bool(srvflags.GRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled.)") + cmd.Flags().String(srvflags.GRPCWebAddress, serverconfig.DefaultGRPCWebAddress, "The gRPC-Web server address to listen on") - cmd.Flags().Bool(flagGRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled.)") - cmd.Flags().String(flagGRPCWebAddress, serverconfig.DefaultGRPCWebAddress, "The gRPC-Web server address to listen on") + cmd.Flags().Bool(srvflags.JSONRPCEnable, true, "Define if the gRPC server should be enabled") + cmd.Flags().StringSlice(srvflags.JSONRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled") + cmd.Flags().String(srvflags.JSONRPCAddress, config.DefaultJSONRPCAddress, "the JSON-RPC server address to listen on") + cmd.Flags().String(srvflags.JSONWsAddress, config.DefaultJSONRPCWsAddress, "the JSON-RPC WS server address to listen on") + cmd.Flags().Bool(srvflags.JSONEnableUnsafeCORS, false, "Define if the JSON-RPC server should enabled CORS (unsafe - use it at your own risk)") - cmd.Flags().Bool(flagEVMRPCEnable, true, "Define if the gRPC server should be enabled") - cmd.Flags().StringSlice(flagEVMRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled") - cmd.Flags().String(flagEVMRPCAddress, config.DefaultEVMAddress, "the EVM RPC server address to listen on") - cmd.Flags().String(flagEVMWSAddress, config.DefaultEVMWSAddress, "the EVM WS server address to listen on") - cmd.Flags().Bool(flagEVMEnableUnsafeCORS, false, "Define if the EVM RPC server should enabled CORS (unsafe - use it at your own risk)") + cmd.Flags().String(srvflags.EVMTracer, config.DefaultEVMTracer, "the EVM tracer type to collect execution traces from the EVM transaction execution (json|struct|access_list|markdown)") - cmd.Flags().Uint64(FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") - cmd.Flags().Uint32(FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") + cmd.Flags().Uint64(server.FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") + cmd.Flags().Uint32(server.FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") // add support for all Tendermint-specific command line options tcmd.AddNodeFlags(cmd) @@ -194,8 +155,8 @@ which accepts a path for the resulting pprof file. } func startStandAlone(ctx *server.Context, appCreator types.AppCreator) error { - addr := ctx.Viper.GetString(flagAddress) - transport := ctx.Viper.GetString(flagTransport) + addr := ctx.Viper.GetString(srvflags.Address) + transport := ctx.Viper.GetString(srvflags.Transport) home := ctx.Viper.GetString(flags.FlagHome) db, err := openDB(home) @@ -203,7 +164,7 @@ func startStandAlone(ctx *server.Context, appCreator types.AppCreator) error { return err } - traceWriterFile := ctx.Viper.GetString(flagTraceStore) + traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore) traceWriter, err := openTraceWriter(traceWriterFile) if err != nil { return err @@ -240,7 +201,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty logger := ctx.Logger var cpuProfileCleanup func() - if cpuProfile := ctx.Viper.GetString(flagCPUProfile); cpuProfile != "" { + if cpuProfile := ctx.Viper.GetString(srvflags.CPUProfile); cpuProfile != "" { f, err := os.Create(ethdebug.ExpandHome(cpuProfile)) if err != nil { return err @@ -258,7 +219,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty } } - traceWriterFile := ctx.Viper.GetString(flagTraceStore) + traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore) db, err := openDB(home) if err != nil { logger.Error("failed to open DB", "error", err.Error()) @@ -272,10 +233,17 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty } config := config.GetConfig(ctx.Viper) + if err := config.ValidateBasic(); err != nil { - ctx.Logger.Error("WARNING: The minimum-gas-prices config in app.toml is set to the empty string. " + - "This defaults to 0 in the current version, but will error in the next version " + - "(SDK v0.44). Please explicitly put the desired minimum-gas-prices in your app.toml.") + if strings.Contains(err.Error(), "set min gas price in app.toml or flag or env variable") { + ctx.Logger.Error( + "WARNING: The minimum-gas-prices config in app.toml is set to the empty string. " + + "This defaults to 0 in the current version, but will error in the next version " + + "(SDK v0.44). Please explicitly put the desired minimum-gas-prices in your app.toml.", + ) + } else { + return err + } } app := appCreator(ctx.Logger, db, traceWriter, ctx.Viper) @@ -405,7 +373,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty httpSrv *http.Server httpSrvDone chan struct{} ) - if config.EVMRPC.Enable { + if config.JSONRPC.Enable { genDoc, err := genDocProvider() if err != nil { return err @@ -415,7 +383,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty tmEndpoint := "/websocket" tmRPCAddr := cfg.RPC.ListenAddress - httpSrv, httpSrvDone, err = StartEVMRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, config) + httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, config) if err != nil { return err } diff --git a/tests/solidity/init-test-node.sh b/tests/solidity/init-test-node.sh index 280620c9..5006f38c 100755 --- a/tests/solidity/init-test-node.sh +++ b/tests/solidity/init-test-node.sh @@ -43,4 +43,4 @@ ethermintd collect-gentxs ethermintd validate-genesis # Start the node (remove the --pruning=nothing flag if historical queries are not needed) -ethermintd start --pruning=nothing --rpc.unsafe --keyring-backend test --trace --log_level info --evm-rpc.api eth,txpool,personal,net,debug,web3 +ethermintd start --pruning=nothing --rpc.unsafe --keyring-backend test --trace --log_level info --json-rpc.api eth,txpool,personal,net,debug,web3 diff --git a/testutil/network/network.go b/testutil/network/network.go index 78ae44bb..c7a41f0a 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -230,7 +230,7 @@ func New(t *testing.T, cfg Config) *Network { jsonRPCAddr := "" tmCfg.RPC.ListenAddress = "" appCfg.GRPC.Enable = false - appCfg.EVMRPC.Enable = false + appCfg.JSONRPC.Enable = false if i == 0 { apiListenAddr, _, err := server.FreeTCPAddr() @@ -244,8 +244,8 @@ func New(t *testing.T, cfg Config) *Network { jsonRPCListenAddr, _, err := server.FreeTCPAddr() require.NoError(t, err) t.Log(jsonRPCListenAddr) - appCfg.EVMRPC.RPCAddress = jsonRPCListenAddr - appCfg.EVMRPC.Enable = true + appCfg.JSONRPC.Address = jsonRPCListenAddr + appCfg.JSONRPC.Enable = true jsonRPCAPIURL, err := url.Parse(jsonRPCListenAddr) require.NoError(t, err) diff --git a/testutil/network/util.go b/testutil/network/util.go index 736291ef..e4fbff66 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -114,14 +114,14 @@ func startInProcess(cfg Config, val *Validator) error { val.grpc = grpcSrv } - if val.AppConfig.EVMRPC.Enable { + if val.AppConfig.JSONRPC.Enable { tmEndpoint := "/websocket" tmRPCAddr := val.Ctx.Config.RPC.ListenAddress tmWsClient := ethsrv.ConnectTmWS(tmRPCAddr, tmEndpoint) val.jsonRPC = jsonrpc.NewServer() - rpcAPIArr := val.AppConfig.EVMRPC.API + rpcAPIArr := val.AppConfig.JSONRPC.API apis := rpc.GetRPCAPIs(val.Ctx, val.ClientCtx, tmWsClient, rpcAPIArr) for _, api := range apis { @@ -153,8 +153,8 @@ func startInProcess(cfg Config, val *Validator) error { }) httpSrv := &http.Server{ - Addr: strings.TrimPrefix(val.AppConfig.EVMRPC.RPCAddress, "tcp://"), // FIXME: timeouts - // Addr: val.AppConfig.EVMRPC.RPCAddress, // FIXME: address has too many colons + Addr: strings.TrimPrefix(val.AppConfig.JSONRPC.Address, "tcp://"), // FIXME: timeouts + // Addr: val.AppConfig.JSONRPC.RPCAddress, // FIXME: address has too many colons Handler: handlerWithCors.Handler(r), } diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index db00b348..db812356 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -378,7 +378,8 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms return nil, status.Error(codes.Internal, err.Error()) } - evm := k.NewEVM(msg, ethCfg, params, coinbase) + evm := k.NewEVM(msg, ethCfg, params, coinbase, k.tracer) + // pass true means execute in query mode, which don't do actual gas refund. res, err := k.ApplyMessage(evm, msg, ethCfg, true) k.ctxStack.RevertAll() @@ -448,7 +449,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type k.WithContext(ctx) msg := args.ToMessage(req.GasCap) - evm := k.NewEVM(msg, ethCfg, params, coinbase) + evm := k.NewEVM(msg, ethCfg, params, coinbase, k.tracer) // pass true means execute in query mode, which don't do actual gas refund. rsp, err := k.ApplyMessage(evm, msg, ethCfg, true) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index c91a1cfa..7465a215 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -48,6 +48,9 @@ type Keeper struct { // chain ID number obtained from the context's chain id eip155ChainID *big.Int + + // Tracer used to collect execution traces from the EVM transaction execution + tracer string // trace EVM state transition execution. This value is obtained from the `--trace` flag. // For more info check https://geth.ethereum.org/docs/dapp/tracing debug bool @@ -58,7 +61,7 @@ func NewKeeper( cdc codec.BinaryCodec, storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, - debug bool, + tracer string, debug bool, ) *Keeper { // ensure evm module account is set @@ -80,6 +83,7 @@ func NewKeeper( stakingKeeper: sk, storeKey: storeKey, transientKey: transientKey, + tracer: tracer, debug: debug, } } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index dcdeab3e..54285df9 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -2,7 +2,6 @@ package keeper import ( "math/big" - "os" "time" "github.com/palantir/stacktrace" @@ -28,7 +27,13 @@ import ( // (ChainConfig and module Params). It additionally sets the validator operator address as the // coinbase address to make it available for the COINBASE opcode, even though there is no // beneficiary of the coinbase transaction (since we're not mining). -func (k *Keeper) NewEVM(msg core.Message, config *params.ChainConfig, params types.Params, coinbase common.Address) *vm.EVM { +func (k *Keeper) NewEVM( + msg core.Message, + config *params.ChainConfig, + params types.Params, + coinbase common.Address, + tracer string, +) *vm.EVM { blockCtx := vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -41,18 +46,20 @@ func (k *Keeper) NewEVM(msg core.Message, config *params.ChainConfig, params typ } txCtx := core.NewEVMTxContext(msg) - vmConfig := k.VMConfig(params) + vmConfig := k.VMConfig(msg, params, tracer) return vm.NewEVM(blockCtx, txCtx, k, config, vmConfig) } // VMConfig creates an EVM configuration from the debug setting and the extra EIPs enabled on the // module parameters. The config generated uses the default JumpTable from the EVM. -func (k Keeper) VMConfig(params types.Params) vm.Config { +func (k Keeper) VMConfig(msg core.Message, params types.Params, tracer string) vm.Config { + cfg := params.ChainConfig.EthereumConfig(k.eip155ChainID) + return vm.Config{ Debug: k.debug, - Tracer: vm.NewJSONLogger(&vm.LogConfig{Debug: k.debug}, os.Stderr), // TODO: consider using the Struct Logger too - NoRecursion: false, // TODO: consider disabling recursion though params + Tracer: types.NewTracer(tracer, msg, cfg, k.Ctx().BlockHeight(), k.debug), + NoRecursion: false, // TODO: consider disabling recursion though params ExtraEips: params.EIPs(), } } @@ -154,7 +161,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT } // create an ethereum EVM instance and run the message - evm := k.NewEVM(msg, ethCfg, params, coinbase) + evm := k.NewEVM(msg, ethCfg, params, coinbase, k.tracer) txHash := tx.Hash() diff --git a/x/evm/types/tracer.go b/x/evm/types/tracer.go new file mode 100644 index 00000000..02bb400f --- /dev/null +++ b/x/evm/types/tracer.go @@ -0,0 +1,40 @@ +package types + +import ( + "math/big" + "os" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" +) + +const ( + TracerAccessList = "access_list" + TracerJSON = "json" + TracerStruct = "struct" + TracerMarkdown = "markdown" +) + +// NewTracer creates a new Logger tracer to collect execution traces from an +// EVM transaction. +func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height int64, debug bool) vm.Tracer { + // TODO: enable additional log configuration + logCfg := &vm.LogConfig{ + Debug: debug, + } + + switch tracer { + case TracerAccessList: + precompiles := vm.ActivePrecompiles(cfg.Rules(big.NewInt(height))) + return vm.NewAccessListTracer(msg.AccessList(), msg.From(), *msg.To(), precompiles) + case TracerJSON: + return vm.NewJSONLogger(logCfg, os.Stderr) + case TracerMarkdown: + return vm.NewMarkdownLogger(logCfg, os.Stdout) // TODO: Stderr ? + case TracerStruct: + return vm.NewStructLogger(logCfg) + default: + return nil + } +}