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.

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