github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/privval/signer_client.go (about)

     1  package privval
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/lazyledger/lazyledger-core/crypto"
     8  	cryptoenc "github.com/lazyledger/lazyledger-core/crypto/encoding"
     9  	privvalproto "github.com/lazyledger/lazyledger-core/proto/tendermint/privval"
    10  	tmproto "github.com/lazyledger/lazyledger-core/proto/tendermint/types"
    11  	"github.com/lazyledger/lazyledger-core/types"
    12  )
    13  
    14  // SignerClient implements PrivValidator.
    15  // Handles remote validator connections that provide signing services
    16  type SignerClient struct {
    17  	endpoint *SignerListenerEndpoint
    18  	chainID  string
    19  }
    20  
    21  var _ types.PrivValidator = (*SignerClient)(nil)
    22  
    23  // NewSignerClient returns an instance of SignerClient.
    24  // it will start the endpoint (if not already started)
    25  func NewSignerClient(endpoint *SignerListenerEndpoint, chainID string) (*SignerClient, error) {
    26  	if !endpoint.IsRunning() {
    27  		if err := endpoint.Start(); err != nil {
    28  			return nil, fmt.Errorf("failed to start listener endpoint: %w", err)
    29  		}
    30  	}
    31  
    32  	return &SignerClient{endpoint: endpoint, chainID: chainID}, nil
    33  }
    34  
    35  // Close closes the underlying connection
    36  func (sc *SignerClient) Close() error {
    37  	return sc.endpoint.Close()
    38  }
    39  
    40  // IsConnected indicates with the signer is connected to a remote signing service
    41  func (sc *SignerClient) IsConnected() bool {
    42  	return sc.endpoint.IsConnected()
    43  }
    44  
    45  // WaitForConnection waits maxWait for a connection or returns a timeout error
    46  func (sc *SignerClient) WaitForConnection(maxWait time.Duration) error {
    47  	return sc.endpoint.WaitForConnection(maxWait)
    48  }
    49  
    50  //--------------------------------------------------------
    51  // Implement PrivValidator
    52  
    53  // Ping sends a ping request to the remote signer
    54  func (sc *SignerClient) Ping() error {
    55  	response, err := sc.endpoint.SendRequest(mustWrapMsg(&privvalproto.PingRequest{}))
    56  	if err != nil {
    57  		sc.endpoint.Logger.Error("SignerClient::Ping", "err", err)
    58  		return nil
    59  	}
    60  
    61  	pb := response.GetPingResponse()
    62  	if pb == nil {
    63  		return err
    64  	}
    65  
    66  	return nil
    67  }
    68  
    69  // GetPubKey retrieves a public key from a remote signer
    70  // returns an error if client is not able to provide the key
    71  func (sc *SignerClient) GetPubKey() (crypto.PubKey, error) {
    72  	response, err := sc.endpoint.SendRequest(mustWrapMsg(&privvalproto.PubKeyRequest{ChainId: sc.chainID}))
    73  	if err != nil {
    74  		return nil, fmt.Errorf("send: %w", err)
    75  	}
    76  
    77  	resp := response.GetPubKeyResponse()
    78  	if resp == nil {
    79  		return nil, ErrUnexpectedResponse
    80  	}
    81  	if resp.Error != nil {
    82  		return nil, &RemoteSignerError{Code: int(resp.Error.Code), Description: resp.Error.Description}
    83  	}
    84  
    85  	pk, err := cryptoenc.PubKeyFromProto(resp.PubKey)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	return pk, nil
    91  }
    92  
    93  // SignVote requests a remote signer to sign a vote
    94  func (sc *SignerClient) SignVote(chainID string, vote *tmproto.Vote) error {
    95  	response, err := sc.endpoint.SendRequest(mustWrapMsg(&privvalproto.SignVoteRequest{Vote: vote, ChainId: chainID}))
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	resp := response.GetSignedVoteResponse()
   101  	if resp == nil {
   102  		return ErrUnexpectedResponse
   103  	}
   104  	if resp.Error != nil {
   105  		return &RemoteSignerError{Code: int(resp.Error.Code), Description: resp.Error.Description}
   106  	}
   107  
   108  	*vote = resp.Vote
   109  
   110  	return nil
   111  }
   112  
   113  // SignProposal requests a remote signer to sign a proposal
   114  func (sc *SignerClient) SignProposal(chainID string, proposal *tmproto.Proposal) error {
   115  	response, err := sc.endpoint.SendRequest(mustWrapMsg(
   116  		&privvalproto.SignProposalRequest{Proposal: proposal, ChainId: chainID},
   117  	))
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	resp := response.GetSignedProposalResponse()
   123  	if resp == nil {
   124  		return ErrUnexpectedResponse
   125  	}
   126  	if resp.Error != nil {
   127  		return &RemoteSignerError{Code: int(resp.Error.Code), Description: resp.Error.Description}
   128  	}
   129  
   130  	*proposal = resp.Proposal
   131  
   132  	return nil
   133  }