github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/privval/signer_client.go (about)

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