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.

735 lines
20 KiB

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