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.

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