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.

397 lines
8.9 KiB

  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. func TestSocketPVAddress(t *testing.T) {
  16. var (
  17. chainID = cmn.RandStr(12)
  18. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
  19. )
  20. defer sc.Stop()
  21. defer rs.Stop()
  22. serverAddr := rs.privVal.GetPubKey().Address()
  23. clientAddr := sc.GetPubKey().Address()
  24. assert.Equal(t, serverAddr, clientAddr)
  25. }
  26. func TestSocketPVPubKey(t *testing.T) {
  27. var (
  28. chainID = cmn.RandStr(12)
  29. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
  30. )
  31. defer sc.Stop()
  32. defer rs.Stop()
  33. clientKey, err := sc.getPubKey()
  34. require.NoError(t, err)
  35. privvalPubKey := rs.privVal.GetPubKey()
  36. assert.Equal(t, privvalPubKey, clientKey)
  37. }
  38. func TestSocketPVProposal(t *testing.T) {
  39. var (
  40. chainID = cmn.RandStr(12)
  41. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
  42. ts = time.Now()
  43. privProposal = &types.Proposal{Timestamp: ts}
  44. clientProposal = &types.Proposal{Timestamp: ts}
  45. )
  46. defer sc.Stop()
  47. defer rs.Stop()
  48. require.NoError(t, rs.privVal.SignProposal(chainID, privProposal))
  49. require.NoError(t, sc.SignProposal(chainID, clientProposal))
  50. assert.Equal(t, privProposal.Signature, clientProposal.Signature)
  51. }
  52. func TestSocketPVVote(t *testing.T) {
  53. var (
  54. chainID = cmn.RandStr(12)
  55. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
  56. ts = time.Now()
  57. vType = types.PrecommitType
  58. want = &types.Vote{Timestamp: ts, Type: vType}
  59. have = &types.Vote{Timestamp: ts, Type: vType}
  60. )
  61. defer sc.Stop()
  62. defer rs.Stop()
  63. require.NoError(t, rs.privVal.SignVote(chainID, want))
  64. require.NoError(t, sc.SignVote(chainID, have))
  65. assert.Equal(t, want.Signature, have.Signature)
  66. }
  67. func TestSocketPVVoteResetDeadline(t *testing.T) {
  68. var (
  69. chainID = cmn.RandStr(12)
  70. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
  71. ts = time.Now()
  72. vType = types.PrecommitType
  73. want = &types.Vote{Timestamp: ts, Type: vType}
  74. have = &types.Vote{Timestamp: ts, Type: vType}
  75. )
  76. defer sc.Stop()
  77. defer rs.Stop()
  78. time.Sleep(3 * time.Millisecond)
  79. require.NoError(t, rs.privVal.SignVote(chainID, want))
  80. require.NoError(t, sc.SignVote(chainID, have))
  81. assert.Equal(t, want.Signature, have.Signature)
  82. // This would exceed the deadline if it was not extended by the previous message
  83. time.Sleep(3 * time.Millisecond)
  84. require.NoError(t, rs.privVal.SignVote(chainID, want))
  85. require.NoError(t, sc.SignVote(chainID, have))
  86. assert.Equal(t, want.Signature, have.Signature)
  87. }
  88. func TestSocketPVVoteKeepalive(t *testing.T) {
  89. var (
  90. chainID = cmn.RandStr(12)
  91. sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
  92. ts = time.Now()
  93. vType = types.PrecommitType
  94. want = &types.Vote{Timestamp: ts, Type: vType}
  95. have = &types.Vote{Timestamp: ts, Type: vType}
  96. )
  97. defer sc.Stop()
  98. defer rs.Stop()
  99. time.Sleep(10 * time.Millisecond)
  100. require.NoError(t, rs.privVal.SignVote(chainID, want))
  101. require.NoError(t, sc.SignVote(chainID, have))
  102. assert.Equal(t, want.Signature, have.Signature)
  103. }
  104. func TestSocketPVDeadline(t *testing.T) {
  105. var (
  106. addr = testFreeAddr(t)
  107. listenc = make(chan struct{})
  108. sc = NewTCPVal(
  109. log.TestingLogger(),
  110. addr,
  111. ed25519.GenPrivKey(),
  112. )
  113. )
  114. TCPValConnTimeout(100 * time.Millisecond)(sc)
  115. go func(sc *TCPVal) {
  116. defer close(listenc)
  117. assert.Equal(t, sc.Start().(cmn.Error).Data(), ErrConnTimeout)
  118. assert.False(t, sc.IsRunning())
  119. }(sc)
  120. for {
  121. conn, err := cmn.Connect(addr)
  122. if err != nil {
  123. continue
  124. }
  125. _, err = p2pconn.MakeSecretConnection(
  126. conn,
  127. ed25519.GenPrivKey(),
  128. )
  129. if err == nil {
  130. break
  131. }
  132. }
  133. <-listenc
  134. }
  135. func TestRemoteSignerRetry(t *testing.T) {
  136. var (
  137. attemptc = make(chan int)
  138. retries = 2
  139. )
  140. ln, err := net.Listen("tcp", "127.0.0.1:0")
  141. require.NoError(t, err)
  142. go func(ln net.Listener, attemptc chan<- int) {
  143. attempts := 0
  144. for {
  145. conn, err := ln.Accept()
  146. require.NoError(t, err)
  147. err = conn.Close()
  148. require.NoError(t, err)
  149. attempts++
  150. if attempts == retries {
  151. attemptc <- attempts
  152. break
  153. }
  154. }
  155. }(ln, attemptc)
  156. rs := NewRemoteSigner(
  157. log.TestingLogger(),
  158. cmn.RandStr(12),
  159. ln.Addr().String(),
  160. types.NewMockPV(),
  161. ed25519.GenPrivKey(),
  162. )
  163. defer rs.Stop()
  164. RemoteSignerConnDeadline(time.Millisecond)(rs)
  165. RemoteSignerConnRetries(retries)(rs)
  166. assert.Equal(t, rs.Start(), ErrDialRetryMax)
  167. select {
  168. case attempts := <-attemptc:
  169. assert.Equal(t, retries, attempts)
  170. case <-time.After(100 * time.Millisecond):
  171. t.Error("expected remote to observe connection attempts")
  172. }
  173. }
  174. func TestRemoteSignVoteErrors(t *testing.T) {
  175. var (
  176. chainID = cmn.RandStr(12)
  177. sc, rs = testSetupSocketPair(t, chainID, types.NewErroringMockPV())
  178. ts = time.Now()
  179. vType = types.PrecommitType
  180. vote = &types.Vote{Timestamp: ts, Type: vType}
  181. )
  182. defer sc.Stop()
  183. defer rs.Stop()
  184. err := writeMsg(sc.conn, &SignVoteRequest{Vote: vote})
  185. require.NoError(t, err)
  186. res, err := readMsg(sc.conn)
  187. require.NoError(t, err)
  188. resp := *res.(*SignedVoteResponse)
  189. require.NotNil(t, resp.Error)
  190. require.Equal(t, resp.Error.Description, types.ErroringMockPVErr.Error())
  191. err = rs.privVal.SignVote(chainID, vote)
  192. require.Error(t, err)
  193. err = sc.SignVote(chainID, vote)
  194. require.Error(t, err)
  195. }
  196. func TestRemoteSignProposalErrors(t *testing.T) {
  197. var (
  198. chainID = cmn.RandStr(12)
  199. sc, rs = testSetupSocketPair(t, chainID, types.NewErroringMockPV())
  200. ts = time.Now()
  201. proposal = &types.Proposal{Timestamp: ts}
  202. )
  203. defer sc.Stop()
  204. defer rs.Stop()
  205. err := writeMsg(sc.conn, &SignProposalRequest{Proposal: proposal})
  206. require.NoError(t, err)
  207. res, err := readMsg(sc.conn)
  208. require.NoError(t, err)
  209. resp := *res.(*SignedProposalResponse)
  210. require.NotNil(t, resp.Error)
  211. require.Equal(t, resp.Error.Description, types.ErroringMockPVErr.Error())
  212. err = rs.privVal.SignProposal(chainID, proposal)
  213. require.Error(t, err)
  214. err = sc.SignProposal(chainID, proposal)
  215. require.Error(t, err)
  216. }
  217. func TestErrUnexpectedResponse(t *testing.T) {
  218. var (
  219. addr = testFreeAddr(t)
  220. logger = log.TestingLogger()
  221. chainID = cmn.RandStr(12)
  222. readyc = make(chan struct{})
  223. errc = make(chan error, 1)
  224. rs = NewRemoteSigner(
  225. logger,
  226. chainID,
  227. addr,
  228. types.NewMockPV(),
  229. ed25519.GenPrivKey(),
  230. )
  231. sc = NewTCPVal(
  232. logger,
  233. addr,
  234. ed25519.GenPrivKey(),
  235. )
  236. )
  237. testStartSocketPV(t, readyc, sc)
  238. defer sc.Stop()
  239. RemoteSignerConnDeadline(time.Millisecond)(rs)
  240. RemoteSignerConnRetries(100)(rs)
  241. // we do not want to Start() the remote signer here and instead use the connection to
  242. // reply with intentionally wrong replies below:
  243. rsConn, err := rs.connect()
  244. defer rsConn.Close()
  245. require.NoError(t, err)
  246. require.NotNil(t, rsConn)
  247. // send over public key to get the remote signer running:
  248. go testReadWriteResponse(t, &PubKeyResponse{}, rsConn)
  249. <-readyc
  250. // Proposal:
  251. go func(errc chan error) {
  252. errc <- sc.SignProposal(chainID, &types.Proposal{})
  253. }(errc)
  254. // read request and write wrong response:
  255. go testReadWriteResponse(t, &SignedVoteResponse{}, rsConn)
  256. err = <-errc
  257. require.Error(t, err)
  258. require.Equal(t, err, ErrUnexpectedResponse)
  259. // Vote:
  260. go func(errc chan error) {
  261. errc <- sc.SignVote(chainID, &types.Vote{})
  262. }(errc)
  263. // read request and write wrong response:
  264. go testReadWriteResponse(t, &SignedProposalResponse{}, rsConn)
  265. err = <-errc
  266. require.Error(t, err)
  267. require.Equal(t, err, ErrUnexpectedResponse)
  268. }
  269. func testSetupSocketPair(
  270. t *testing.T,
  271. chainID string,
  272. privValidator types.PrivValidator,
  273. ) (*TCPVal, *RemoteSigner) {
  274. var (
  275. addr = testFreeAddr(t)
  276. logger = log.TestingLogger()
  277. privVal = privValidator
  278. readyc = make(chan struct{})
  279. rs = NewRemoteSigner(
  280. logger,
  281. chainID,
  282. addr,
  283. privVal,
  284. ed25519.GenPrivKey(),
  285. )
  286. sc = NewTCPVal(
  287. logger,
  288. addr,
  289. ed25519.GenPrivKey(),
  290. )
  291. )
  292. TCPValConnTimeout(5 * time.Millisecond)(sc)
  293. TCPValHeartbeat(2 * time.Millisecond)(sc)
  294. RemoteSignerConnDeadline(5 * time.Millisecond)(rs)
  295. RemoteSignerConnRetries(1e6)(rs)
  296. testStartSocketPV(t, readyc, sc)
  297. require.NoError(t, rs.Start())
  298. assert.True(t, rs.IsRunning())
  299. <-readyc
  300. return sc, rs
  301. }
  302. func testReadWriteResponse(t *testing.T, resp RemoteSignerMsg, rsConn net.Conn) {
  303. _, err := readMsg(rsConn)
  304. require.NoError(t, err)
  305. err = writeMsg(rsConn, resp)
  306. require.NoError(t, err)
  307. }
  308. func testStartSocketPV(t *testing.T, readyc chan struct{}, sc *TCPVal) {
  309. go func(sc *TCPVal) {
  310. require.NoError(t, sc.Start())
  311. assert.True(t, sc.IsRunning())
  312. readyc <- struct{}{}
  313. }(sc)
  314. }
  315. // testFreeAddr claims a free port so we don't block on listener being ready.
  316. func testFreeAddr(t *testing.T) string {
  317. ln, err := net.Listen("tcp", "127.0.0.1:0")
  318. require.NoError(t, err)
  319. defer ln.Close()
  320. return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
  321. }