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.

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