You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.1 KiB

  1. package grpc
  2. import (
  3. "context"
  4. "time"
  5. grpc "google.golang.org/grpc"
  6. "google.golang.org/grpc/status"
  7. "github.com/tendermint/tendermint/crypto"
  8. cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
  9. "github.com/tendermint/tendermint/libs/log"
  10. privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval"
  11. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  12. "github.com/tendermint/tendermint/types"
  13. )
  14. // SignerClient implements PrivValidator.
  15. // Handles remote validator connections that provide signing services
  16. type SignerClient struct {
  17. logger log.Logger
  18. client privvalproto.PrivValidatorAPIClient
  19. conn *grpc.ClientConn
  20. chainID string
  21. }
  22. var _ types.PrivValidator = (*SignerClient)(nil)
  23. // NewSignerClient returns an instance of SignerClient.
  24. // it will start the endpoint (if not already started)
  25. func NewSignerClient(conn *grpc.ClientConn,
  26. chainID string, log log.Logger) (*SignerClient, error) {
  27. sc := &SignerClient{
  28. logger: log,
  29. chainID: chainID,
  30. client: privvalproto.NewPrivValidatorAPIClient(conn), // Create the Private Validator Client
  31. }
  32. return sc, nil
  33. }
  34. // Close closes the underlying connection
  35. func (sc *SignerClient) Close() error {
  36. sc.logger.Info("Stopping service")
  37. if sc.conn != nil {
  38. return sc.conn.Close()
  39. }
  40. return nil
  41. }
  42. //--------------------------------------------------------
  43. // Implement PrivValidator
  44. // GetPubKey retrieves a public key from a remote signer
  45. // returns an error if client is not able to provide the key
  46. func (sc *SignerClient) GetPubKey() (crypto.PubKey, error) {
  47. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // Todo: should this be configurable?
  48. defer cancel()
  49. resp, err := sc.client.GetPubKey(ctx, &privvalproto.PubKeyRequest{ChainId: sc.chainID})
  50. if err != nil {
  51. errStatus, _ := status.FromError(err)
  52. sc.logger.Error("SignerClient::GetPubKey", "err", errStatus.Message())
  53. return nil, errStatus.Err()
  54. }
  55. pk, err := cryptoenc.PubKeyFromProto(resp.PubKey)
  56. if err != nil {
  57. return nil, err
  58. }
  59. return pk, nil
  60. }
  61. // SignVote requests a remote signer to sign a vote
  62. func (sc *SignerClient) SignVote(chainID string, vote *tmproto.Vote) error {
  63. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  64. defer cancel()
  65. resp, err := sc.client.SignVote(ctx, &privvalproto.SignVoteRequest{ChainId: sc.chainID, Vote: vote})
  66. if err != nil {
  67. errStatus, _ := status.FromError(err)
  68. sc.logger.Error("Client SignVote", "err", errStatus.Message())
  69. return errStatus.Err()
  70. }
  71. *vote = resp.Vote
  72. return nil
  73. }
  74. // SignProposal requests a remote signer to sign a proposal
  75. func (sc *SignerClient) SignProposal(chainID string, proposal *tmproto.Proposal) error {
  76. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  77. defer cancel()
  78. resp, err := sc.client.SignProposal(
  79. ctx, &privvalproto.SignProposalRequest{ChainId: chainID, Proposal: proposal})
  80. if err != nil {
  81. errStatus, _ := status.FromError(err)
  82. sc.logger.Error("SignerClient::SignProposal", "err", errStatus.Message())
  83. return errStatus.Err()
  84. }
  85. *proposal = resp.Proposal
  86. return nil
  87. }