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 }