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