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.

466 lines
12 KiB

Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
  1. package privval
  2. import (
  3. "fmt"
  4. "net"
  5. "testing"
  6. "time"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. "github.com/tendermint/tendermint/crypto/ed25519"
  10. cmn "github.com/tendermint/tendermint/libs/common"
  11. "github.com/tendermint/tendermint/libs/log"
  12. p2pconn "github.com/tendermint/tendermint/p2p/conn"
  13. "github.com/tendermint/tendermint/types"
  14. )
  15. var (
  16. testAcceptDeadline = defaultAcceptDeadlineSeconds * time.Second
  17. testConnDeadline = 100 * time.Millisecond
  18. testConnDeadline2o3 = 66 * time.Millisecond // 2/3 of the other one
  19. testHeartbeatTimeout = 10 * time.Millisecond
  20. testHeartbeatTimeout3o2 = 6 * time.Millisecond // 3/2 of the other one
  21. )
  22. type socketTestCase struct {
  23. addr string
  24. dialer Dialer
  25. }
  26. func socketTestCases(t *testing.T) []socketTestCase {
  27. tcpAddr := fmt.Sprintf("tcp://%s", testFreeTCPAddr(t))
  28. unixFilePath, err := testUnixAddr()
  29. require.NoError(t, err)
  30. unixAddr := fmt.Sprintf("unix://%s", unixFilePath)
  31. return []socketTestCase{
  32. socketTestCase{
  33. addr: tcpAddr,
  34. dialer: DialTCPFn(tcpAddr, testConnDeadline, ed25519.GenPrivKey()),
  35. },
  36. socketTestCase{
  37. addr: unixAddr,
  38. dialer: DialUnixFn(unixFilePath),
  39. },
  40. }
  41. }
  42. func TestSocketPVAddress(t *testing.T) {
  43. for _, tc := range socketTestCases(t) {
  44. // Execute the test within a closure to ensure the deferred statements
  45. // are called between each for loop iteration, for isolated test cases.
  46. func() {
  47. var (
  48. chainID = cmn.RandStr(12)
  49. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV(), tc.addr, tc.dialer)
  50. )
  51. defer sc.Stop()
  52. defer rs.Stop()
  53. serverAddr := rs.privVal.GetPubKey().Address()
  54. clientAddr := sc.GetPubKey().Address()
  55. assert.Equal(t, serverAddr, clientAddr)
  56. }()
  57. }
  58. }
  59. func TestSocketPVPubKey(t *testing.T) {
  60. for _, tc := range socketTestCases(t) {
  61. func() {
  62. var (
  63. chainID = cmn.RandStr(12)
  64. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV(), tc.addr, tc.dialer)
  65. )
  66. defer sc.Stop()
  67. defer rs.Stop()
  68. clientKey := sc.GetPubKey()
  69. privvalPubKey := rs.privVal.GetPubKey()
  70. assert.Equal(t, privvalPubKey, clientKey)
  71. }()
  72. }
  73. }
  74. func TestSocketPVProposal(t *testing.T) {
  75. for _, tc := range socketTestCases(t) {
  76. func() {
  77. var (
  78. chainID = cmn.RandStr(12)
  79. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV(), tc.addr, tc.dialer)
  80. ts = time.Now()
  81. privProposal = &types.Proposal{Timestamp: ts}
  82. clientProposal = &types.Proposal{Timestamp: ts}
  83. )
  84. defer sc.Stop()
  85. defer rs.Stop()
  86. require.NoError(t, rs.privVal.SignProposal(chainID, privProposal))
  87. require.NoError(t, sc.SignProposal(chainID, clientProposal))
  88. assert.Equal(t, privProposal.Signature, clientProposal.Signature)
  89. }()
  90. }
  91. }
  92. func TestSocketPVVote(t *testing.T) {
  93. for _, tc := range socketTestCases(t) {
  94. func() {
  95. var (
  96. chainID = cmn.RandStr(12)
  97. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV(), tc.addr, tc.dialer)
  98. ts = time.Now()
  99. vType = types.PrecommitType
  100. want = &types.Vote{Timestamp: ts, Type: vType}
  101. have = &types.Vote{Timestamp: ts, Type: vType}
  102. )
  103. defer sc.Stop()
  104. defer rs.Stop()
  105. require.NoError(t, rs.privVal.SignVote(chainID, want))
  106. require.NoError(t, sc.SignVote(chainID, have))
  107. assert.Equal(t, want.Signature, have.Signature)
  108. }()
  109. }
  110. }
  111. func TestSocketPVVoteResetDeadline(t *testing.T) {
  112. for _, tc := range socketTestCases(t) {
  113. func() {
  114. var (
  115. chainID = cmn.RandStr(12)
  116. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV(), tc.addr, tc.dialer)
  117. ts = time.Now()
  118. vType = types.PrecommitType
  119. want = &types.Vote{Timestamp: ts, Type: vType}
  120. have = &types.Vote{Timestamp: ts, Type: vType}
  121. )
  122. defer sc.Stop()
  123. defer rs.Stop()
  124. time.Sleep(testConnDeadline2o3)
  125. require.NoError(t, rs.privVal.SignVote(chainID, want))
  126. require.NoError(t, sc.SignVote(chainID, have))
  127. assert.Equal(t, want.Signature, have.Signature)
  128. // This would exceed the deadline if it was not extended by the previous message
  129. time.Sleep(testConnDeadline2o3)
  130. require.NoError(t, rs.privVal.SignVote(chainID, want))
  131. require.NoError(t, sc.SignVote(chainID, have))
  132. assert.Equal(t, want.Signature, have.Signature)
  133. }()
  134. }
  135. }
  136. func TestSocketPVVoteKeepalive(t *testing.T) {
  137. for _, tc := range socketTestCases(t) {
  138. func() {
  139. var (
  140. chainID = cmn.RandStr(12)
  141. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV(), tc.addr, tc.dialer)
  142. ts = time.Now()
  143. vType = types.PrecommitType
  144. want = &types.Vote{Timestamp: ts, Type: vType}
  145. have = &types.Vote{Timestamp: ts, Type: vType}
  146. )
  147. defer sc.Stop()
  148. defer rs.Stop()
  149. time.Sleep(testConnDeadline * 2)
  150. require.NoError(t, rs.privVal.SignVote(chainID, want))
  151. require.NoError(t, sc.SignVote(chainID, have))
  152. assert.Equal(t, want.Signature, have.Signature)
  153. }()
  154. }
  155. }
  156. // TestSocketPVDeadlineTCPOnly is not relevant to Unix domain sockets, since the
  157. // OS knows instantaneously the state of both sides of the connection.
  158. func TestSocketPVDeadlineTCPOnly(t *testing.T) {
  159. var (
  160. addr = testFreeTCPAddr(t)
  161. listenc = make(chan struct{})
  162. thisConnTimeout = 100 * time.Millisecond
  163. sc = newSocketVal(log.TestingLogger(), addr, thisConnTimeout)
  164. )
  165. go func(sc *SocketVal) {
  166. defer close(listenc)
  167. assert.Equal(t, sc.Start().(cmn.Error).Data(), ErrConnTimeout)
  168. assert.False(t, sc.IsRunning())
  169. }(sc)
  170. for {
  171. conn, err := cmn.Connect(addr)
  172. if err != nil {
  173. continue
  174. }
  175. _, err = p2pconn.MakeSecretConnection(
  176. conn,
  177. ed25519.GenPrivKey(),
  178. )
  179. if err == nil {
  180. break
  181. }
  182. }
  183. <-listenc
  184. }
  185. func TestRemoteSignVoteErrors(t *testing.T) {
  186. for _, tc := range socketTestCases(t) {
  187. func() {
  188. var (
  189. chainID = cmn.RandStr(12)
  190. sc, rs = testSetupSocketPair(t, chainID, types.NewErroringMockPV(), tc.addr, tc.dialer)
  191. ts = time.Now()
  192. vType = types.PrecommitType
  193. vote = &types.Vote{Timestamp: ts, Type: vType}
  194. )
  195. defer sc.Stop()
  196. defer rs.Stop()
  197. err := sc.SignVote("", vote)
  198. require.Equal(t, err.(*RemoteSignerError).Description, types.ErroringMockPVErr.Error())
  199. err = rs.privVal.SignVote(chainID, vote)
  200. require.Error(t, err)
  201. err = sc.SignVote(chainID, vote)
  202. require.Error(t, err)
  203. }()
  204. }
  205. }
  206. func TestRemoteSignProposalErrors(t *testing.T) {
  207. for _, tc := range socketTestCases(t) {
  208. func() {
  209. var (
  210. chainID = cmn.RandStr(12)
  211. sc, rs = testSetupSocketPair(t, chainID, types.NewErroringMockPV(), tc.addr, tc.dialer)
  212. ts = time.Now()
  213. proposal = &types.Proposal{Timestamp: ts}
  214. )
  215. defer sc.Stop()
  216. defer rs.Stop()
  217. err := sc.SignProposal("", proposal)
  218. require.Equal(t, err.(*RemoteSignerError).Description, types.ErroringMockPVErr.Error())
  219. err = rs.privVal.SignProposal(chainID, proposal)
  220. require.Error(t, err)
  221. err = sc.SignProposal(chainID, proposal)
  222. require.Error(t, err)
  223. }()
  224. }
  225. }
  226. func TestErrUnexpectedResponse(t *testing.T) {
  227. for _, tc := range socketTestCases(t) {
  228. func() {
  229. var (
  230. logger = log.TestingLogger()
  231. chainID = cmn.RandStr(12)
  232. readyc = make(chan struct{})
  233. errc = make(chan error, 1)
  234. rs = NewRemoteSigner(
  235. logger,
  236. chainID,
  237. types.NewMockPV(),
  238. tc.dialer,
  239. )
  240. sc = newSocketVal(logger, tc.addr, testConnDeadline)
  241. )
  242. testStartSocketPV(t, readyc, sc)
  243. defer sc.Stop()
  244. RemoteSignerConnDeadline(time.Millisecond)(rs)
  245. RemoteSignerConnRetries(100)(rs)
  246. // we do not want to Start() the remote signer here and instead use the connection to
  247. // reply with intentionally wrong replies below:
  248. rsConn, err := rs.connect()
  249. defer rsConn.Close()
  250. require.NoError(t, err)
  251. require.NotNil(t, rsConn)
  252. // send over public key to get the remote signer running:
  253. go testReadWriteResponse(t, &PubKeyResponse{}, rsConn)
  254. <-readyc
  255. // Proposal:
  256. go func(errc chan error) {
  257. errc <- sc.SignProposal(chainID, &types.Proposal{})
  258. }(errc)
  259. // read request and write wrong response:
  260. go testReadWriteResponse(t, &SignedVoteResponse{}, rsConn)
  261. err = <-errc
  262. require.Error(t, err)
  263. require.Equal(t, err, ErrUnexpectedResponse)
  264. // Vote:
  265. go func(errc chan error) {
  266. errc <- sc.SignVote(chainID, &types.Vote{})
  267. }(errc)
  268. // read request and write wrong response:
  269. go testReadWriteResponse(t, &SignedProposalResponse{}, rsConn)
  270. err = <-errc
  271. require.Error(t, err)
  272. require.Equal(t, err, ErrUnexpectedResponse)
  273. }()
  274. }
  275. }
  276. func TestRetryConnToRemoteSigner(t *testing.T) {
  277. for _, tc := range socketTestCases(t) {
  278. func() {
  279. var (
  280. logger = log.TestingLogger()
  281. chainID = cmn.RandStr(12)
  282. readyc = make(chan struct{})
  283. rs = NewRemoteSigner(
  284. logger,
  285. chainID,
  286. types.NewMockPV(),
  287. tc.dialer,
  288. )
  289. thisConnTimeout = testConnDeadline
  290. sc = newSocketVal(logger, tc.addr, thisConnTimeout)
  291. )
  292. // Ping every:
  293. SocketValHeartbeat(testHeartbeatTimeout)(sc)
  294. RemoteSignerConnDeadline(testConnDeadline)(rs)
  295. RemoteSignerConnRetries(10)(rs)
  296. testStartSocketPV(t, readyc, sc)
  297. defer sc.Stop()
  298. require.NoError(t, rs.Start())
  299. assert.True(t, rs.IsRunning())
  300. <-readyc
  301. time.Sleep(testHeartbeatTimeout * 2)
  302. rs.Stop()
  303. rs2 := NewRemoteSigner(
  304. logger,
  305. chainID,
  306. types.NewMockPV(),
  307. tc.dialer,
  308. )
  309. // let some pings pass
  310. time.Sleep(testHeartbeatTimeout3o2)
  311. require.NoError(t, rs2.Start())
  312. assert.True(t, rs2.IsRunning())
  313. defer rs2.Stop()
  314. // give the client some time to re-establish the conn to the remote signer
  315. // should see sth like this in the logs:
  316. //
  317. // E[10016-01-10|17:12:46.128] Ping err="remote signer timed out"
  318. // I[10016-01-10|17:16:42.447] Re-created connection to remote signer impl=SocketVal
  319. time.Sleep(testConnDeadline * 2)
  320. }()
  321. }
  322. }
  323. func newSocketVal(logger log.Logger, addr string, connDeadline time.Duration) *SocketVal {
  324. proto, address := cmn.ProtocolAndAddress(addr)
  325. ln, err := net.Listen(proto, address)
  326. logger.Info("Listening at", "proto", proto, "address", address)
  327. if err != nil {
  328. panic(err)
  329. }
  330. var svln net.Listener
  331. if proto == "unix" {
  332. unixLn := NewUnixListener(ln)
  333. UnixListenerAcceptDeadline(testAcceptDeadline)(unixLn)
  334. UnixListenerConnDeadline(connDeadline)(unixLn)
  335. svln = unixLn
  336. } else {
  337. tcpLn := NewTCPListener(ln, ed25519.GenPrivKey())
  338. TCPListenerAcceptDeadline(testAcceptDeadline)(tcpLn)
  339. TCPListenerConnDeadline(connDeadline)(tcpLn)
  340. svln = tcpLn
  341. }
  342. return NewSocketVal(logger, svln)
  343. }
  344. func testSetupSocketPair(
  345. t *testing.T,
  346. chainID string,
  347. privValidator types.PrivValidator,
  348. addr string,
  349. dialer Dialer,
  350. ) (*SocketVal, *RemoteSigner) {
  351. var (
  352. logger = log.TestingLogger()
  353. privVal = privValidator
  354. readyc = make(chan struct{})
  355. rs = NewRemoteSigner(
  356. logger,
  357. chainID,
  358. privVal,
  359. dialer,
  360. )
  361. thisConnTimeout = testConnDeadline
  362. sc = newSocketVal(logger, addr, thisConnTimeout)
  363. )
  364. SocketValHeartbeat(testHeartbeatTimeout)(sc)
  365. RemoteSignerConnDeadline(testConnDeadline)(rs)
  366. RemoteSignerConnRetries(1e6)(rs)
  367. testStartSocketPV(t, readyc, sc)
  368. require.NoError(t, rs.Start())
  369. assert.True(t, rs.IsRunning())
  370. <-readyc
  371. return sc, rs
  372. }
  373. func testReadWriteResponse(t *testing.T, resp RemoteSignerMsg, rsConn net.Conn) {
  374. _, err := readMsg(rsConn)
  375. require.NoError(t, err)
  376. err = writeMsg(rsConn, resp)
  377. require.NoError(t, err)
  378. }
  379. func testStartSocketPV(t *testing.T, readyc chan struct{}, sc *SocketVal) {
  380. go func(sc *SocketVal) {
  381. require.NoError(t, sc.Start())
  382. assert.True(t, sc.IsRunning())
  383. readyc <- struct{}{}
  384. }(sc)
  385. }
  386. // testFreeTCPAddr claims a free port so we don't block on listener being ready.
  387. func testFreeTCPAddr(t *testing.T) string {
  388. ln, err := net.Listen("tcp", "127.0.0.1:0")
  389. require.NoError(t, err)
  390. defer ln.Close()
  391. return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
  392. }