diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index d91ad4b76..7c76703f1 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -49,7 +49,8 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi - [crypto/ed25519] \#5632 Adopt zip215 `ed25519` verification. (@marbar3778) - [privval] \#5603 Add `--key` to `init`, `gen_validator`, `testnet` & `unsafe_reset_priv_validator` for use in generating `secp256k1` keys. -- [privval] \#5725 add gRPC support to private validator. +- [privval] \#5725 Add gRPC support to private validator. +- [privval] \#5876 `tendermint show-validator` will query the remote signer if gRPC is being used (@marbar3778) - [abci/client] \#5673 `Async` requests return an error if queue is full (@melekes) - [mempool] \#5673 Cancel `CheckTx` requests if RPC client disconnects or times out (@melekes) - [abci] \#5706 Added `AbciVersion` to `RequestInfo` allowing applications to check ABCI version when connecting to Tendermint. (@marbar3778) diff --git a/cmd/tendermint/commands/show_validator.go b/cmd/tendermint/commands/show_validator.go index f29976bb3..54b027961 100644 --- a/cmd/tendermint/commands/show_validator.go +++ b/cmd/tendermint/commands/show_validator.go @@ -5,9 +5,12 @@ import ( "github.com/spf13/cobra" + "github.com/tendermint/tendermint/crypto" tmjson "github.com/tendermint/tendermint/libs/json" + tmnet "github.com/tendermint/tendermint/libs/net" tmos "github.com/tendermint/tendermint/libs/os" "github.com/tendermint/tendermint/privval" + tmgrpc "github.com/tendermint/tendermint/privval/grpc" ) // ShowValidatorCmd adds capabilities for showing the validator info. @@ -20,16 +23,36 @@ var ShowValidatorCmd = &cobra.Command{ } func showValidator(cmd *cobra.Command, args []string) error { - keyFilePath := config.PrivValidatorKeyFile() - if !tmos.FileExists(keyFilePath) { - return fmt.Errorf("private validator file %s does not exist", keyFilePath) - } + var ( + pubKey crypto.PubKey + err error + ) - pv := privval.LoadFilePV(keyFilePath, config.PrivValidatorStateFile()) + //TODO: remove once gRPC is the only supported protocol + protocol, _ := tmnet.ProtocolAndAddress(config.PrivValidatorListenAddr) + switch protocol { + case "grpc": + pvsc, err := tmgrpc.DialRemoteSigner(config, config.ChainID(), logger) + if err != nil { + return fmt.Errorf("can't connect to remote validator %w", err) + } + pubKey, err = pvsc.GetPubKey() + if err != nil { + return fmt.Errorf("can't get pubkey: %w", err) + } + default: - pubKey, err := pv.GetPubKey() - if err != nil { - return fmt.Errorf("can't get pubkey: %w", err) + keyFilePath := config.PrivValidatorKeyFile() + if !tmos.FileExists(keyFilePath) { + return fmt.Errorf("private validator file %s does not exist", keyFilePath) + } + + pv := privval.LoadFilePV(keyFilePath, config.PrivValidatorStateFile()) + + pubKey, err = pv.GetPubKey() + if err != nil { + return fmt.Errorf("can't get pubkey: %w", err) + } } bz, err := tmjson.Marshal(pubKey) diff --git a/node/node.go b/node/node.go index d9e504758..06161cde7 100644 --- a/node/node.go +++ b/node/node.go @@ -10,11 +10,9 @@ import ( _ "net/http/pprof" // nolint: gosec // securely exposed on separate, optional port "time" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/rs/cors" - "google.golang.org/grpc" dbm "github.com/tendermint/tm-db" @@ -678,11 +676,11 @@ func NewNode(config *cfg.Config, // If an address is provided, listen on the socket for a connection from an // external signing process. if config.PrivValidatorListenAddr != "" { - protocol, address := tmnet.ProtocolAndAddress(config.PrivValidatorListenAddr) + protocol, _ := tmnet.ProtocolAndAddress(config.PrivValidatorListenAddr) // FIXME: we should start services inside OnStart switch protocol { case "grpc": - privValidator, err = createAndStartPrivValidatorGRPCClient(config, address, genDoc.ChainID, logger) + privValidator, err = createAndStartPrivValidatorGRPCClient(config, genDoc.ChainID, logger) if err != nil { return nil, fmt.Errorf("error with private validator grpc client: %w", err) } @@ -1435,33 +1433,10 @@ func createAndStartPrivValidatorSocketClient( func createAndStartPrivValidatorGRPCClient( config *cfg.Config, - address, chainID string, logger log.Logger, ) (types.PrivValidator, error) { - var transportSecurity grpc.DialOption - if config.BaseConfig.ArePrivValidatorClientSecurityOptionsPresent() { - transportSecurity = tmgrpc.GenerateTLS(config.PrivValidatorClientCertificateFile(), - config.PrivValidatorClientKeyFile(), config.PrivValidatorRootCAFile(), logger) - } else { - transportSecurity = grpc.WithInsecure() - logger.Info("Using an insecure gRPC connection!") - } - dialOptions := tmgrpc.DefaultDialOptions() - if config.Instrumentation.Prometheus { - grpcMetrics := grpc_prometheus.DefaultClientMetrics - dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(grpcMetrics.UnaryClientInterceptor())) - } - - dialOptions = append(dialOptions, transportSecurity) - - ctx := context.Background() - - conn, err := grpc.DialContext(ctx, address, dialOptions...) - if err != nil { - logger.Error("unable to connect to server", "target", address, "err", err) - } - pvsc, err := tmgrpc.NewSignerClient(conn, chainID, logger) + pvsc, err := tmgrpc.DialRemoteSigner(config, chainID, logger) if err != nil { return nil, fmt.Errorf("failed to start private validator: %w", err) } diff --git a/privval/grpc/util.go b/privval/grpc/util.go index 66b5397b6..a70ab54bf 100644 --- a/privval/grpc/util.go +++ b/privval/grpc/util.go @@ -1,6 +1,7 @@ package grpc import ( + "context" "crypto/tls" "crypto/x509" "io/ioutil" @@ -8,7 +9,11 @@ import ( "time" grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" + grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + + cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/log" + tmnet "github.com/tendermint/tendermint/libs/net" grpc "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" @@ -80,3 +85,36 @@ func GenerateTLS(certPath, keyPath, ca string, log log.Logger) grpc.DialOption { return grpc.WithTransportCredentials(transportCreds) } + +// DialRemoteSigner is a generalized function to dial the gRPC server. +func DialRemoteSigner( + config *cfg.Config, + chainID string, + logger log.Logger, +) (*SignerClient, error) { + var transportSecurity grpc.DialOption + if config.BaseConfig.ArePrivValidatorClientSecurityOptionsPresent() { + transportSecurity = GenerateTLS(config.PrivValidatorClientCertificateFile(), + config.PrivValidatorClientKeyFile(), config.PrivValidatorRootCAFile(), logger) + } else { + transportSecurity = grpc.WithInsecure() + logger.Info("Using an insecure gRPC connection!") + } + + dialOptions := DefaultDialOptions() + if config.Instrumentation.Prometheus { + grpcMetrics := grpc_prometheus.DefaultClientMetrics + dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(grpcMetrics.UnaryClientInterceptor())) + } + + dialOptions = append(dialOptions, transportSecurity) + + ctx := context.Background() + _, address := tmnet.ProtocolAndAddress(config.PrivValidatorListenAddr) + conn, err := grpc.DialContext(ctx, address, dialOptions...) + if err != nil { + logger.Error("unable to connect to server", "target", address, "err", err) + } + + return NewSignerClient(conn, chainID, logger) +}