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.

741 lines
21 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. ext := types.VoteExtension{
  339. AppDataToSign: []byte("signed"),
  340. AppDataSelfAuthenticating: []byte("auth"),
  341. }
  342. v := &types.Vote{
  343. ValidatorAddress: []byte("add_more_exclamation"),
  344. ValidatorIndex: 1,
  345. Height: 1,
  346. Round: 0,
  347. Timestamp: date,
  348. Type: tmproto.PrecommitType,
  349. BlockID: bi,
  350. VoteExtension: ext,
  351. }
  352. vpb := v.ToProto()
  353. testCases := []struct {
  354. testName string
  355. cMsg proto.Message
  356. expBytes string
  357. }{
  358. {"NewRoundStep", &tmcons.Message{Sum: &tmcons.Message_NewRoundStep{NewRoundStep: &tmcons.NewRoundStep{
  359. Height: 1,
  360. Round: 1,
  361. Step: 1,
  362. SecondsSinceStartTime: 1,
  363. LastCommitRound: 1,
  364. }}}, "0a0a08011001180120012801"},
  365. {"NewRoundStep Max", &tmcons.Message{Sum: &tmcons.Message_NewRoundStep{NewRoundStep: &tmcons.NewRoundStep{
  366. Height: math.MaxInt64,
  367. Round: math.MaxInt32,
  368. Step: math.MaxUint32,
  369. SecondsSinceStartTime: math.MaxInt64,
  370. LastCommitRound: math.MaxInt32,
  371. }}}, "0a2608ffffffffffffffff7f10ffffffff0718ffffffff0f20ffffffffffffffff7f28ffffffff07"},
  372. {"NewValidBlock", &tmcons.Message{Sum: &tmcons.Message_NewValidBlock{
  373. NewValidBlock: &tmcons.NewValidBlock{
  374. Height: 1, Round: 1, BlockPartSetHeader: pbPsh, BlockParts: pbBits, IsCommit: false}}},
  375. "1231080110011a24080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d22050801120100"},
  376. {"Proposal", &tmcons.Message{Sum: &tmcons.Message_Proposal{Proposal: &tmcons.Proposal{Proposal: *pbProposal}}},
  377. "1a720a7008201001180120012a480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d320608c0b89fdc053a146164645f6d6f72655f6578636c616d6174696f6e"},
  378. {"ProposalPol", &tmcons.Message{Sum: &tmcons.Message_ProposalPol{
  379. ProposalPol: &tmcons.ProposalPOL{Height: 1, ProposalPolRound: 1}}},
  380. "2206080110011a00"},
  381. {"BlockPart", &tmcons.Message{Sum: &tmcons.Message_BlockPart{
  382. BlockPart: &tmcons.BlockPart{Height: 1, Round: 1, Part: *pbParts}}},
  383. "2a36080110011a3008011204746573741a26080110011a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"},
  384. {"Vote", &tmcons.Message{Sum: &tmcons.Message_Vote{
  385. Vote: &tmcons.Vote{Vote: vpb}}},
  386. "3280010a7e0802100122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a0608c0b89fdc0532146164645f6d6f72655f6578636c616d6174696f6e38014a0e0a067369676e6564120461757468"},
  387. {"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{
  388. HasVote: &tmcons.HasVote{Height: 1, Round: 1, Type: tmproto.PrevoteType, Index: 1}}},
  389. "3a080801100118012001"},
  390. {"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{
  391. HasVote: &tmcons.HasVote{Height: math.MaxInt64, Round: math.MaxInt32,
  392. Type: tmproto.PrevoteType, Index: math.MaxInt32}}},
  393. "3a1808ffffffffffffffff7f10ffffffff07180120ffffffff07"},
  394. {"VoteSetMaj23", &tmcons.Message{Sum: &tmcons.Message_VoteSetMaj23{
  395. VoteSetMaj23: &tmcons.VoteSetMaj23{Height: 1, Round: 1, Type: tmproto.PrevoteType, BlockID: pbBi}}},
  396. "425008011001180122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"},
  397. {"VoteSetBits", &tmcons.Message{Sum: &tmcons.Message_VoteSetBits{
  398. VoteSetBits: &tmcons.VoteSetBits{Height: 1, Round: 1, Type: tmproto.PrevoteType, BlockID: pbBi, Votes: *pbBits}}},
  399. "4a5708011001180122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a050801120100"},
  400. }
  401. for _, tc := range testCases {
  402. tc := tc
  403. t.Run(tc.testName, func(t *testing.T) {
  404. bz, err := proto.Marshal(tc.cMsg)
  405. require.NoError(t, err)
  406. require.Equal(t, tc.expBytes, hex.EncodeToString(bz))
  407. })
  408. }
  409. }
  410. func TestVoteSetMaj23MessageValidateBasic(t *testing.T) {
  411. const (
  412. validSignedMsgType tmproto.SignedMsgType = 0x01
  413. invalidSignedMsgType tmproto.SignedMsgType = 0x03
  414. )
  415. validBlockID := types.BlockID{}
  416. invalidBlockID := types.BlockID{
  417. Hash: bytes.HexBytes{},
  418. PartSetHeader: types.PartSetHeader{
  419. Total: 1,
  420. Hash: []byte{0},
  421. },
  422. }
  423. testCases := []struct { // nolint: maligned
  424. expectErr bool
  425. messageRound int32
  426. messageHeight int64
  427. testName string
  428. messageType tmproto.SignedMsgType
  429. messageBlockID types.BlockID
  430. }{
  431. {false, 0, 0, "Valid Message", validSignedMsgType, validBlockID},
  432. {true, -1, 0, "Invalid Message", validSignedMsgType, validBlockID},
  433. {true, 0, -1, "Invalid Message", validSignedMsgType, validBlockID},
  434. {true, 0, 0, "Invalid Message", invalidSignedMsgType, validBlockID},
  435. {true, 0, 0, "Invalid Message", validSignedMsgType, invalidBlockID},
  436. }
  437. for _, tc := range testCases {
  438. tc := tc
  439. t.Run(tc.testName, func(t *testing.T) {
  440. message := VoteSetMaj23Message{
  441. Height: tc.messageHeight,
  442. Round: tc.messageRound,
  443. Type: tc.messageType,
  444. BlockID: tc.messageBlockID,
  445. }
  446. assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  447. })
  448. }
  449. }
  450. func TestVoteSetBitsMessageValidateBasic(t *testing.T) {
  451. testCases := []struct {
  452. malleateFn func(*VoteSetBitsMessage)
  453. expErr string
  454. }{
  455. {func(msg *VoteSetBitsMessage) {}, ""},
  456. {func(msg *VoteSetBitsMessage) { msg.Height = -1 }, "negative Height"},
  457. {func(msg *VoteSetBitsMessage) { msg.Type = 0x03 }, "invalid Type"},
  458. {func(msg *VoteSetBitsMessage) {
  459. msg.BlockID = types.BlockID{
  460. Hash: bytes.HexBytes{},
  461. PartSetHeader: types.PartSetHeader{
  462. Total: 1,
  463. Hash: []byte{0},
  464. },
  465. }
  466. }, "wrong BlockID: wrong PartSetHeader: wrong Hash:"},
  467. {func(msg *VoteSetBitsMessage) { msg.Votes = bits.NewBitArray(types.MaxVotesCount + 1) },
  468. "votes bit array is too big: 10001, max: 10000"},
  469. }
  470. for i, tc := range testCases {
  471. tc := tc
  472. t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  473. msg := &VoteSetBitsMessage{
  474. Height: 1,
  475. Round: 0,
  476. Type: 0x01,
  477. Votes: bits.NewBitArray(1),
  478. BlockID: types.BlockID{},
  479. }
  480. tc.malleateFn(msg)
  481. err := msg.ValidateBasic()
  482. if tc.expErr != "" && assert.Error(t, err) {
  483. assert.Contains(t, err.Error(), tc.expErr)
  484. }
  485. })
  486. }
  487. }
  488. func TestNewRoundStepMessageValidateBasic(t *testing.T) {
  489. testCases := []struct { // nolint: maligned
  490. expectErr bool
  491. messageRound int32
  492. messageLastCommitRound int32
  493. messageHeight int64
  494. testName string
  495. messageStep cstypes.RoundStepType
  496. }{
  497. {false, 0, 0, 0, "Valid Message", cstypes.RoundStepNewHeight},
  498. {true, -1, 0, 0, "Negative round", cstypes.RoundStepNewHeight},
  499. {true, 0, 0, -1, "Negative height", cstypes.RoundStepNewHeight},
  500. {true, 0, 0, 0, "Invalid Step", cstypes.RoundStepCommit + 1},
  501. // The following cases will be handled by ValidateHeight
  502. {false, 0, 0, 1, "H == 1 but LCR != -1 ", cstypes.RoundStepNewHeight},
  503. {false, 0, -1, 2, "H > 1 but LCR < 0", cstypes.RoundStepNewHeight},
  504. }
  505. for _, tc := range testCases {
  506. tc := tc
  507. t.Run(tc.testName, func(t *testing.T) {
  508. message := NewRoundStepMessage{
  509. Height: tc.messageHeight,
  510. Round: tc.messageRound,
  511. Step: tc.messageStep,
  512. LastCommitRound: tc.messageLastCommitRound,
  513. }
  514. err := message.ValidateBasic()
  515. if tc.expectErr {
  516. require.Error(t, err)
  517. } else {
  518. require.NoError(t, err)
  519. }
  520. })
  521. }
  522. }
  523. func TestNewRoundStepMessageValidateHeight(t *testing.T) {
  524. initialHeight := int64(10)
  525. testCases := []struct { // nolint: maligned
  526. expectErr bool
  527. messageLastCommitRound int32
  528. messageHeight int64
  529. testName string
  530. }{
  531. {false, 0, 11, "Valid Message"},
  532. {true, 0, -1, "Negative height"},
  533. {true, 0, 0, "Zero height"},
  534. {true, 0, 10, "Initial height but LCR != -1 "},
  535. {true, -1, 11, "Normal height but LCR < 0"},
  536. }
  537. for _, tc := range testCases {
  538. tc := tc
  539. t.Run(tc.testName, func(t *testing.T) {
  540. message := NewRoundStepMessage{
  541. Height: tc.messageHeight,
  542. Round: 0,
  543. Step: cstypes.RoundStepNewHeight,
  544. LastCommitRound: tc.messageLastCommitRound,
  545. }
  546. err := message.ValidateHeight(initialHeight)
  547. if tc.expectErr {
  548. require.Error(t, err)
  549. } else {
  550. require.NoError(t, err)
  551. }
  552. })
  553. }
  554. }
  555. func TestNewValidBlockMessageValidateBasic(t *testing.T) {
  556. testCases := []struct {
  557. malleateFn func(*NewValidBlockMessage)
  558. expErr string
  559. }{
  560. {func(msg *NewValidBlockMessage) {}, ""},
  561. {func(msg *NewValidBlockMessage) { msg.Height = -1 }, "negative Height"},
  562. {func(msg *NewValidBlockMessage) { msg.Round = -1 }, "negative Round"},
  563. {
  564. func(msg *NewValidBlockMessage) { msg.BlockPartSetHeader.Total = 2 },
  565. "blockParts bit array size 1 not equal to BlockPartSetHeader.Total 2",
  566. },
  567. {
  568. func(msg *NewValidBlockMessage) {
  569. msg.BlockPartSetHeader.Total = 0
  570. msg.BlockParts = bits.NewBitArray(0)
  571. },
  572. "empty blockParts",
  573. },
  574. {
  575. func(msg *NewValidBlockMessage) { msg.BlockParts = bits.NewBitArray(int(types.MaxBlockPartsCount) + 1) },
  576. "blockParts bit array size 1602 not equal to BlockPartSetHeader.Total 1",
  577. },
  578. }
  579. for i, tc := range testCases {
  580. tc := tc
  581. t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  582. msg := &NewValidBlockMessage{
  583. Height: 1,
  584. Round: 0,
  585. BlockPartSetHeader: types.PartSetHeader{
  586. Total: 1,
  587. },
  588. BlockParts: bits.NewBitArray(1),
  589. }
  590. tc.malleateFn(msg)
  591. err := msg.ValidateBasic()
  592. if tc.expErr != "" && assert.Error(t, err) {
  593. assert.Contains(t, err.Error(), tc.expErr)
  594. }
  595. })
  596. }
  597. }
  598. func TestProposalPOLMessageValidateBasic(t *testing.T) {
  599. testCases := []struct {
  600. malleateFn func(*ProposalPOLMessage)
  601. expErr string
  602. }{
  603. {func(msg *ProposalPOLMessage) {}, ""},
  604. {func(msg *ProposalPOLMessage) { msg.Height = -1 }, "negative Height"},
  605. {func(msg *ProposalPOLMessage) { msg.ProposalPOLRound = -1 }, "negative ProposalPOLRound"},
  606. {func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(0) }, "empty ProposalPOL bit array"},
  607. {func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(types.MaxVotesCount + 1) },
  608. "proposalPOL bit array is too big: 10001, max: 10000"},
  609. }
  610. for i, tc := range testCases {
  611. tc := tc
  612. t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  613. msg := &ProposalPOLMessage{
  614. Height: 1,
  615. ProposalPOLRound: 1,
  616. ProposalPOL: bits.NewBitArray(1),
  617. }
  618. tc.malleateFn(msg)
  619. err := msg.ValidateBasic()
  620. if tc.expErr != "" && assert.Error(t, err) {
  621. assert.Contains(t, err.Error(), tc.expErr)
  622. }
  623. })
  624. }
  625. }
  626. func TestBlockPartMessageValidateBasic(t *testing.T) {
  627. testPart := new(types.Part)
  628. testPart.Proof.LeafHash = tmhash.Sum([]byte("leaf"))
  629. testCases := []struct {
  630. testName string
  631. messageHeight int64
  632. messageRound int32
  633. messagePart *types.Part
  634. expectErr bool
  635. }{
  636. {"Valid Message", 0, 0, testPart, false},
  637. {"Invalid Message", -1, 0, testPart, true},
  638. {"Invalid Message", 0, -1, testPart, true},
  639. }
  640. for _, tc := range testCases {
  641. tc := tc
  642. t.Run(tc.testName, func(t *testing.T) {
  643. message := BlockPartMessage{
  644. Height: tc.messageHeight,
  645. Round: tc.messageRound,
  646. Part: tc.messagePart,
  647. }
  648. assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  649. })
  650. }
  651. message := BlockPartMessage{Height: 0, Round: 0, Part: new(types.Part)}
  652. message.Part.Index = 1
  653. assert.Equal(t, true, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  654. }
  655. func TestHasVoteMessageValidateBasic(t *testing.T) {
  656. const (
  657. validSignedMsgType tmproto.SignedMsgType = 0x01
  658. invalidSignedMsgType tmproto.SignedMsgType = 0x03
  659. )
  660. testCases := []struct { // nolint: maligned
  661. expectErr bool
  662. messageRound int32
  663. messageIndex int32
  664. messageHeight int64
  665. testName string
  666. messageType tmproto.SignedMsgType
  667. }{
  668. {false, 0, 0, 0, "Valid Message", validSignedMsgType},
  669. {true, -1, 0, 0, "Invalid Message", validSignedMsgType},
  670. {true, 0, -1, 0, "Invalid Message", validSignedMsgType},
  671. {true, 0, 0, 0, "Invalid Message", invalidSignedMsgType},
  672. {true, 0, 0, -1, "Invalid Message", validSignedMsgType},
  673. }
  674. for _, tc := range testCases {
  675. tc := tc
  676. t.Run(tc.testName, func(t *testing.T) {
  677. message := HasVoteMessage{
  678. Height: tc.messageHeight,
  679. Round: tc.messageRound,
  680. Type: tc.messageType,
  681. Index: tc.messageIndex,
  682. }
  683. assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  684. })
  685. }
  686. }