diff --git a/CHANGELOG.md b/CHANGELOG.md index c7c226d957..45145b9e9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ - (evm) [#130](https://github.com/EscanBE/evermint/pull/130) Allow one and only one Ethereum Tx per tx execution - (misc) [#131](https://github.com/EscanBE/evermint/pull/131) Miscellaneous refactor and improve code logic - (rpc+indexer) [#138](https://github.com/EscanBE/evermint/pull/138) Improve check txs dropped pre-AnteHandle +- (rpc) [#142](https://github.com/EscanBE/evermint/pull/142) Support flag `--allow-insecure-unlock` to protect local accounts on node ### Bug Fixes diff --git a/README.md b/README.md index a901da4408..3cba3c9253 100644 --- a/README.md +++ b/README.md @@ -63,4 +63,5 @@ evmd convert-address evm1sv9m0g7ycejwr3s369km58h5qe7xj77hxrsmsz evmos 2. [Rename chain](https://github.com/EscanBE/evermint/blob/main/RENAME_CHAIN.md) 3. [`snapshots` command](https://github.com/EscanBE/evermint/pull/12) 4. [`inspect` command](https://github.com/EscanBE/evermint/pull/14) -5. Dependencies updated: `Cosmos-SDK v0.47.13`, `CometBFT v0.37.5`, `ibc-go v7.8.0`, `go-ethereum v1.10.26` \ No newline at end of file +5. [Flag `--allow-insecure-unlock`](https://github.com/EscanBE/evermint/pull/142) +6. Dependencies updated: `Cosmos-SDK v0.47.13`, `CometBFT v0.37.5`, `ibc-go v7.8.0`, `go-ethereum v1.10.26` \ No newline at end of file diff --git a/local_node.sh b/local_node.sh index e3ecd9b9b0..bcc438566b 100755 --- a/local_node.sh +++ b/local_node.sh @@ -165,6 +165,7 @@ fi --metrics "$TRACE" --log_level "$LOGLEVEL" \ --minimum-gas-prices="0.0001$MIN_DENOM" \ --json-rpc.api eth,txpool,personal,net,debug,web3 \ + --allow-insecure-unlock true \ --api.enable \ --grpc.enable true \ --home "$HOMEDIR" \ diff --git a/rpc/backend/node_info.go b/rpc/backend/node_info.go index 3bf1f8da80..77bd91f68b 100644 --- a/rpc/backend/node_info.go +++ b/rpc/backend/node_info.go @@ -1,6 +1,7 @@ package backend import ( + "errors" "fmt" "math/big" "time" @@ -28,6 +29,11 @@ import ( // Accounts returns the list of accounts available to this node. func (b *Backend) Accounts() ([]common.Address, error) { + if !b.cfg.JSONRPC.AllowInsecureUnlock { + b.logger.Debug("account unlock with HTTP access is forbidden") + return []common.Address{}, errors.New("account unlock with HTTP access is forbidden") + } + addresses := make([]common.Address, 0) // return [] instead of nil if empty infos, err := b.clientCtx.Keyring.List() @@ -75,6 +81,11 @@ func (b *Backend) Syncing() (interface{}, error) { // SetEtherbase sets the etherbase of the miner func (b *Backend) SetEtherbase(etherbase common.Address) bool { + if !b.cfg.JSONRPC.AllowInsecureUnlock { + b.logger.Debug("account unlock with HTTP access is forbidden") + return false + } + delAddr, err := b.GetCoinbase() if err != nil { b.logger.Debug("failed to get coinbase address", "error", err.Error()) @@ -214,6 +225,11 @@ func (b *Backend) ImportRawKey(privkey, password string) (common.Address, error) // ListAccounts will return a list of addresses for accounts this node manages. func (b *Backend) ListAccounts() ([]common.Address, error) { + if !b.cfg.JSONRPC.AllowInsecureUnlock { + b.logger.Debug("account unlock with HTTP access is forbidden") + return []common.Address{}, fmt.Errorf("account unlock with HTTP access is forbidden") + } + addrs := []common.Address{} list, err := b.clientCtx.Keyring.List() diff --git a/rpc/backend/sign_tx.go b/rpc/backend/sign_tx.go index 493a661c69..886f269d7f 100644 --- a/rpc/backend/sign_tx.go +++ b/rpc/backend/sign_tx.go @@ -20,6 +20,11 @@ import ( // SendTransaction sends transaction based on received args using Node's key to sign it func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) { + if !b.cfg.JSONRPC.AllowInsecureUnlock { + b.logger.Debug("account unlock with HTTP access is forbidden") + return common.Hash{}, fmt.Errorf("account unlock with HTTP access is forbidden") + } + // Look up the wallet containing the requested signer _, err := b.clientCtx.Keyring.KeyByAddress(sdk.AccAddress(args.GetFrom().Bytes())) if err != nil { diff --git a/server/config/config.go b/server/config/config.go index 017315dabc..28b2da4992 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -3,6 +3,7 @@ package config import ( "errors" "fmt" + "github.com/EscanBE/evermint/v12/server/flags" "path" "time" @@ -25,7 +26,7 @@ const ( // DefaultJSONRPCWsAddress is the default address the JSON-RPC WebSocket server binds to. DefaultJSONRPCWsAddress = "127.0.0.1:8546" - // DefaultJsonRPCMetricsAddress is the default address the JSON-RPC Metrics server binds to. + // DefaultJSONRPCMetricsAddress is the default address the JSON-RPC Metrics server binds to. DefaultJSONRPCMetricsAddress = "127.0.0.1:6065" // DefaultEVMTracer is the default vm.Tracer type @@ -64,6 +65,9 @@ const ( // DefaultAllowUnprotectedTxs value is false DefaultAllowUnprotectedTxs = false + // DefaultAllowInsecureUnlock is the default value of allow insecure unlock configuration + DefaultAllowInsecureUnlock = false + // DefaultMaxOpenConnections represents the amount of open connections (unlimited = 0) DefaultMaxOpenConnections = 0 ) @@ -120,6 +124,8 @@ type JSONRPCConfig struct { // AllowUnprotectedTxs restricts unprotected (non EIP155 signed) transactions to be submitted via // the node's RPC when global parameter is disabled. AllowUnprotectedTxs bool `mapstructure:"allow-unprotected-txs"` + // AllowInsecureUnlock allow insecure account unlocking when account-related RPCs are exposed by http + AllowInsecureUnlock bool `mapstructure:"allow-insecure-unlock"` // MaxOpenConnections sets the maximum number of simultaneous connections // for the server listener. MaxOpenConnections int `mapstructure:"max-open-connections"` @@ -224,6 +230,7 @@ func DefaultJSONRPCConfig() *JSONRPCConfig { HTTPTimeout: DefaultHTTPTimeout, HTTPIdleTimeout: DefaultHTTPIdleTimeout, AllowUnprotectedTxs: DefaultAllowUnprotectedTxs, + AllowInsecureUnlock: DefaultAllowInsecureUnlock, MaxOpenConnections: DefaultMaxOpenConnections, MetricsAddress: DefaultJSONRPCMetricsAddress, } @@ -319,21 +326,23 @@ func GetConfig(v *viper.Viper) (Config, error) { MaxTxGasWanted: v.GetUint64("evm.max-tx-gas-wanted"), }, 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"), - GasCap: v.GetUint64("json-rpc.gas-cap"), - FilterCap: v.GetInt32("json-rpc.filter-cap"), - FeeHistoryCap: v.GetInt32("json-rpc.feehistory-cap"), - TxFeeCap: v.GetFloat64("json-rpc.txfee-cap"), - EVMTimeout: v.GetDuration("json-rpc.evm-timeout"), - LogsCap: v.GetInt32("json-rpc.logs-cap"), - BlockRangeCap: v.GetInt32("json-rpc.block-range-cap"), - HTTPTimeout: v.GetDuration("json-rpc.http-timeout"), - HTTPIdleTimeout: v.GetDuration("json-rpc.http-idle-timeout"), - MaxOpenConnections: v.GetInt("json-rpc.max-open-connections"), - MetricsAddress: v.GetString("json-rpc.metrics-address"), + 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"), + GasCap: v.GetUint64("json-rpc.gas-cap"), + FilterCap: v.GetInt32("json-rpc.filter-cap"), + FeeHistoryCap: v.GetInt32("json-rpc.feehistory-cap"), + TxFeeCap: v.GetFloat64("json-rpc.txfee-cap"), + EVMTimeout: v.GetDuration("json-rpc.evm-timeout"), + LogsCap: v.GetInt32("json-rpc.logs-cap"), + BlockRangeCap: v.GetInt32("json-rpc.block-range-cap"), + HTTPTimeout: v.GetDuration("json-rpc.http-timeout"), + HTTPIdleTimeout: v.GetDuration("json-rpc.http-idle-timeout"), + AllowUnprotectedTxs: v.GetBool(flags.JSONRPCAllowUnprotectedTxs) || v.GetBool(flags.LegacyRpcAllowUnprotectedTxs), + AllowInsecureUnlock: v.GetBool(flags.JSONRPCAllowInsecureUnlock) || v.GetBool(flags.LegacyAllowInsecureUnlock), + MaxOpenConnections: v.GetInt("json-rpc.max-open-connections"), + MetricsAddress: v.GetString("json-rpc.metrics-address"), }, TLS: TLSConfig{ CertificatePath: v.GetString("tls.certificate-path"), diff --git a/server/config/toml.go b/server/config/toml.go index 6486e6e75e..838a1c7080 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -22,7 +22,7 @@ max-tx-gas-wanted = {{ .EVM.MaxTxGasWanted }} [json-rpc] -# Enable defines if the gRPC server should be enabled. +# Enable defines if the EVM Json-RPC server should be enabled. enable = {{ .JSONRPC.Enable }} # Address defines the EVM RPC HTTP server address to bind to. @@ -66,6 +66,9 @@ http-idle-timeout = "{{ .JSONRPC.HTTPIdleTimeout }}" # the node's RPC when the global parameter is disabled. allow-unprotected-txs = {{ .JSONRPC.AllowUnprotectedTxs }} +# Allow insecure account unlocking when account-related RPCs are exposed by http +allow-insecure-unlock = {{ .JSONRPC.AllowInsecureUnlock }} + # MaxOpenConnections sets the maximum number of simultaneous connections # for the server listener. max-open-connections = {{ .JSONRPC.MaxOpenConnections }} diff --git a/server/flags/flags.go b/server/flags/flags.go index ccdc29b722..8adde11af6 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -50,6 +50,7 @@ const ( JSONRPCHTTPTimeout = "json-rpc.http-timeout" JSONRPCHTTPIdleTimeout = "json-rpc.http-idle-timeout" JSONRPCAllowUnprotectedTxs = "json-rpc.allow-unprotected-txs" + JSONRPCAllowInsecureUnlock = "json-rpc.allow-insecure-unlock" JSONRPCMaxOpenConnections = "json-rpc.max-open-connections" // JSONRPCEnableMetrics enables EVM RPC metrics server. // Set to `metrics` which is hardcoded flag from go-ethereum. @@ -57,6 +58,12 @@ const ( JSONRPCEnableMetrics = "metrics" ) +// Flags follow go-ethereum naming +const ( + LegacyRpcAllowUnprotectedTxs = "rpc.allow-unprotected-txs" + LegacyAllowInsecureUnlock = "allow-insecure-unlock" +) + // EVM flags const ( EVMTracer = "evm.tracer" diff --git a/server/start.go b/server/start.go index 3e11d4f4d8..00cc7bba62 100644 --- a/server/start.go +++ b/server/start.go @@ -191,6 +191,9 @@ which accepts a path for the resulting pprof file. cmd.Flags().Duration(srvflags.JSONRPCHTTPTimeout, config.DefaultHTTPTimeout, "Sets a read/write timeout for json-rpc http server (0=infinite)") cmd.Flags().Duration(srvflags.JSONRPCHTTPIdleTimeout, config.DefaultHTTPIdleTimeout, "Sets a idle timeout for json-rpc http server (0=infinite)") cmd.Flags().Bool(srvflags.JSONRPCAllowUnprotectedTxs, config.DefaultAllowUnprotectedTxs, "Allow for unprotected (non EIP155 signed) transactions to be submitted via the node's RPC when the global parameter is disabled") //nolint:lll + cmd.Flags().Bool(srvflags.LegacyRpcAllowUnprotectedTxs, config.DefaultAllowUnprotectedTxs, fmt.Sprintf("alias of flag --%s to consistency with go-ethereum naming", srvflags.JSONRPCAllowUnprotectedTxs)) //nolint:lll + cmd.Flags().Bool(srvflags.JSONRPCAllowInsecureUnlock, config.DefaultAllowInsecureUnlock, "Allow insecure account unlocking when account-related RPCs are exposed by http") + cmd.Flags().Bool(srvflags.LegacyAllowInsecureUnlock, config.DefaultAllowInsecureUnlock, fmt.Sprintf("alias of flag --%s to consistency with go-ethereum naming", srvflags.JSONRPCAllowInsecureUnlock)) cmd.Flags().Int32(srvflags.JSONRPCLogsCap, config.DefaultLogsCap, "Sets the max number of results can be returned from single `eth_getLogs` query") cmd.Flags().Int32(srvflags.JSONRPCBlockRangeCap, config.DefaultBlockRangeCap, "Sets the max block range allowed for `eth_getLogs` query") cmd.Flags().Int(srvflags.JSONRPCMaxOpenConnections, config.DefaultMaxOpenConnections, "Sets the maximum number of simultaneous connections for the server listener") //nolint:lll