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.

160 lines
3.4 KiB

  1. package privval
  2. import (
  3. "io"
  4. "net"
  5. "time"
  6. "github.com/tendermint/tendermint/crypto/ed25519"
  7. cmn "github.com/tendermint/tendermint/libs/common"
  8. "github.com/tendermint/tendermint/libs/log"
  9. p2pconn "github.com/tendermint/tendermint/p2p/conn"
  10. "github.com/tendermint/tendermint/types"
  11. )
  12. // RemoteSignerOption sets an optional parameter on the RemoteSigner.
  13. type RemoteSignerOption func(*RemoteSigner)
  14. // RemoteSignerConnDeadline sets the read and write deadline for connections
  15. // from external signing processes.
  16. func RemoteSignerConnDeadline(deadline time.Duration) RemoteSignerOption {
  17. return func(ss *RemoteSigner) { ss.connDeadline = deadline }
  18. }
  19. // RemoteSignerConnRetries sets the amount of attempted retries to connect.
  20. func RemoteSignerConnRetries(retries int) RemoteSignerOption {
  21. return func(ss *RemoteSigner) { ss.connRetries = retries }
  22. }
  23. // RemoteSigner implements PrivValidator by dialing to a socket.
  24. type RemoteSigner struct {
  25. cmn.BaseService
  26. addr string
  27. chainID string
  28. connDeadline time.Duration
  29. connRetries int
  30. privKey ed25519.PrivKeyEd25519
  31. privVal types.PrivValidator
  32. conn net.Conn
  33. }
  34. // NewRemoteSigner returns an instance of RemoteSigner.
  35. func NewRemoteSigner(
  36. logger log.Logger,
  37. chainID, socketAddr string,
  38. privVal types.PrivValidator,
  39. privKey ed25519.PrivKeyEd25519,
  40. ) *RemoteSigner {
  41. rs := &RemoteSigner{
  42. addr: socketAddr,
  43. chainID: chainID,
  44. connDeadline: time.Second * defaultConnDeadlineSeconds,
  45. connRetries: defaultDialRetries,
  46. privKey: privKey,
  47. privVal: privVal,
  48. }
  49. rs.BaseService = *cmn.NewBaseService(logger, "RemoteSigner", rs)
  50. return rs
  51. }
  52. // OnStart implements cmn.Service.
  53. func (rs *RemoteSigner) OnStart() error {
  54. conn, err := rs.connect()
  55. if err != nil {
  56. rs.Logger.Error("OnStart", "err", err)
  57. return err
  58. }
  59. go rs.handleConnection(conn)
  60. return nil
  61. }
  62. // OnStop implements cmn.Service.
  63. func (rs *RemoteSigner) OnStop() {
  64. if rs.conn == nil {
  65. return
  66. }
  67. if err := rs.conn.Close(); err != nil {
  68. rs.Logger.Error("OnStop", "err", cmn.ErrorWrap(err, "closing listener failed"))
  69. }
  70. }
  71. func (rs *RemoteSigner) connect() (net.Conn, error) {
  72. for retries := rs.connRetries; retries > 0; retries-- {
  73. // Don't sleep if it is the first retry.
  74. if retries != rs.connRetries {
  75. time.Sleep(rs.connDeadline)
  76. }
  77. conn, err := cmn.Connect(rs.addr)
  78. if err != nil {
  79. rs.Logger.Error(
  80. "connect",
  81. "addr", rs.addr,
  82. "err", err,
  83. )
  84. continue
  85. }
  86. if err := conn.SetDeadline(time.Now().Add(connTimeout)); err != nil {
  87. rs.Logger.Error(
  88. "connect",
  89. "err", err,
  90. )
  91. continue
  92. }
  93. conn, err = p2pconn.MakeSecretConnection(conn, rs.privKey)
  94. if err != nil {
  95. rs.Logger.Error(
  96. "connect",
  97. "err", err,
  98. )
  99. continue
  100. }
  101. return conn, nil
  102. }
  103. return nil, ErrDialRetryMax
  104. }
  105. func (rs *RemoteSigner) handleConnection(conn net.Conn) {
  106. for {
  107. if !rs.IsRunning() {
  108. return // Ignore error from listener closing.
  109. }
  110. // Reset the connection deadline
  111. conn.SetDeadline(time.Now().Add(rs.connDeadline))
  112. req, err := readMsg(conn)
  113. if err != nil {
  114. if err != io.EOF {
  115. rs.Logger.Error("handleConnection", "err", err)
  116. }
  117. return
  118. }
  119. res, err := handleRequest(req, rs.chainID, rs.privVal)
  120. if err != nil {
  121. // only log the error; we'll reply with an error in res
  122. rs.Logger.Error("handleConnection", "err", err)
  123. }
  124. err = writeMsg(conn, res)
  125. if err != nil {
  126. rs.Logger.Error("handleConnection", "err", err)
  127. return
  128. }
  129. }
  130. }