From cf90cebdcf9576797034d4da7e802d0baf65a4b8 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 12 Aug 2021 16:09:53 +0200 Subject: [PATCH 1/7] server: update server and enable configurable tracer --- app/app.go | 4 ++- config.yml | 2 +- docs/api/json-rpc/events.md | 4 +-- docs/api/json-rpc/running_server.md | 8 +++--- docs/intro/clients.md | 2 +- docs/quickstart/run_node.md | 2 +- init.sh | 2 +- scripts/contract-test.sh | 2 +- scripts/integration-test-all.sh | 2 +- scripts/start.sh | 2 +- server/config/config.go | 43 +++++++++++++++++------------ server/config/config_test.go | 2 +- server/config/toml.go | 23 ++++++++++----- server/{evmrpc.go => json_rpc.go} | 26 ++++++++--------- server/start.go | 14 +++++----- tests/solidity/init-test-node.sh | 2 +- testutil/network/network.go | 6 ++-- testutil/network/util.go | 8 +++--- x/evm/keeper/keeper.go | 9 ++++++ x/evm/keeper/state_transition.go | 6 ++-- x/evm/types/tracer.go | 27 ++++++++++++++++++ 21 files changed, 125 insertions(+), 71 deletions(-) rename server/{evmrpc.go => json_rpc.go} (62%) create mode 100644 x/evm/types/tracer.go diff --git a/app/app.go b/app/app.go index 02261d7365..93a5fed445 100644 --- a/app/app.go +++ b/app/app.go @@ -388,7 +388,9 @@ 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)) + + // tracer := cast.ToString(appOpts.Get()) // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. diff --git a/config.yml b/config.yml index 191fbeced4..32ffb0f75f 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 47995b9087..4c6671ce3a 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 f527c774d1..6a702b0766 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 d28d3ac487..1ae2085e9e 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 4715b1e8ea..a201c8ce93 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 4d8d0f1d01..e4de72723f 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 1f54394114..76c9c88e5c 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 3c581ad9ff..95eb32311d 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 bac7b3ffb8..fbe2d919cc 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 c323fe0e4a..4b2878b41d 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -45,8 +45,8 @@ func AppConfig(denom string) (string, interface{}) { } customAppConfig := Config{ - Config: *srvCfg, - EVMRPC: *DefaultEVMConfig(), + Config: *srvCfg, + JSONRPC: *DefaultEVMConfig(), } customAppTemplate := config.DefaultConfigTemplate + DefaultConfigTemplate @@ -57,15 +57,22 @@ 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(), + JSONRPC: *DefaultEVMConfig(), } } -// 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"` +} + +// 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 @@ -77,11 +84,11 @@ type EVMRPCConfig struct { } // DefaultEVMConfig returns an EVM config with the JSON-RPC API enabled by default -func DefaultEVMConfig() *EVMRPCConfig { - return &EVMRPCConfig{ +func DefaultEVMConfig() *JSONRPCConfig { + return &JSONRPCConfig{ Enable: true, API: GetDefaultAPINamespaces(), - RPCAddress: DefaultEVMAddress, + Address: DefaultEVMAddress, WsAddress: DefaultEVMWSAddress, EnableUnsafeCORS: false, } @@ -92,7 +99,7 @@ func DefaultEVMConfig() *EVMRPCConfig { type Config struct { config.Config - EVMRPC EVMRPCConfig `mapstructure:"evm-rpc"` + JSONRPC JSONRPCConfig `mapstructure:"json-rpc"` } // GetConfig returns a fully parsed Config object. @@ -101,12 +108,12 @@ 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"), + 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"), }, } } diff --git a/server/config/config_test.go b/server/config/config_test.go index 3bb36bd39e..11479c74d9 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -9,6 +9,6 @@ import ( func TestDefaultConfig(t *testing.T) { cfg := DefaultEVMConfig() require.True(t, cfg.Enable) - require.Equal(t, cfg.RPCAddress, DefaultEVMAddress) + require.Equal(t, cfg.Address, DefaultEVMAddress) require.Equal(t, cfg.WsAddress, DefaultEVMWSAddress) } diff --git a/server/config/toml.go b/server/config/toml.go index 7312d9bf9d..2260978208 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -3,24 +3,33 @@ package config // DefaultConfigTemplate defines the configuration template for the EVM RPC configuration const DefaultConfigTemplate = ` ############################################################################### -### EVM RPC Configuration ### +### EVM Configuration ### ############################################################################### -[evm-rpc] +[json-rpc] -# Enable defines if the gRPC server should be enabled. +# tracer defines the tracer. enable = {{ .EVMRPC.Enable }} +############################################################################### +### JSON RPC Configuration ### +############################################################################### + +[json-rpc] + +# Enable defines if the gRPC server should be enabled. +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/evmrpc.go b/server/json_rpc.go similarity index 62% rename from server/evmrpc.go rename to server/json_rpc.go index 225ca51da1..2ae6170510 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 b314461be4..564f5fb0cc 100644 --- a/server/start.go +++ b/server/start.go @@ -71,11 +71,11 @@ const ( 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" + flagEVMRPCEnable = "json-rpc.enable" + flagEVMRPCAPI = "json-rpc.api" + flagEVMRPCAddress = "json-rpc.address" + flagEVMWSAddress = "json-rpc.ws-address" + flagEVMEnableUnsafeCORS = "json-rpc.enable-unsafe-cors" flagGRPCWebEnable = "grpc-web.enable" flagGRPCWebAddress = "grpc-web.address" ) @@ -405,7 +405,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 +415,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 280620c9f5..5006f38c7f 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 78ae44bb57..c7a41f0a5e 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 736291efe8..e4fbff66c1 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/keeper.go b/x/evm/keeper/keeper.go index c91a1cfa0a..f0fba4f347 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "bytes" "math/big" + "os" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -10,6 +11,7 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/palantir/stacktrace" "github.com/tendermint/tendermint/libs/log" @@ -48,6 +50,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 vm.Tracer // 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 @@ -71,6 +76,9 @@ func NewKeeper( paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } + // TODO: consider using the Struct Logger too + tracer := vm.NewJSONLogger(&vm.LogConfig{Debug: debug}, os.Stderr) + // NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations return &Keeper{ cdc: cdc, @@ -80,6 +88,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 1cae6d2a6a..22ec7b3815 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" @@ -49,10 +48,11 @@ func (k *Keeper) NewEVM(msg core.Message, config *params.ChainConfig, params typ // 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 { + 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: k.tracer, + NoRecursion: false, // TODO: consider disabling recursion though params ExtraEips: params.EIPs(), } } diff --git a/x/evm/types/tracer.go b/x/evm/types/tracer.go new file mode 100644 index 0000000000..3f09760f64 --- /dev/null +++ b/x/evm/types/tracer.go @@ -0,0 +1,27 @@ +package types + +import "github.com/ethereum/go-ethereum/core/vm" + +const ( + TracerAccessList = "access_list" + TracerJSON = "json" + TracerStruct = "struct" + TracerMarkdown = "markdown" + TracerMd = "md" +) + +// NewTracer +func NewTracer(tracer string) vm.Tracer { + switch tracer { + case TracerAccessList: + return &vm.AccessListTracer{} + case TracerJSON: + return &vm.JSONLogger{} + case TracerMarkdown, TracerMd: + return vm.NewMarkdownLogger(nil, nil) + case TracerStruct: + return vm.NewStructLogger(nil) + default: + return nil + } +} From 4ef2d8a4f02a210666a4631cf72672a4cb63ee7f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 12 Aug 2021 16:47:27 +0200 Subject: [PATCH 2/7] config validation --- server/config/config.go | 71 +++++++++++++++++++++----- server/config/config_test.go | 8 +-- server/flags.go | 31 ++++++++++++ server/start.go | 97 ++++++++++++------------------------ 4 files changed, 126 insertions(+), 81 deletions(-) diff --git a/server/config/config.go b/server/config/config.go index 4b2878b41d..971e968b7c 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 @@ -46,7 +60,8 @@ func AppConfig(denom string) (string, interface{}) { customAppConfig := Config{ Config: *srvCfg, - JSONRPC: *DefaultEVMConfig(), + EVM: *DefaultEVMConfig(), + JSONRPC: *DefaultJSONRPCConfig(), } customAppTemplate := config.DefaultConfigTemplate + DefaultConfigTemplate @@ -58,17 +73,34 @@ func AppConfig(denom string) (string, interface{}) { func DefaultConfig() *Config { return &Config{ Config: *config.DefaultConfig(), - JSONRPC: *DefaultEVMConfig(), + EVM: *DefaultEVMConfig(), + JSONRPC: *DefaultJSONRPCConfig(), } } // 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' + // 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 @@ -83,13 +115,13 @@ type JSONRPCConfig struct { EnableUnsafeCORS bool `mapstructure:"enable-unsafe-cors"` } -// DefaultEVMConfig returns an EVM config with the JSON-RPC API enabled by default -func DefaultEVMConfig() *JSONRPCConfig { +// DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default +func DefaultJSONRPCConfig() *JSONRPCConfig { return &JSONRPCConfig{ Enable: true, API: GetDefaultAPINamespaces(), - Address: DefaultEVMAddress, - WsAddress: DefaultEVMWSAddress, + Address: DefaultJSONRPCAddress, + WsAddress: DefaultJSONRPCWsAddress, EnableUnsafeCORS: false, } } @@ -99,6 +131,7 @@ func DefaultEVMConfig() *JSONRPCConfig { type Config struct { config.Config + EVM EVMConfig `mapstructure:"evm"` JSONRPC JSONRPCConfig `mapstructure:"json-rpc"` } @@ -108,6 +141,9 @@ func GetConfig(v *viper.Viper) Config { return Config{ Config: cfg, + EVM: EVMConfig{ + Tracer: v.GetString("evm.tracer"), + }, JSONRPC: JSONRPCConfig{ Enable: v.GetBool("json-rpc.enable"), API: v.GetStringSlice("json-rpc.api"), @@ -117,3 +153,14 @@ func GetConfig(v *viper.Viper) Config { }, } } + +// 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 11479c74d9..9a19e3e997 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.Address, 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/flags.go b/server/flags.go index 27095d46e7..f9ee20fee4 100644 --- a/server/flags.go +++ b/server/flags.go @@ -7,6 +7,37 @@ import ( "github.com/spf13/viper" ) +// Tendermint full-node start flags +const ( + flagWithTendermint = "with-tendermint" + flagAddress = "address" + flagTransport = "transport" + flagTraceStore = "trace-store" + flagCPUProfile = "cpu-profile" +) + +// GRPC-related flags. +const ( + flagGRPCEnable = "grpc.enable" + flagGRPCAddress = "grpc.address" + flagGRPCWebEnable = "grpc-web.enable" + flagGRPCWebAddress = "grpc-web.address" +) + +// JSON-RPC flags +const ( + flagJSONRPCEnable = "json-rpc.enable" + flagJSONRPCAPI = "json-rpc.api" + flagJSONRPCAddress = "json-rpc.address" + flagJSONWsAddress = "json-rpc.ws-address" + flagJSONEnableUnsafeCORS = "json-rpc.enable-unsafe-cors" +) + +// EVM flags +const ( + flagEVMTracer = "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/start.go b/server/start.go index 564f5fb0cc..8da8000383 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" @@ -44,48 +45,6 @@ import ( "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 = "json-rpc.enable" - flagEVMRPCAPI = "json-rpc.api" - flagEVMRPCAddress = "json-rpc.address" - flagEVMWSAddress = "json-rpc.ws-address" - flagEVMEnableUnsafeCORS = "json-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" -) - // StartCmd runs the service passed in, either stand-alone or in-process with // Tendermint. func StartCmd(appCreator types.AppCreator, defaultNodeHome string) *cobra.Command { @@ -159,34 +118,35 @@ which accepts a path for the resulting pprof file. 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(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(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(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(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(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().Bool(flagJSONRPCEnable, true, "Define if the gRPC server should be enabled") + cmd.Flags().StringSlice(flagJSONRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled") + cmd.Flags().String(flagJSONRPCAddress, config.DefaultJSONRPCAddress, "the JSON-RPC server address to listen on") + cmd.Flags().String(flagJSONWsAddress, config.DefaultJSONRPCWsAddress, "the JSON-RPC WS server address to listen on") + cmd.Flags().Bool(flagJSONEnableUnsafeCORS, false, "Define if the JSON-RPC server should enabled CORS (unsafe - use it at your own risk)") + + cmd.Flags().String(flagEVMTracer, 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) @@ -272,10 +232,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) From 7a767304ce0ae7ae8105dd9abb7ccdc4ced7501e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 12 Aug 2021 17:38:16 +0200 Subject: [PATCH 3/7] fix import cycle --- app/app.go | 7 +++--- cmd/ethermintd/root.go | 3 ++- server/config/toml.go | 8 +++--- server/{ => flags}/flags.go | 32 ++++++++++++------------ server/start.go | 43 ++++++++++++++++---------------- x/evm/keeper/keeper.go | 9 ++----- x/evm/keeper/state_transition.go | 7 +++--- x/evm/types/tracer.go | 31 ++++++++++++++++------- 8 files changed, 77 insertions(+), 63 deletions(-) rename server/{ => flags}/flags.go (77%) diff --git a/app/app.go b/app/app.go index 93a5fed445..7d999b4b85 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 @@ -390,8 +393,6 @@ func NewEthermintApp( // we prefer to be more strict in what arguments the modules expect. skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) - // tracer := cast.ToString(appOpts.Get()) - // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.mm = module.NewManager( diff --git a/cmd/ethermintd/root.go b/cmd/ethermintd/root.go index 8b5323395c..471965dc04 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/server/config/toml.go b/server/config/toml.go index 2260978208..8c9f1f4247 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -6,10 +6,12 @@ const DefaultConfigTemplate = ` ### EVM Configuration ### ############################################################################### -[json-rpc] +[evm] -# tracer defines the tracer. -enable = {{ .EVMRPC.Enable }} +# 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 ### diff --git a/server/flags.go b/server/flags/flags.go similarity index 77% rename from server/flags.go rename to server/flags/flags.go index f9ee20fee4..5460c60242 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" @@ -9,33 +9,33 @@ import ( // Tendermint full-node start flags const ( - flagWithTendermint = "with-tendermint" - flagAddress = "address" - flagTransport = "transport" - flagTraceStore = "trace-store" - flagCPUProfile = "cpu-profile" + WithTendermint = "with-tendermint" + Address = "address" + Transport = "transport" + TraceStore = "trace-store" + CPUProfile = "cpu-profile" ) // GRPC-related flags. const ( - flagGRPCEnable = "grpc.enable" - flagGRPCAddress = "grpc.address" - flagGRPCWebEnable = "grpc-web.enable" - flagGRPCWebAddress = "grpc-web.address" + GRPCEnable = "grpc.enable" + GRPCAddress = "grpc.address" + GRPCWebEnable = "grpc-web.enable" + GRPCWebAddress = "grpc-web.address" ) // JSON-RPC flags const ( - flagJSONRPCEnable = "json-rpc.enable" - flagJSONRPCAPI = "json-rpc.api" - flagJSONRPCAddress = "json-rpc.address" - flagJSONWsAddress = "json-rpc.ws-address" - flagJSONEnableUnsafeCORS = "json-rpc.enable-unsafe-cors" + 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 ( - flagEVMTracer = "evm.tracer" + EVMTracer = "evm.tracer" ) // AddTxFlags adds common flags for commands to post tx diff --git a/server/start.go b/server/start.go index 8da8000383..2c0e3efd8a 100644 --- a/server/start.go +++ b/server/start.go @@ -43,6 +43,7 @@ import ( ethdebug "github.com/tharsis/ethermint/ethereum/rpc/namespaces/debug" "github.com/tharsis/ethermint/server/config" + srvflags "github.com/tharsis/ethermint/server/flags" ) // StartCmd runs the service passed in, either stand-alone or in-process with @@ -93,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) @@ -114,16 +115,16 @@ 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().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(flagCPUProfile, "", "Enable CPU profiling and write to the provided file") + 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')") @@ -132,18 +133,18 @@ which accepts a path for the resulting pprof file. 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(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.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(flagJSONRPCEnable, true, "Define if the gRPC server should be enabled") - cmd.Flags().StringSlice(flagJSONRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled") - cmd.Flags().String(flagJSONRPCAddress, config.DefaultJSONRPCAddress, "the JSON-RPC server address to listen on") - cmd.Flags().String(flagJSONWsAddress, config.DefaultJSONRPCWsAddress, "the JSON-RPC WS server address to listen on") - cmd.Flags().Bool(flagJSONEnableUnsafeCORS, false, "Define if the JSON-RPC server should enabled CORS (unsafe - use it at your own risk)") + 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().String(flagEVMTracer, config.DefaultEVMTracer, "the EVM tracer type to collect execution traces from the EVM transaction execution (json|struct|access_list|markdown)") + 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(server.FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") cmd.Flags().Uint32(server.FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") @@ -154,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) @@ -163,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 @@ -200,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 @@ -218,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()) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index f0fba4f347..7465a215d1 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -3,7 +3,6 @@ package keeper import ( "bytes" "math/big" - "os" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -11,7 +10,6 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/palantir/stacktrace" "github.com/tendermint/tendermint/libs/log" @@ -52,7 +50,7 @@ type Keeper struct { eip155ChainID *big.Int // Tracer used to collect execution traces from the EVM transaction execution - tracer vm.Tracer + 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 @@ -63,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 @@ -76,9 +74,6 @@ func NewKeeper( paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } - // TODO: consider using the Struct Logger too - tracer := vm.NewJSONLogger(&vm.LogConfig{Debug: debug}, os.Stderr) - // NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations return &Keeper{ cdc: cdc, diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index 22ec7b3815..fcbc1c79b4 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -40,18 +40,19 @@ 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) 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) vm.Config { + cfg := params.ChainConfig.EthereumConfig(k.eip155ChainID) return vm.Config{ Debug: k.debug, - Tracer: k.tracer, + Tracer: types.NewTracer(k.tracer, msg, cfg, k.Ctx().BlockHeight(), k.debug), NoRecursion: false, // TODO: consider disabling recursion though params ExtraEips: params.EIPs(), } diff --git a/x/evm/types/tracer.go b/x/evm/types/tracer.go index 3f09760f64..02bb400f9a 100644 --- a/x/evm/types/tracer.go +++ b/x/evm/types/tracer.go @@ -1,26 +1,39 @@ package types -import "github.com/ethereum/go-ethereum/core/vm" +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" - TracerMd = "md" ) -// NewTracer -func NewTracer(tracer string) vm.Tracer { +// 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: - return &vm.AccessListTracer{} + precompiles := vm.ActivePrecompiles(cfg.Rules(big.NewInt(height))) + return vm.NewAccessListTracer(msg.AccessList(), msg.From(), *msg.To(), precompiles) case TracerJSON: - return &vm.JSONLogger{} - case TracerMarkdown, TracerMd: - return vm.NewMarkdownLogger(nil, nil) + return vm.NewJSONLogger(logCfg, os.Stderr) + case TracerMarkdown: + return vm.NewMarkdownLogger(logCfg, os.Stdout) // TODO: Stderr ? case TracerStruct: - return vm.NewStructLogger(nil) + return vm.NewStructLogger(logCfg) default: return nil } From e112a5012a5143886fab589dde9b31110410c7b1 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 12 Aug 2021 17:44:09 +0200 Subject: [PATCH 4/7] fix start --- server/config/toml.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/config/toml.go b/server/config/toml.go index 8c9f1f4247..98ddcd1337 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -11,7 +11,7 @@ const DefaultConfigTemplate = ` # 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 }} +tracer = "{{ .EVM.Tracer }}" ############################################################################### ### JSON RPC Configuration ### From d783d38dddca623396f61f110b3504995410d429 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 16 Aug 2021 11:14:14 +0200 Subject: [PATCH 5/7] update fields --- app/ante/eth.go | 6 +++--- x/evm/keeper/grpc_query.go | 5 +++-- x/evm/keeper/state_transition.go | 16 +++++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/ante/eth.go b/app/ante/eth.go index 06dc292b14..9d81b14a80 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/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index db00b348aa..db812356c4 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/state_transition.go b/x/evm/keeper/state_transition.go index a8511a0395..54285df9cf 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -27,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, @@ -40,19 +46,19 @@ func (k *Keeper) NewEVM(msg core.Message, config *params.ChainConfig, params typ } txCtx := core.NewEVMTxContext(msg) - vmConfig := k.VMConfig(msg, 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(msg core.Message, 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: types.NewTracer(k.tracer, msg, cfg, k.Ctx().BlockHeight(), k.debug), + Tracer: types.NewTracer(tracer, msg, cfg, k.Ctx().BlockHeight(), k.debug), NoRecursion: false, // TODO: consider disabling recursion though params ExtraEips: params.EIPs(), } @@ -155,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() From e444e0087e29ca5a7f3482b63bc90a205ceee17b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 16 Aug 2021 11:17:27 +0200 Subject: [PATCH 6/7] c++ --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 810844e182..348b94f75c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,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 +66,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. From 934197ebe20060edd9ce70d0b3b7b16f25f36a7f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 16 Aug 2021 11:36:15 +0200 Subject: [PATCH 7/7] c++ --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 348b94f75c..41656c54a0 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.