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.

732 lines
20 KiB

  1. package consensus
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "math"
  6. "testing"
  7. "time"
  8. "github.com/gogo/protobuf/proto"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. "github.com/tendermint/tendermint/crypto/merkle"
  12. "github.com/tendermint/tendermint/crypto/tmhash"
  13. cstypes "github.com/tendermint/tendermint/internal/consensus/types"
  14. "github.com/tendermint/tendermint/internal/test/factory"
  15. "github.com/tendermint/tendermint/libs/bits"
  16. "github.com/tendermint/tendermint/libs/bytes"
  17. tmrand "github.com/tendermint/tendermint/libs/rand"
  18. tmcons "github.com/tendermint/tendermint/proto/tendermint/consensus"
  19. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  20. "github.com/tendermint/tendermint/types"
  21. )
  22. func TestMsgToProto(t *testing.T) {
  23. psh := types.PartSetHeader{
  24. Total: 1,
  25. Hash: tmrand.Bytes(32),
  26. }
  27. pbPsh := psh.ToProto()
  28. bi := types.BlockID{
  29. Hash: tmrand.Bytes(32),
  30. PartSetHeader: psh,
  31. }
  32. pbBi := bi.ToProto()
  33. bits := bits.NewBitArray(1)
  34. pbBits := bits.ToProto()
  35. parts := types.Part{
  36. Index: 1,
  37. Bytes: []byte("test"),
  38. Proof: merkle.Proof{
  39. Total: 1,
  40. Index: 1,
  41. LeafHash: tmrand.Bytes(32),
  42. Aunts: [][]byte{},
  43. },
  44. }
  45. pbParts, err := parts.ToProto()
  46. require.NoError(t, err)
  47. proposal := types.Proposal{
  48. Type: tmproto.ProposalType,
  49. Height: 1,
  50. Round: 1,
  51. POLRound: 1,
  52. BlockID: bi,
  53. Timestamp: time.Now(),
  54. Signature: tmrand.Bytes(20),
  55. }
  56. pbProposal := proposal.ToProto()
  57. pv := types.NewMockPV()
  58. vote, err := factory.MakeVote(pv, factory.DefaultTestChainID,
  59. 0, 1, 0, 2, types.BlockID{}, time.Now())
  60. require.NoError(t, err)
  61. pbVote := vote.ToProto()
  62. testsCases := []struct {
  63. testName string
  64. msg Message
  65. want *tmcons.Message
  66. wantErr bool
  67. }{
  68. {"successful NewRoundStepMessage", &NewRoundStepMessage{
  69. Height: 2,
  70. Round: 1,
  71. Step: 1,
  72. SecondsSinceStartTime: 1,
  73. LastCommitRound: 2,
  74. }, &tmcons.Message{
  75. Sum: &tmcons.Message_NewRoundStep{
  76. NewRoundStep: &tmcons.NewRoundStep{
  77. Height: 2,
  78. Round: 1,
  79. Step: 1,
  80. SecondsSinceStartTime: 1,
  81. LastCommitRound: 2,
  82. },
  83. },
  84. }, false},
  85. {"successful NewValidBlockMessage", &NewValidBlockMessage{
  86. Height: 1,
  87. Round: 1,
  88. BlockPartSetHeader: psh,
  89. BlockParts: bits,
  90. IsCommit: false,
  91. }, &tmcons.Message{
  92. Sum: &tmcons.Message_NewValidBlock{
  93. NewValidBlock: &tmcons.NewValidBlock{
  94. Height: 1,
  95. Round: 1,
  96. BlockPartSetHeader: pbPsh,
  97. BlockParts: pbBits,
  98. IsCommit: false,
  99. },
  100. },
  101. }, false},
  102. {"successful BlockPartMessage", &BlockPartMessage{
  103. Height: 100,
  104. Round: 1,
  105. Part: &parts,
  106. }, &tmcons.Message{
  107. Sum: &tmcons.Message_BlockPart{
  108. BlockPart: &tmcons.BlockPart{
  109. Height: 100,
  110. Round: 1,
  111. Part: *pbParts,
  112. },
  113. },
  114. }, false},
  115. {"successful ProposalPOLMessage", &ProposalPOLMessage{
  116. Height: 1,
  117. ProposalPOLRound: 1,
  118. ProposalPOL: bits,
  119. }, &tmcons.Message{
  120. Sum: &tmcons.Message_ProposalPol{
  121. ProposalPol: &tmcons.ProposalPOL{
  122. Height: 1,
  123. ProposalPolRound: 1,
  124. ProposalPol: *pbBits,
  125. },
  126. }}, false},
  127. {"successful ProposalMessage", &ProposalMessage{
  128. Proposal: &proposal,
  129. }, &tmcons.Message{
  130. Sum: &tmcons.Message_Proposal{
  131. Proposal: &tmcons.Proposal{
  132. Proposal: *pbProposal,
  133. },
  134. },
  135. }, false},
  136. {"successful VoteMessage", &VoteMessage{
  137. Vote: vote,
  138. }, &tmcons.Message{
  139. Sum: &tmcons.Message_Vote{
  140. Vote: &tmcons.Vote{
  141. Vote: pbVote,
  142. },
  143. },
  144. }, false},
  145. {"successful VoteSetMaj23", &VoteSetMaj23Message{
  146. Height: 1,
  147. Round: 1,
  148. Type: 1,
  149. BlockID: bi,
  150. }, &tmcons.Message{
  151. Sum: &tmcons.Message_VoteSetMaj23{
  152. VoteSetMaj23: &tmcons.VoteSetMaj23{
  153. Height: 1,
  154. Round: 1,
  155. Type: 1,
  156. BlockID: pbBi,
  157. },
  158. },
  159. }, false},
  160. {"successful VoteSetBits", &VoteSetBitsMessage{
  161. Height: 1,
  162. Round: 1,
  163. Type: 1,
  164. BlockID: bi,
  165. Votes: bits,
  166. }, &tmcons.Message{
  167. Sum: &tmcons.Message_VoteSetBits{
  168. VoteSetBits: &tmcons.VoteSetBits{
  169. Height: 1,
  170. Round: 1,
  171. Type: 1,
  172. BlockID: pbBi,
  173. Votes: *pbBits,
  174. },
  175. },
  176. }, false},
  177. {"failure", nil, &tmcons.Message{}, true},
  178. }
  179. for _, tt := range testsCases {
  180. tt := tt
  181. t.Run(tt.testName, func(t *testing.T) {
  182. pb, err := MsgToProto(tt.msg)
  183. if tt.wantErr == true {
  184. assert.Equal(t, err != nil, tt.wantErr)
  185. return
  186. }
  187. assert.EqualValues(t, tt.want, pb, tt.testName)
  188. msg, err := MsgFromProto(pb)
  189. if !tt.wantErr {
  190. require.NoError(t, err)
  191. bcm := assert.Equal(t, tt.msg, msg, tt.testName)
  192. assert.True(t, bcm, tt.testName)
  193. } else {
  194. require.Error(t, err, tt.testName)
  195. }
  196. })
  197. }
  198. }
  199. func TestWALMsgProto(t *testing.T) {
  200. parts := types.Part{
  201. Index: 1,
  202. Bytes: []byte("test"),
  203. Proof: merkle.Proof{
  204. Total: 1,
  205. Index: 1,
  206. LeafHash: tmrand.Bytes(32),
  207. Aunts: [][]byte{},
  208. },
  209. }
  210. pbParts, err := parts.ToProto()
  211. require.NoError(t, err)
  212. testsCases := []struct {
  213. testName string
  214. msg WALMessage
  215. want *tmcons.WALMessage
  216. wantErr bool
  217. }{
  218. {"successful EventDataRoundState", types.EventDataRoundState{
  219. Height: 2,
  220. Round: 1,
  221. Step: "ronies",
  222. }, &tmcons.WALMessage{
  223. Sum: &tmcons.WALMessage_EventDataRoundState{
  224. EventDataRoundState: &tmproto.EventDataRoundState{
  225. Height: 2,
  226. Round: 1,
  227. Step: "ronies",
  228. },
  229. },
  230. }, false},
  231. {"successful msgInfo", msgInfo{
  232. Msg: &BlockPartMessage{
  233. Height: 100,
  234. Round: 1,
  235. Part: &parts,
  236. },
  237. PeerID: types.NodeID("string"),
  238. }, &tmcons.WALMessage{
  239. Sum: &tmcons.WALMessage_MsgInfo{
  240. MsgInfo: &tmcons.MsgInfo{
  241. Msg: tmcons.Message{
  242. Sum: &tmcons.Message_BlockPart{
  243. BlockPart: &tmcons.BlockPart{
  244. Height: 100,
  245. Round: 1,
  246. Part: *pbParts,
  247. },
  248. },
  249. },
  250. PeerID: "string",
  251. },
  252. },
  253. }, false},
  254. {"successful timeoutInfo", timeoutInfo{
  255. Duration: time.Duration(100),
  256. Height: 1,
  257. Round: 1,
  258. Step: 1,
  259. }, &tmcons.WALMessage{
  260. Sum: &tmcons.WALMessage_TimeoutInfo{
  261. TimeoutInfo: &tmcons.TimeoutInfo{
  262. Duration: time.Duration(100),
  263. Height: 1,
  264. Round: 1,
  265. Step: 1,
  266. },
  267. },
  268. }, false},
  269. {"successful EndHeightMessage", EndHeightMessage{
  270. Height: 1,
  271. }, &tmcons.WALMessage{
  272. Sum: &tmcons.WALMessage_EndHeight{
  273. EndHeight: &tmcons.EndHeight{
  274. Height: 1,
  275. },
  276. },
  277. }, false},
  278. {"failure", nil, &tmcons.WALMessage{}, true},
  279. }
  280. for _, tt := range testsCases {
  281. tt := tt
  282. t.Run(tt.testName, func(t *testing.T) {
  283. pb, err := WALToProto(tt.msg)
  284. if tt.wantErr == true {
  285. assert.Equal(t, err != nil, tt.wantErr)
  286. return
  287. }
  288. assert.EqualValues(t, tt.want, pb, tt.testName)
  289. msg, err := WALFromProto(pb)
  290. if !tt.wantErr {
  291. require.NoError(t, err)
  292. assert.Equal(t, tt.msg, msg, tt.testName) // need the concrete type as WAL Message is a empty interface
  293. } else {
  294. require.Error(t, err, tt.testName)
  295. }
  296. })
  297. }
  298. }
  299. // nolint:lll //ignore line length for tests
  300. func TestConsMsgsVectors(t *testing.T) {
  301. date := time.Date(2018, 8, 30, 12, 0, 0, 0, time.UTC)
  302. psh := types.PartSetHeader{
  303. Total: 1,
  304. Hash: []byte("add_more_exclamation_marks_code-"),
  305. }
  306. pbPsh := psh.ToProto()
  307. bi := types.BlockID{
  308. Hash: []byte("add_more_exclamation_marks_code-"),
  309. PartSetHeader: psh,
  310. }
  311. pbBi := bi.ToProto()
  312. bits := bits.NewBitArray(1)
  313. pbBits := bits.ToProto()
  314. parts := types.Part{
  315. Index: 1,
  316. Bytes: []byte("test"),
  317. Proof: merkle.Proof{
  318. Total: 1,
  319. Index: 1,
  320. LeafHash: []byte("add_more_exclamation_marks_code-"),
  321. Aunts: [][]byte{},
  322. },
  323. }
  324. pbParts, err := parts.ToProto()
  325. require.NoError(t, err)
  326. proposal := types.Proposal{
  327. Type: tmproto.ProposalType,
  328. Height: 1,
  329. Round: 1,
  330. POLRound: 1,
  331. BlockID: bi,
  332. Timestamp: date,
  333. Signature: []byte("add_more_exclamation"),
  334. }
  335. pbProposal := proposal.ToProto()
  336. v := &types.Vote{
  337. ValidatorAddress: []byte("add_more_exclamation"),
  338. ValidatorIndex: 1,
  339. Height: 1,
  340. Round: 0,
  341. Timestamp: date,
  342. Type: tmproto.PrecommitType,
  343. BlockID: bi,
  344. }
  345. vpb := v.ToProto()
  346. testCases := []struct {
  347. testName string
  348. cMsg proto.Message
  349. expBytes string
  350. }{
  351. {"NewRoundStep", &tmcons.Message{Sum: &tmcons.Message_NewRoundStep{NewRoundStep: &tmcons.NewRoundStep{
  352. Height: 1,
  353. Round: 1,
  354. Step: 1,
  355. SecondsSinceStartTime: 1,
  356. LastCommitRound: 1,
  357. }}}, "0a0a08011001180120012801"},
  358. {"NewRoundStep Max", &tmcons.Message{Sum: &tmcons.Message_NewRoundStep{NewRoundStep: &tmcons.NewRoundStep{
  359. Height: math.MaxInt64,
  360. Round: math.MaxInt32,
  361. Step: math.MaxUint32,
  362. SecondsSinceStartTime: math.MaxInt64,
  363. LastCommitRound: math.MaxInt32,
  364. }}}, "0a2608ffffffffffffffff7f10ffffffff0718ffffffff0f20ffffffffffffffff7f28ffffffff07"},
  365. {"NewValidBlock", &tmcons.Message{Sum: &tmcons.Message_NewValidBlock{
  366. NewValidBlock: &tmcons.NewValidBlock{
  367. Height: 1, Round: 1, BlockPartSetHeader: pbPsh, BlockParts: pbBits, IsCommit: false}}},
  368. "1231080110011a24080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d22050801120100"},
  369. {"Proposal", &tmcons.Message{Sum: &tmcons.Message_Proposal{Proposal: &tmcons.Proposal{Proposal: *pbProposal}}},
  370. "1a720a7008201001180120012a480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d320608c0b89fdc053a146164645f6d6f72655f6578636c616d6174696f6e"},
  371. {"ProposalPol", &tmcons.Message{Sum: &tmcons.Message_ProposalPol{
  372. ProposalPol: &tmcons.ProposalPOL{Height: 1, ProposalPolRound: 1}}},
  373. "2206080110011a00"},
  374. {"BlockPart", &tmcons.Message{Sum: &tmcons.Message_BlockPart{
  375. BlockPart: &tmcons.BlockPart{Height: 1, Round: 1, Part: *pbParts}}},
  376. "2a36080110011a3008011204746573741a26080110011a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"},
  377. {"Vote", &tmcons.Message{Sum: &tmcons.Message_Vote{
  378. Vote: &tmcons.Vote{Vote: vpb}}},
  379. "32700a6e0802100122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a0608c0b89fdc0532146164645f6d6f72655f6578636c616d6174696f6e3801"},
  380. {"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{
  381. HasVote: &tmcons.HasVote{Height: 1, Round: 1, Type: tmproto.PrevoteType, Index: 1}}},
  382. "3a080801100118012001"},
  383. {"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{
  384. HasVote: &tmcons.HasVote{Height: math.MaxInt64, Round: math.MaxInt32,
  385. Type: tmproto.PrevoteType, Index: math.MaxInt32}}},
  386. "3a1808ffffffffffffffff7f10ffffffff07180120ffffffff07"},
  387. {"VoteSetMaj23", &tmcons.Message{Sum: &tmcons.Message_VoteSetMaj23{
  388. VoteSetMaj23: &tmcons.VoteSetMaj23{Height: 1, Round: 1, Type: tmproto.PrevoteType, BlockID: pbBi}}},
  389. "425008011001180122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"},
  390. {"VoteSetBits", &tmcons.Message{Sum: &tmcons.Message_VoteSetBits{
  391. VoteSetBits: &tmcons.VoteSetBits{Height: 1, Round: 1, Type: tmproto.PrevoteType, BlockID: pbBi, Votes: *pbBits}}},
  392. "4a5708011001180122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a050801120100"},
  393. }
  394. for _, tc := range testCases {
  395. tc := tc
  396. t.Run(tc.testName, func(t *testing.T) {
  397. bz, err := proto.Marshal(tc.cMsg)
  398. require.NoError(t, err)
  399. require.Equal(t, tc.expBytes, hex.EncodeToString(bz))
  400. })
  401. }
  402. }
  403. func TestVoteSetMaj23MessageValidateBasic(t *testing.T) {
  404. const (
  405. validSignedMsgType tmproto.SignedMsgType = 0x01
  406. invalidSignedMsgType tmproto.SignedMsgType = 0x03
  407. )
  408. validBlockID := types.BlockID{}
  409. invalidBlockID := types.BlockID{
  410. Hash: bytes.HexBytes{},
  411. PartSetHeader: types.PartSetHeader{
  412. Total: 1,
  413. Hash: []byte{0},
  414. },
  415. }
  416. testCases := []struct { // nolint: maligned
  417. expectErr bool
  418. messageRound int32
  419. messageHeight int64
  420. testName string
  421. messageType tmproto.SignedMsgType
  422. messageBlockID types.BlockID
  423. }{
  424. {false, 0, 0, "Valid Message", validSignedMsgType, validBlockID},
  425. {true, -1, 0, "Invalid Message", validSignedMsgType, validBlockID},
  426. {true, 0, -1, "Invalid Message", validSignedMsgType, validBlockID},
  427. {true, 0, 0, "Invalid Message", invalidSignedMsgType, validBlockID},
  428. {true, 0, 0, "Invalid Message", validSignedMsgType, invalidBlockID},
  429. }
  430. for _, tc := range testCases {
  431. tc := tc
  432. t.Run(tc.testName, func(t *testing.T) {
  433. message := VoteSetMaj23Message{
  434. Height: tc.messageHeight,
  435. Round: tc.messageRound,
  436. Type: tc.messageType,
  437. BlockID: tc.messageBlockID,
  438. }
  439. assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  440. })
  441. }
  442. }
  443. func TestVoteSetBitsMessageValidateBasic(t *testing.T) {
  444. testCases := []struct {
  445. malleateFn func(*VoteSetBitsMessage)
  446. expErr string
  447. }{
  448. {func(msg *VoteSetBitsMessage) {}, ""},
  449. {func(msg *VoteSetBitsMessage) { msg.Height = -1 }, "negative Height"},
  450. {func(msg *VoteSetBitsMessage) { msg.Type = 0x03 }, "invalid Type"},
  451. {func(msg *VoteSetBitsMessage) {
  452. msg.BlockID = types.BlockID{
  453. Hash: bytes.HexBytes{},
  454. PartSetHeader: types.PartSetHeader{
  455. Total: 1,
  456. Hash: []byte{0},
  457. },
  458. }
  459. }, "wrong BlockID: wrong PartSetHeader: wrong Hash:"},
  460. {func(msg *VoteSetBitsMessage) { msg.Votes = bits.NewBitArray(types.MaxVotesCount + 1) },
  461. "votes bit array is too big: 10001, max: 10000"},
  462. }
  463. for i, tc := range testCases {
  464. tc := tc
  465. t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  466. msg := &VoteSetBitsMessage{
  467. Height: 1,
  468. Round: 0,
  469. Type: 0x01,
  470. Votes: bits.NewBitArray(1),
  471. BlockID: types.BlockID{},
  472. }
  473. tc.malleateFn(msg)
  474. err := msg.ValidateBasic()
  475. if tc.expErr != "" && assert.Error(t, err) {
  476. assert.Contains(t, err.Error(), tc.expErr)
  477. }
  478. })
  479. }
  480. }
  481. func TestNewRoundStepMessageValidateBasic(t *testing.T) {
  482. testCases := []struct { // nolint: maligned
  483. expectErr bool
  484. messageRound int32
  485. messageLastCommitRound int32
  486. messageHeight int64
  487. testName string
  488. messageStep cstypes.RoundStepType
  489. }{
  490. {false, 0, 0, 0, "Valid Message", cstypes.RoundStepNewHeight},
  491. {true, -1, 0, 0, "Negative round", cstypes.RoundStepNewHeight},
  492. {true, 0, 0, -1, "Negative height", cstypes.RoundStepNewHeight},
  493. {true, 0, 0, 0, "Invalid Step", cstypes.RoundStepCommit + 1},
  494. // The following cases will be handled by ValidateHeight
  495. {false, 0, 0, 1, "H == 1 but LCR != -1 ", cstypes.RoundStepNewHeight},
  496. {false, 0, -1, 2, "H > 1 but LCR < 0", cstypes.RoundStepNewHeight},
  497. }
  498. for _, tc := range testCases {
  499. tc := tc
  500. t.Run(tc.testName, func(t *testing.T) {
  501. message := NewRoundStepMessage{
  502. Height: tc.messageHeight,
  503. Round: tc.messageRound,
  504. Step: tc.messageStep,
  505. LastCommitRound: tc.messageLastCommitRound,
  506. }
  507. err := message.ValidateBasic()
  508. if tc.expectErr {
  509. require.Error(t, err)
  510. } else {
  511. require.NoError(t, err)
  512. }
  513. })
  514. }
  515. }
  516. func TestNewRoundStepMessageValidateHeight(t *testing.T) {
  517. initialHeight := int64(10)
  518. testCases := []struct { // nolint: maligned
  519. expectErr bool
  520. messageLastCommitRound int32
  521. messageHeight int64
  522. testName string
  523. }{
  524. {false, 0, 11, "Valid Message"},
  525. {true, 0, -1, "Negative height"},
  526. {true, 0, 0, "Zero height"},
  527. {true, 0, 10, "Initial height but LCR != -1 "},
  528. {true, -1, 11, "Normal height but LCR < 0"},
  529. }
  530. for _, tc := range testCases {
  531. tc := tc
  532. t.Run(tc.testName, func(t *testing.T) {
  533. message := NewRoundStepMessage{
  534. Height: tc.messageHeight,
  535. Round: 0,
  536. Step: cstypes.RoundStepNewHeight,
  537. LastCommitRound: tc.messageLastCommitRound,
  538. }
  539. err := message.ValidateHeight(initialHeight)
  540. if tc.expectErr {
  541. require.Error(t, err)
  542. } else {
  543. require.NoError(t, err)
  544. }
  545. })
  546. }
  547. }
  548. func TestNewValidBlockMessageValidateBasic(t *testing.T) {
  549. testCases := []struct {
  550. malleateFn func(*NewValidBlockMessage)
  551. expErr string
  552. }{
  553. {func(msg *NewValidBlockMessage) {}, ""},
  554. {func(msg *NewValidBlockMessage) { msg.Height = -1 }, "negative Height"},
  555. {func(msg *NewValidBlockMessage) { msg.Round = -1 }, "negative Round"},
  556. {
  557. func(msg *NewValidBlockMessage) { msg.BlockPartSetHeader.Total = 2 },
  558. "blockParts bit array size 1 not equal to BlockPartSetHeader.Total 2",
  559. },
  560. {
  561. func(msg *NewValidBlockMessage) {
  562. msg.BlockPartSetHeader.Total = 0
  563. msg.BlockParts = bits.NewBitArray(0)
  564. },
  565. "empty blockParts",
  566. },
  567. {
  568. func(msg *NewValidBlockMessage) { msg.BlockParts = bits.NewBitArray(int(types.MaxBlockPartsCount) + 1) },
  569. "blockParts bit array size 1602 not equal to BlockPartSetHeader.Total 1",
  570. },
  571. }
  572. for i, tc := range testCases {
  573. tc := tc
  574. t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  575. msg := &NewValidBlockMessage{
  576. Height: 1,
  577. Round: 0,
  578. BlockPartSetHeader: types.PartSetHeader{
  579. Total: 1,
  580. },
  581. BlockParts: bits.NewBitArray(1),
  582. }
  583. tc.malleateFn(msg)
  584. err := msg.ValidateBasic()
  585. if tc.expErr != "" && assert.Error(t, err) {
  586. assert.Contains(t, err.Error(), tc.expErr)
  587. }
  588. })
  589. }
  590. }
  591. func TestProposalPOLMessageValidateBasic(t *testing.T) {
  592. testCases := []struct {
  593. malleateFn func(*ProposalPOLMessage)
  594. expErr string
  595. }{
  596. {func(msg *ProposalPOLMessage) {}, ""},
  597. {func(msg *ProposalPOLMessage) { msg.Height = -1 }, "negative Height"},
  598. {func(msg *ProposalPOLMessage) { msg.ProposalPOLRound = -1 }, "negative ProposalPOLRound"},
  599. {func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(0) }, "empty ProposalPOL bit array"},
  600. {func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(types.MaxVotesCount + 1) },
  601. "proposalPOL bit array is too big: 10001, max: 10000"},
  602. }
  603. for i, tc := range testCases {
  604. tc := tc
  605. t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  606. msg := &ProposalPOLMessage{
  607. Height: 1,
  608. ProposalPOLRound: 1,
  609. ProposalPOL: bits.NewBitArray(1),
  610. }
  611. tc.malleateFn(msg)
  612. err := msg.ValidateBasic()
  613. if tc.expErr != "" && assert.Error(t, err) {
  614. assert.Contains(t, err.Error(), tc.expErr)
  615. }
  616. })
  617. }
  618. }
  619. func TestBlockPartMessageValidateBasic(t *testing.T) {
  620. testPart := new(types.Part)
  621. testPart.Proof.LeafHash = tmhash.Sum([]byte("leaf"))
  622. testCases := []struct {
  623. testName string
  624. messageHeight int64
  625. messageRound int32
  626. messagePart *types.Part
  627. expectErr bool
  628. }{
  629. {"Valid Message", 0, 0, testPart, false},
  630. {"Invalid Message", -1, 0, testPart, true},
  631. {"Invalid Message", 0, -1, testPart, true},
  632. }
  633. for _, tc := range testCases {
  634. tc := tc
  635. t.Run(tc.testName, func(t *testing.T) {
  636. message := BlockPartMessage{
  637. Height: tc.messageHeight,
  638. Round: tc.messageRound,
  639. Part: tc.messagePart,
  640. }
  641. assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  642. })
  643. }
  644. message := BlockPartMessage{Height: 0, Round: 0, Part: new(types.Part)}
  645. message.Part.Index = 1
  646. assert.Equal(t, true, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  647. }
  648. func TestHasVoteMessageValidateBasic(t *testing.T) {
  649. const (
  650. validSignedMsgType tmproto.SignedMsgType = 0x01
  651. invalidSignedMsgType tmproto.SignedMsgType = 0x03
  652. )
  653. testCases := []struct { // nolint: maligned
  654. expectErr bool
  655. messageRound int32
  656. messageIndex int32
  657. messageHeight int64
  658. testName string
  659. messageType tmproto.SignedMsgType
  660. }{
  661. {false, 0, 0, 0, "Valid Message", validSignedMsgType},
  662. {true, -1, 0, 0, "Invalid Message", validSignedMsgType},
  663. {true, 0, -1, 0, "Invalid Message", validSignedMsgType},
  664. {true, 0, 0, 0, "Invalid Message", invalidSignedMsgType},
  665. {true, 0, 0, -1, "Invalid Message", validSignedMsgType},
  666. }
  667. for _, tc := range testCases {
  668. tc := tc
  669. t.Run(tc.testName, func(t *testing.T) {
  670. message := HasVoteMessage{
  671. Height: tc.messageHeight,
  672. Round: tc.messageRound,
  673. Type: tc.messageType,
  674. Index: tc.messageIndex,
  675. }
  676. assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  677. })
  678. }
  679. }