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.

303 lines
7.2 KiB

  1. package privval
  2. import (
  3. "fmt"
  4. "io"
  5. "net"
  6. "sync"
  7. "github.com/tendermint/go-amino"
  8. "github.com/tendermint/tendermint/crypto"
  9. cmn "github.com/tendermint/tendermint/libs/common"
  10. "github.com/tendermint/tendermint/types"
  11. )
  12. // RemoteSignerClient implements PrivValidator, it uses a socket to request signatures
  13. // from an external process.
  14. type RemoteSignerClient struct {
  15. conn net.Conn
  16. lock sync.Mutex
  17. }
  18. // Check that RemoteSignerClient implements PrivValidator.
  19. var _ types.PrivValidator = (*RemoteSignerClient)(nil)
  20. // NewRemoteSignerClient returns an instance of RemoteSignerClient.
  21. func NewRemoteSignerClient(
  22. conn net.Conn,
  23. ) *RemoteSignerClient {
  24. sc := &RemoteSignerClient{
  25. conn: conn,
  26. }
  27. return sc
  28. }
  29. // GetAddress implements PrivValidator.
  30. func (sc *RemoteSignerClient) GetAddress() types.Address {
  31. pubKey, err := sc.getPubKey()
  32. if err != nil {
  33. panic(err)
  34. }
  35. return pubKey.Address()
  36. }
  37. // GetPubKey implements PrivValidator.
  38. func (sc *RemoteSignerClient) GetPubKey() crypto.PubKey {
  39. pubKey, err := sc.getPubKey()
  40. if err != nil {
  41. panic(err)
  42. }
  43. return pubKey
  44. }
  45. func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) {
  46. sc.lock.Lock()
  47. defer sc.lock.Unlock()
  48. err := writeMsg(sc.conn, &PubKeyMsg{})
  49. if err != nil {
  50. return nil, err
  51. }
  52. res, err := readMsg(sc.conn)
  53. if err != nil {
  54. return nil, err
  55. }
  56. return res.(*PubKeyMsg).PubKey, nil
  57. }
  58. // SignVote implements PrivValidator.
  59. func (sc *RemoteSignerClient) SignVote(chainID string, vote *types.Vote) error {
  60. sc.lock.Lock()
  61. defer sc.lock.Unlock()
  62. err := writeMsg(sc.conn, &SignVoteRequest{Vote: vote})
  63. if err != nil {
  64. return err
  65. }
  66. res, err := readMsg(sc.conn)
  67. if err != nil {
  68. return err
  69. }
  70. resp, ok := res.(*SignedVoteResponse)
  71. if !ok {
  72. return ErrUnexpectedResponse
  73. }
  74. if resp.Error != nil {
  75. return resp.Error
  76. }
  77. *vote = *resp.Vote
  78. return nil
  79. }
  80. // SignProposal implements PrivValidator.
  81. func (sc *RemoteSignerClient) SignProposal(
  82. chainID string,
  83. proposal *types.Proposal,
  84. ) error {
  85. sc.lock.Lock()
  86. defer sc.lock.Unlock()
  87. err := writeMsg(sc.conn, &SignProposalRequest{Proposal: proposal})
  88. if err != nil {
  89. return err
  90. }
  91. res, err := readMsg(sc.conn)
  92. if err != nil {
  93. return err
  94. }
  95. resp, ok := res.(*SignedProposalResponse)
  96. if !ok {
  97. return ErrUnexpectedResponse
  98. }
  99. if resp.Error != nil {
  100. return resp.Error
  101. }
  102. *proposal = *resp.Proposal
  103. return nil
  104. }
  105. // SignHeartbeat implements PrivValidator.
  106. func (sc *RemoteSignerClient) SignHeartbeat(
  107. chainID string,
  108. heartbeat *types.Heartbeat,
  109. ) error {
  110. sc.lock.Lock()
  111. defer sc.lock.Unlock()
  112. err := writeMsg(sc.conn, &SignHeartbeatRequest{Heartbeat: heartbeat})
  113. if err != nil {
  114. return err
  115. }
  116. res, err := readMsg(sc.conn)
  117. if err != nil {
  118. return err
  119. }
  120. resp, ok := res.(*SignedHeartbeatResponse)
  121. if !ok {
  122. return ErrUnexpectedResponse
  123. }
  124. if resp.Error != nil {
  125. return resp.Error
  126. }
  127. *heartbeat = *resp.Heartbeat
  128. return nil
  129. }
  130. // Ping is used to check connection health.
  131. func (sc *RemoteSignerClient) Ping() error {
  132. sc.lock.Lock()
  133. defer sc.lock.Unlock()
  134. err := writeMsg(sc.conn, &PingRequest{})
  135. if err != nil {
  136. return err
  137. }
  138. res, err := readMsg(sc.conn)
  139. if err != nil {
  140. return err
  141. }
  142. _, ok := res.(*PingResponse)
  143. if !ok {
  144. return ErrUnexpectedResponse
  145. }
  146. return nil
  147. }
  148. // RemoteSignerMsg is sent between RemoteSigner and the RemoteSigner client.
  149. type RemoteSignerMsg interface{}
  150. func RegisterRemoteSignerMsg(cdc *amino.Codec) {
  151. cdc.RegisterInterface((*RemoteSignerMsg)(nil), nil)
  152. cdc.RegisterConcrete(&PubKeyMsg{}, "tendermint/remotesigner/PubKeyMsg", nil)
  153. cdc.RegisterConcrete(&SignVoteRequest{}, "tendermint/remotesigner/SignVoteRequest", nil)
  154. cdc.RegisterConcrete(&SignedVoteResponse{}, "tendermint/remotesigner/SignedVoteResponse", nil)
  155. cdc.RegisterConcrete(&SignProposalRequest{}, "tendermint/remotesigner/SignProposalRequest", nil)
  156. cdc.RegisterConcrete(&SignedProposalResponse{}, "tendermint/remotesigner/SignedProposalResponse", nil)
  157. cdc.RegisterConcrete(&SignHeartbeatRequest{}, "tendermint/remotesigner/SignHeartbeatRequest", nil)
  158. cdc.RegisterConcrete(&SignedHeartbeatResponse{}, "tendermint/remotesigner/SignedHeartbeatResponse", nil)
  159. cdc.RegisterConcrete(&PingRequest{}, "tendermint/remotesigner/PingRequest", nil)
  160. cdc.RegisterConcrete(&PingResponse{}, "tendermint/remotesigner/PingResponse", nil)
  161. }
  162. // PubKeyMsg is a PrivValidatorSocket message containing the public key.
  163. type PubKeyMsg struct {
  164. PubKey crypto.PubKey
  165. }
  166. // SignVoteRequest is a PrivValidatorSocket message containing a vote.
  167. type SignVoteRequest struct {
  168. Vote *types.Vote
  169. }
  170. // SignedVoteResponse is a PrivValidatorSocket message containing a signed vote along with a potenial error message.
  171. type SignedVoteResponse struct {
  172. Vote *types.Vote
  173. Error *RemoteSignerError
  174. }
  175. // SignProposalRequest is a PrivValidatorSocket message containing a Proposal.
  176. type SignProposalRequest struct {
  177. Proposal *types.Proposal
  178. }
  179. type SignedProposalResponse struct {
  180. Proposal *types.Proposal
  181. Error *RemoteSignerError
  182. }
  183. // SignHeartbeatRequest is a PrivValidatorSocket message containing a Heartbeat.
  184. type SignHeartbeatRequest struct {
  185. Heartbeat *types.Heartbeat
  186. }
  187. type SignedHeartbeatResponse struct {
  188. Heartbeat *types.Heartbeat
  189. Error *RemoteSignerError
  190. }
  191. // PingRequest is a PrivValidatorSocket message to keep the connection alive.
  192. type PingRequest struct {
  193. }
  194. type PingResponse struct {
  195. }
  196. // RemoteSignerError allows (remote) validators to include meaningful error descriptions in their reply.
  197. type RemoteSignerError struct {
  198. // TODO(ismail): create an enum of known errors
  199. Code int
  200. Description string
  201. }
  202. func (e *RemoteSignerError) Error() string {
  203. return fmt.Sprintf("RemoteSigner returned error #%d: %s", e.Code, e.Description)
  204. }
  205. func readMsg(r io.Reader) (msg RemoteSignerMsg, err error) {
  206. const maxRemoteSignerMsgSize = 1024 * 10
  207. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(r, &msg, maxRemoteSignerMsgSize)
  208. if _, ok := err.(timeoutError); ok {
  209. err = cmn.ErrorWrap(ErrConnTimeout, err.Error())
  210. }
  211. return
  212. }
  213. func writeMsg(w io.Writer, msg interface{}) (err error) {
  214. _, err = cdc.MarshalBinaryLengthPrefixedWriter(w, msg)
  215. if _, ok := err.(timeoutError); ok {
  216. err = cmn.ErrorWrap(ErrConnTimeout, err.Error())
  217. }
  218. return
  219. }
  220. func handleRequest(req RemoteSignerMsg, chainID string, privVal types.PrivValidator) (RemoteSignerMsg, error) {
  221. var res RemoteSignerMsg
  222. var err error
  223. switch r := req.(type) {
  224. case *PubKeyMsg:
  225. var p crypto.PubKey
  226. p = privVal.GetPubKey()
  227. res = &PubKeyMsg{p}
  228. case *SignVoteRequest:
  229. err = privVal.SignVote(chainID, r.Vote)
  230. if err != nil {
  231. res = &SignedVoteResponse{nil, &RemoteSignerError{0, err.Error()}}
  232. } else {
  233. res = &SignedVoteResponse{r.Vote, nil}
  234. }
  235. case *SignProposalRequest:
  236. err = privVal.SignProposal(chainID, r.Proposal)
  237. if err != nil {
  238. res = &SignedProposalResponse{nil, &RemoteSignerError{0, err.Error()}}
  239. } else {
  240. res = &SignedProposalResponse{r.Proposal, nil}
  241. }
  242. case *SignHeartbeatRequest:
  243. err = privVal.SignHeartbeat(chainID, r.Heartbeat)
  244. if err != nil {
  245. res = &SignedHeartbeatResponse{nil, &RemoteSignerError{0, err.Error()}}
  246. } else {
  247. res = &SignedHeartbeatResponse{r.Heartbeat, nil}
  248. }
  249. case *PingRequest:
  250. res = &PingResponse{}
  251. default:
  252. err = fmt.Errorf("unknown msg: %v", r)
  253. }
  254. return res, err
  255. }