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.

603 lines
14 KiB

  1. package privval
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "net"
  7. "time"
  8. "github.com/tendermint/go-amino"
  9. "github.com/tendermint/tendermint/crypto"
  10. "github.com/tendermint/tendermint/crypto/ed25519"
  11. cmn "github.com/tendermint/tendermint/libs/common"
  12. "github.com/tendermint/tendermint/libs/log"
  13. p2pconn "github.com/tendermint/tendermint/p2p/conn"
  14. "github.com/tendermint/tendermint/types"
  15. )
  16. const (
  17. defaultAcceptDeadlineSeconds = 3
  18. defaultConnDeadlineSeconds = 3
  19. defaultConnHeartBeatSeconds = 30
  20. defaultConnWaitSeconds = 60
  21. defaultDialRetries = 10
  22. )
  23. // Socket errors.
  24. var (
  25. ErrDialRetryMax = errors.New("dialed maximum retries")
  26. ErrConnWaitTimeout = errors.New("waited for remote signer for too long")
  27. ErrConnTimeout = errors.New("remote signer timed out")
  28. ErrUnexpectedResponse = errors.New("received unexpected response")
  29. )
  30. var (
  31. acceptDeadline = time.Second * defaultAcceptDeadlineSeconds
  32. connDeadline = time.Second * defaultConnDeadlineSeconds
  33. connHeartbeat = time.Second * defaultConnHeartBeatSeconds
  34. )
  35. // SocketPVOption sets an optional parameter on the SocketPV.
  36. type SocketPVOption func(*SocketPV)
  37. // SocketPVAcceptDeadline sets the deadline for the SocketPV listener.
  38. // A zero time value disables the deadline.
  39. func SocketPVAcceptDeadline(deadline time.Duration) SocketPVOption {
  40. return func(sc *SocketPV) { sc.acceptDeadline = deadline }
  41. }
  42. // SocketPVConnDeadline sets the read and write deadline for connections
  43. // from external signing processes.
  44. func SocketPVConnDeadline(deadline time.Duration) SocketPVOption {
  45. return func(sc *SocketPV) { sc.connDeadline = deadline }
  46. }
  47. // SocketPVHeartbeat sets the period on which to check the liveness of the
  48. // connected Signer connections.
  49. func SocketPVHeartbeat(period time.Duration) SocketPVOption {
  50. return func(sc *SocketPV) { sc.connHeartbeat = period }
  51. }
  52. // SocketPVConnWait sets the timeout duration before connection of external
  53. // signing processes are considered to be unsuccessful.
  54. func SocketPVConnWait(timeout time.Duration) SocketPVOption {
  55. return func(sc *SocketPV) { sc.connWaitTimeout = timeout }
  56. }
  57. // SocketPV implements PrivValidator, it uses a socket to request signatures
  58. // from an external process.
  59. type SocketPV struct {
  60. cmn.BaseService
  61. addr string
  62. acceptDeadline time.Duration
  63. connDeadline time.Duration
  64. connHeartbeat time.Duration
  65. connWaitTimeout time.Duration
  66. privKey ed25519.PrivKeyEd25519
  67. conn net.Conn
  68. listener net.Listener
  69. }
  70. // Check that SocketPV implements PrivValidator.
  71. var _ types.PrivValidator = (*SocketPV)(nil)
  72. // NewSocketPV returns an instance of SocketPV.
  73. func NewSocketPV(
  74. logger log.Logger,
  75. socketAddr string,
  76. privKey ed25519.PrivKeyEd25519,
  77. ) *SocketPV {
  78. sc := &SocketPV{
  79. addr: socketAddr,
  80. acceptDeadline: acceptDeadline,
  81. connDeadline: connDeadline,
  82. connHeartbeat: connHeartbeat,
  83. connWaitTimeout: time.Second * defaultConnWaitSeconds,
  84. privKey: privKey,
  85. }
  86. sc.BaseService = *cmn.NewBaseService(logger, "SocketPV", sc)
  87. return sc
  88. }
  89. // GetAddress implements PrivValidator.
  90. func (sc *SocketPV) GetAddress() types.Address {
  91. addr, err := sc.getAddress()
  92. if err != nil {
  93. panic(err)
  94. }
  95. return addr
  96. }
  97. // Address is an alias for PubKey().Address().
  98. func (sc *SocketPV) getAddress() (cmn.HexBytes, error) {
  99. p, err := sc.getPubKey()
  100. if err != nil {
  101. return nil, err
  102. }
  103. return p.Address(), nil
  104. }
  105. // GetPubKey implements PrivValidator.
  106. func (sc *SocketPV) GetPubKey() crypto.PubKey {
  107. pubKey, err := sc.getPubKey()
  108. if err != nil {
  109. panic(err)
  110. }
  111. return pubKey
  112. }
  113. func (sc *SocketPV) getPubKey() (crypto.PubKey, error) {
  114. err := writeMsg(sc.conn, &PubKeyMsg{})
  115. if err != nil {
  116. return nil, err
  117. }
  118. res, err := readMsg(sc.conn)
  119. if err != nil {
  120. return nil, err
  121. }
  122. return res.(*PubKeyMsg).PubKey, nil
  123. }
  124. // SignVote implements PrivValidator.
  125. func (sc *SocketPV) SignVote(chainID string, vote *types.Vote) error {
  126. err := writeMsg(sc.conn, &SignVoteRequest{Vote: vote})
  127. if err != nil {
  128. return err
  129. }
  130. res, err := readMsg(sc.conn)
  131. if err != nil {
  132. return err
  133. }
  134. resp, ok := res.(*SignedVoteResponse)
  135. if !ok {
  136. return ErrUnexpectedResponse
  137. }
  138. if resp.Error != nil {
  139. return fmt.Errorf("remote error occurred: code: %v, description: %s",
  140. resp.Error.Code,
  141. resp.Error.Description)
  142. }
  143. *vote = *resp.Vote
  144. return nil
  145. }
  146. // SignProposal implements PrivValidator.
  147. func (sc *SocketPV) SignProposal(
  148. chainID string,
  149. proposal *types.Proposal,
  150. ) error {
  151. err := writeMsg(sc.conn, &SignProposalRequest{Proposal: proposal})
  152. if err != nil {
  153. return err
  154. }
  155. res, err := readMsg(sc.conn)
  156. if err != nil {
  157. return err
  158. }
  159. resp, ok := res.(*SignedProposalResponse)
  160. if !ok {
  161. return ErrUnexpectedResponse
  162. }
  163. if resp.Error != nil {
  164. return fmt.Errorf("remote error occurred: code: %v, description: %s",
  165. resp.Error.Code,
  166. resp.Error.Description)
  167. }
  168. *proposal = *resp.Proposal
  169. return nil
  170. }
  171. // SignHeartbeat implements PrivValidator.
  172. func (sc *SocketPV) SignHeartbeat(
  173. chainID string,
  174. heartbeat *types.Heartbeat,
  175. ) error {
  176. err := writeMsg(sc.conn, &SignHeartbeatRequest{Heartbeat: heartbeat})
  177. if err != nil {
  178. return err
  179. }
  180. res, err := readMsg(sc.conn)
  181. if err != nil {
  182. return err
  183. }
  184. resp, ok := res.(*SignedHeartbeatResponse)
  185. if !ok {
  186. return ErrUnexpectedResponse
  187. }
  188. if resp.Error != nil {
  189. return fmt.Errorf("remote error occurred: code: %v, description: %s",
  190. resp.Error.Code,
  191. resp.Error.Description)
  192. }
  193. *heartbeat = *resp.Heartbeat
  194. return nil
  195. }
  196. // OnStart implements cmn.Service.
  197. func (sc *SocketPV) OnStart() error {
  198. if err := sc.listen(); err != nil {
  199. err = cmn.ErrorWrap(err, "failed to listen")
  200. sc.Logger.Error(
  201. "OnStart",
  202. "err", err,
  203. )
  204. return err
  205. }
  206. conn, err := sc.waitConnection()
  207. if err != nil {
  208. err = cmn.ErrorWrap(err, "failed to accept connection")
  209. sc.Logger.Error(
  210. "OnStart",
  211. "err", err,
  212. )
  213. return err
  214. }
  215. sc.conn = conn
  216. return nil
  217. }
  218. // OnStop implements cmn.Service.
  219. func (sc *SocketPV) OnStop() {
  220. if sc.conn != nil {
  221. if err := sc.conn.Close(); err != nil {
  222. err = cmn.ErrorWrap(err, "failed to close connection")
  223. sc.Logger.Error(
  224. "OnStop",
  225. "err", err,
  226. )
  227. }
  228. }
  229. if sc.listener != nil {
  230. if err := sc.listener.Close(); err != nil {
  231. err = cmn.ErrorWrap(err, "failed to close listener")
  232. sc.Logger.Error(
  233. "OnStop",
  234. "err", err,
  235. )
  236. }
  237. }
  238. }
  239. func (sc *SocketPV) acceptConnection() (net.Conn, error) {
  240. conn, err := sc.listener.Accept()
  241. if err != nil {
  242. if !sc.IsRunning() {
  243. return nil, nil // Ignore error from listener closing.
  244. }
  245. return nil, err
  246. }
  247. conn, err = p2pconn.MakeSecretConnection(conn, sc.privKey)
  248. if err != nil {
  249. return nil, err
  250. }
  251. return conn, nil
  252. }
  253. func (sc *SocketPV) listen() error {
  254. ln, err := net.Listen(cmn.ProtocolAndAddress(sc.addr))
  255. if err != nil {
  256. return err
  257. }
  258. sc.listener = newTCPTimeoutListener(
  259. ln,
  260. sc.acceptDeadline,
  261. sc.connDeadline,
  262. sc.connHeartbeat,
  263. )
  264. return nil
  265. }
  266. // waitConnection uses the configured wait timeout to error if no external
  267. // process connects in the time period.
  268. func (sc *SocketPV) waitConnection() (net.Conn, error) {
  269. var (
  270. connc = make(chan net.Conn, 1)
  271. errc = make(chan error, 1)
  272. )
  273. go func(connc chan<- net.Conn, errc chan<- error) {
  274. conn, err := sc.acceptConnection()
  275. if err != nil {
  276. errc <- err
  277. return
  278. }
  279. connc <- conn
  280. }(connc, errc)
  281. select {
  282. case conn := <-connc:
  283. return conn, nil
  284. case err := <-errc:
  285. if _, ok := err.(timeoutError); ok {
  286. return nil, cmn.ErrorWrap(ErrConnWaitTimeout, err.Error())
  287. }
  288. return nil, err
  289. case <-time.After(sc.connWaitTimeout):
  290. return nil, ErrConnWaitTimeout
  291. }
  292. }
  293. //---------------------------------------------------------
  294. // RemoteSignerOption sets an optional parameter on the RemoteSigner.
  295. type RemoteSignerOption func(*RemoteSigner)
  296. // RemoteSignerConnDeadline sets the read and write deadline for connections
  297. // from external signing processes.
  298. func RemoteSignerConnDeadline(deadline time.Duration) RemoteSignerOption {
  299. return func(ss *RemoteSigner) { ss.connDeadline = deadline }
  300. }
  301. // RemoteSignerConnRetries sets the amount of attempted retries to connect.
  302. func RemoteSignerConnRetries(retries int) RemoteSignerOption {
  303. return func(ss *RemoteSigner) { ss.connRetries = retries }
  304. }
  305. // RemoteSigner implements PrivValidator by dialing to a socket.
  306. type RemoteSigner struct {
  307. cmn.BaseService
  308. addr string
  309. chainID string
  310. connDeadline time.Duration
  311. connRetries int
  312. privKey ed25519.PrivKeyEd25519
  313. privVal types.PrivValidator
  314. conn net.Conn
  315. }
  316. // NewRemoteSigner returns an instance of RemoteSigner.
  317. func NewRemoteSigner(
  318. logger log.Logger,
  319. chainID, socketAddr string,
  320. privVal types.PrivValidator,
  321. privKey ed25519.PrivKeyEd25519,
  322. ) *RemoteSigner {
  323. rs := &RemoteSigner{
  324. addr: socketAddr,
  325. chainID: chainID,
  326. connDeadline: time.Second * defaultConnDeadlineSeconds,
  327. connRetries: defaultDialRetries,
  328. privKey: privKey,
  329. privVal: privVal,
  330. }
  331. rs.BaseService = *cmn.NewBaseService(logger, "RemoteSigner", rs)
  332. return rs
  333. }
  334. // OnStart implements cmn.Service.
  335. func (rs *RemoteSigner) OnStart() error {
  336. conn, err := rs.connect()
  337. if err != nil {
  338. err = cmn.ErrorWrap(err, "connect")
  339. rs.Logger.Error("OnStart", "err", err)
  340. return err
  341. }
  342. go rs.handleConnection(conn)
  343. return nil
  344. }
  345. // OnStop implements cmn.Service.
  346. func (rs *RemoteSigner) OnStop() {
  347. if rs.conn == nil {
  348. return
  349. }
  350. if err := rs.conn.Close(); err != nil {
  351. rs.Logger.Error("OnStop", "err", cmn.ErrorWrap(err, "closing listener failed"))
  352. }
  353. }
  354. func (rs *RemoteSigner) connect() (net.Conn, error) {
  355. for retries := rs.connRetries; retries > 0; retries-- {
  356. // Don't sleep if it is the first retry.
  357. if retries != rs.connRetries {
  358. time.Sleep(rs.connDeadline)
  359. }
  360. conn, err := cmn.Connect(rs.addr)
  361. if err != nil {
  362. err = cmn.ErrorWrap(err, "connection failed")
  363. rs.Logger.Error(
  364. "connect",
  365. "addr", rs.addr,
  366. "err", err,
  367. )
  368. continue
  369. }
  370. if err := conn.SetDeadline(time.Now().Add(connDeadline)); err != nil {
  371. err = cmn.ErrorWrap(err, "setting connection timeout failed")
  372. rs.Logger.Error(
  373. "connect",
  374. "err", err,
  375. )
  376. continue
  377. }
  378. conn, err = p2pconn.MakeSecretConnection(conn, rs.privKey)
  379. if err != nil {
  380. err = cmn.ErrorWrap(err, "encrypting connection failed")
  381. rs.Logger.Error(
  382. "connect",
  383. "err", err,
  384. )
  385. continue
  386. }
  387. return conn, nil
  388. }
  389. return nil, ErrDialRetryMax
  390. }
  391. func (rs *RemoteSigner) handleConnection(conn net.Conn) {
  392. for {
  393. if !rs.IsRunning() {
  394. return // Ignore error from listener closing.
  395. }
  396. req, err := readMsg(conn)
  397. if err != nil {
  398. if err != io.EOF {
  399. rs.Logger.Error("handleConnection", "err", err)
  400. }
  401. return
  402. }
  403. var res SocketPVMsg
  404. switch r := req.(type) {
  405. case *PubKeyMsg:
  406. var p crypto.PubKey
  407. p = rs.privVal.GetPubKey()
  408. res = &PubKeyMsg{p}
  409. case *SignVoteRequest:
  410. err = rs.privVal.SignVote(rs.chainID, r.Vote)
  411. if err != nil {
  412. res = &SignedVoteResponse{nil, &RemoteSignerError{0, err.Error()}}
  413. } else {
  414. res = &SignedVoteResponse{r.Vote, nil}
  415. }
  416. case *SignProposalRequest:
  417. err = rs.privVal.SignProposal(rs.chainID, r.Proposal)
  418. if err != nil {
  419. res = &SignedProposalResponse{nil, &RemoteSignerError{0, err.Error()}}
  420. } else {
  421. res = &SignedProposalResponse{r.Proposal, nil}
  422. }
  423. case *SignHeartbeatRequest:
  424. err = rs.privVal.SignHeartbeat(rs.chainID, r.Heartbeat)
  425. if err != nil {
  426. res = &SignedHeartbeatResponse{nil, &RemoteSignerError{0, err.Error()}}
  427. } else {
  428. res = &SignedHeartbeatResponse{r.Heartbeat, nil}
  429. }
  430. default:
  431. err = fmt.Errorf("unknown msg: %v", r)
  432. }
  433. if err != nil {
  434. // only log the error; we'll reply with an error in res
  435. rs.Logger.Error("handleConnection", "err", err)
  436. }
  437. err = writeMsg(conn, res)
  438. if err != nil {
  439. rs.Logger.Error("handleConnection", "err", err)
  440. return
  441. }
  442. }
  443. }
  444. //---------------------------------------------------------
  445. // SocketPVMsg is sent between RemoteSigner and SocketPV.
  446. type SocketPVMsg interface{}
  447. func RegisterSocketPVMsg(cdc *amino.Codec) {
  448. cdc.RegisterInterface((*SocketPVMsg)(nil), nil)
  449. cdc.RegisterConcrete(&PubKeyMsg{}, "tendermint/socketpv/PubKeyMsg", nil)
  450. cdc.RegisterConcrete(&SignVoteRequest{}, "tendermint/socketpv/SignVoteRequest", nil)
  451. cdc.RegisterConcrete(&SignedVoteResponse{}, "tendermint/socketpv/SignedVoteResponse", nil)
  452. cdc.RegisterConcrete(&SignProposalRequest{}, "tendermint/socketpv/SignProposalRequest", nil)
  453. cdc.RegisterConcrete(&SignedProposalResponse{}, "tendermint/socketpv/SignedProposalResponse", nil)
  454. cdc.RegisterConcrete(&SignHeartbeatRequest{}, "tendermint/socketpv/SignHeartbeatRequest", nil)
  455. cdc.RegisterConcrete(&SignedHeartbeatResponse{}, "tendermint/socketpv/SignedHeartbeatResponse", nil)
  456. }
  457. // PubKeyMsg is a PrivValidatorSocket message containing the public key.
  458. type PubKeyMsg struct {
  459. PubKey crypto.PubKey
  460. }
  461. // SignVoteRequest is a PrivValidatorSocket message containing a vote.
  462. type SignVoteRequest struct {
  463. Vote *types.Vote
  464. }
  465. // SignedVoteResponse is a PrivValidatorSocket message containing a signed vote along with a potenial error message.
  466. type SignedVoteResponse struct {
  467. Vote *types.Vote
  468. Error *RemoteSignerError
  469. }
  470. // SignProposalRequest is a PrivValidatorSocket message containing a Proposal.
  471. type SignProposalRequest struct {
  472. Proposal *types.Proposal
  473. }
  474. type SignedProposalResponse struct {
  475. Proposal *types.Proposal
  476. Error *RemoteSignerError
  477. }
  478. // SignHeartbeatRequest is a PrivValidatorSocket message containing a Heartbeat.
  479. type SignHeartbeatRequest struct {
  480. Heartbeat *types.Heartbeat
  481. }
  482. type SignedHeartbeatResponse struct {
  483. Heartbeat *types.Heartbeat
  484. Error *RemoteSignerError
  485. }
  486. // RemoteSignerError allows (remote) validators to include meaningful error descriptions in their reply.
  487. type RemoteSignerError struct {
  488. // TODO(ismail): create an enum of known errors
  489. Code int
  490. Description string
  491. }
  492. func readMsg(r io.Reader) (msg SocketPVMsg, err error) {
  493. const maxSocketPVMsgSize = 1024 * 10
  494. _, err = cdc.UnmarshalBinaryReader(r, &msg, maxSocketPVMsgSize)
  495. if _, ok := err.(timeoutError); ok {
  496. err = cmn.ErrorWrap(ErrConnTimeout, err.Error())
  497. }
  498. return
  499. }
  500. func writeMsg(w io.Writer, msg interface{}) (err error) {
  501. _, err = cdc.MarshalBinaryWriter(w, msg)
  502. if _, ok := err.(timeoutError); ok {
  503. err = cmn.ErrorWrap(ErrConnTimeout, err.Error())
  504. }
  505. return
  506. }