github.com/DFWallet/tendermint-cosmos@v0.0.2/types/block_test.go (about) 1 package types 2 3 import ( 4 // it is ok to use math/rand here: we do not need a cryptographically secure random 5 // number generator here and we can run the tests a bit faster 6 "crypto/rand" 7 "encoding/hex" 8 "math" 9 "os" 10 "reflect" 11 "testing" 12 "time" 13 14 gogotypes "github.com/gogo/protobuf/types" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 18 "github.com/DFWallet/tendermint-cosmos/crypto" 19 "github.com/DFWallet/tendermint-cosmos/crypto/merkle" 20 "github.com/DFWallet/tendermint-cosmos/crypto/tmhash" 21 "github.com/DFWallet/tendermint-cosmos/libs/bits" 22 "github.com/DFWallet/tendermint-cosmos/libs/bytes" 23 tmrand "github.com/DFWallet/tendermint-cosmos/libs/rand" 24 tmproto "github.com/DFWallet/tendermint-cosmos/proto/tendermint/types" 25 tmversion "github.com/DFWallet/tendermint-cosmos/proto/tendermint/version" 26 tmtime "github.com/DFWallet/tendermint-cosmos/types/time" 27 "github.com/DFWallet/tendermint-cosmos/version" 28 ) 29 30 func TestMain(m *testing.M) { 31 code := m.Run() 32 os.Exit(code) 33 } 34 35 func TestBlockAddEvidence(t *testing.T) { 36 txs := []Tx{Tx("foo"), Tx("bar")} 37 lastID := makeBlockIDRandom() 38 h := int64(3) 39 40 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 41 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 42 require.NoError(t, err) 43 44 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 45 evList := []Evidence{ev} 46 47 block := MakeBlock(h, txs, commit, evList) 48 require.NotNil(t, block) 49 require.Equal(t, 1, len(block.Evidence.Evidence)) 50 require.NotNil(t, block.EvidenceHash) 51 } 52 53 func TestBlockValidateBasic(t *testing.T) { 54 require.Error(t, (*Block)(nil).ValidateBasic()) 55 56 txs := []Tx{Tx("foo"), Tx("bar")} 57 lastID := makeBlockIDRandom() 58 h := int64(3) 59 60 voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 61 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 62 require.NoError(t, err) 63 64 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 65 evList := []Evidence{ev} 66 67 testCases := []struct { 68 testName string 69 malleateBlock func(*Block) 70 expErr bool 71 }{ 72 {"Make Block", func(blk *Block) {}, false}, 73 {"Make Block w/ proposer Addr", func(blk *Block) { blk.ProposerAddress = valSet.GetProposer().Address }, false}, 74 {"Negative Height", func(blk *Block) { blk.Height = -1 }, true}, 75 {"Remove 1/2 the commits", func(blk *Block) { 76 blk.LastCommit.Signatures = commit.Signatures[:commit.Size()/2] 77 blk.LastCommit.hash = nil // clear hash or change wont be noticed 78 }, true}, 79 {"Remove LastCommitHash", func(blk *Block) { blk.LastCommitHash = []byte("something else") }, true}, 80 {"Tampered Data", func(blk *Block) { 81 blk.Data.Txs[0] = Tx("something else") 82 blk.Data.hash = nil // clear hash or change wont be noticed 83 }, true}, 84 {"Tampered DataHash", func(blk *Block) { 85 blk.DataHash = tmrand.Bytes(len(blk.DataHash)) 86 }, true}, 87 {"Tampered EvidenceHash", func(blk *Block) { 88 blk.EvidenceHash = []byte("something else") 89 }, true}, 90 {"Incorrect block protocol version", func(blk *Block) { 91 blk.Version.Block = 1 92 }, true}, 93 } 94 for i, tc := range testCases { 95 tc := tc 96 i := i 97 t.Run(tc.testName, func(t *testing.T) { 98 block := MakeBlock(h, txs, commit, evList) 99 block.ProposerAddress = valSet.GetProposer().Address 100 tc.malleateBlock(block) 101 err = block.ValidateBasic() 102 assert.Equal(t, tc.expErr, err != nil, "#%d: %v", i, err) 103 }) 104 } 105 } 106 107 func TestBlockHash(t *testing.T) { 108 assert.Nil(t, (*Block)(nil).Hash()) 109 assert.Nil(t, MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).Hash()) 110 } 111 112 func TestBlockMakePartSet(t *testing.T) { 113 assert.Nil(t, (*Block)(nil).MakePartSet(2)) 114 115 partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).MakePartSet(1024) 116 assert.NotNil(t, partSet) 117 assert.EqualValues(t, 1, partSet.Total()) 118 } 119 120 func TestBlockMakePartSetWithEvidence(t *testing.T) { 121 assert.Nil(t, (*Block)(nil).MakePartSet(2)) 122 123 lastID := makeBlockIDRandom() 124 h := int64(3) 125 126 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 127 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 128 require.NoError(t, err) 129 130 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 131 evList := []Evidence{ev} 132 133 partSet := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512) 134 assert.NotNil(t, partSet) 135 assert.EqualValues(t, 4, partSet.Total()) 136 } 137 138 func TestBlockHashesTo(t *testing.T) { 139 assert.False(t, (*Block)(nil).HashesTo(nil)) 140 141 lastID := makeBlockIDRandom() 142 h := int64(3) 143 voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 144 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 145 require.NoError(t, err) 146 147 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 148 evList := []Evidence{ev} 149 150 block := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList) 151 block.ValidatorsHash = valSet.Hash() 152 assert.False(t, block.HashesTo([]byte{})) 153 assert.False(t, block.HashesTo([]byte("something else"))) 154 assert.True(t, block.HashesTo(block.Hash())) 155 } 156 157 func TestBlockSize(t *testing.T) { 158 size := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).Size() 159 if size <= 0 { 160 t.Fatal("Size of the block is zero or negative") 161 } 162 } 163 164 func TestBlockString(t *testing.T) { 165 assert.Equal(t, "nil-Block", (*Block)(nil).String()) 166 assert.Equal(t, "nil-Block", (*Block)(nil).StringIndented("")) 167 assert.Equal(t, "nil-Block", (*Block)(nil).StringShort()) 168 169 block := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil) 170 assert.NotEqual(t, "nil-Block", block.String()) 171 assert.NotEqual(t, "nil-Block", block.StringIndented("")) 172 assert.NotEqual(t, "nil-Block", block.StringShort()) 173 } 174 175 func makeBlockIDRandom() BlockID { 176 var ( 177 blockHash = make([]byte, tmhash.Size) 178 partSetHash = make([]byte, tmhash.Size) 179 ) 180 rand.Read(blockHash) //nolint: errcheck // ignore errcheck for read 181 rand.Read(partSetHash) //nolint: errcheck // ignore errcheck for read 182 return BlockID{blockHash, PartSetHeader{123, partSetHash}} 183 } 184 185 func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) BlockID { 186 var ( 187 h = make([]byte, tmhash.Size) 188 psH = make([]byte, tmhash.Size) 189 ) 190 copy(h, hash) 191 copy(psH, partSetHash) 192 return BlockID{ 193 Hash: h, 194 PartSetHeader: PartSetHeader{ 195 Total: partSetSize, 196 Hash: psH, 197 }, 198 } 199 } 200 201 var nilBytes []byte 202 203 // This follows RFC-6962, i.e. `echo -n '' | sha256sum` 204 var emptyBytes = []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 205 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 206 0x78, 0x52, 0xb8, 0x55} 207 208 func TestNilHeaderHashDoesntCrash(t *testing.T) { 209 assert.Equal(t, nilBytes, []byte((*Header)(nil).Hash())) 210 assert.Equal(t, nilBytes, []byte((new(Header)).Hash())) 211 } 212 213 func TestNilDataHashDoesntCrash(t *testing.T) { 214 assert.Equal(t, emptyBytes, []byte((*Data)(nil).Hash())) 215 assert.Equal(t, emptyBytes, []byte(new(Data).Hash())) 216 } 217 218 func TestCommit(t *testing.T) { 219 lastID := makeBlockIDRandom() 220 h := int64(3) 221 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 222 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 223 require.NoError(t, err) 224 225 assert.Equal(t, h-1, commit.Height) 226 assert.EqualValues(t, 1, commit.Round) 227 assert.Equal(t, tmproto.PrecommitType, tmproto.SignedMsgType(commit.Type())) 228 if commit.Size() <= 0 { 229 t.Fatalf("commit %v has a zero or negative size: %d", commit, commit.Size()) 230 } 231 232 require.NotNil(t, commit.BitArray()) 233 assert.Equal(t, bits.NewBitArray(10).Size(), commit.BitArray().Size()) 234 235 assert.Equal(t, voteSet.GetByIndex(0), commit.GetByIndex(0)) 236 assert.True(t, commit.IsCommit()) 237 } 238 239 func TestCommitValidateBasic(t *testing.T) { 240 testCases := []struct { 241 testName string 242 malleateCommit func(*Commit) 243 expectErr bool 244 }{ 245 {"Random Commit", func(com *Commit) {}, false}, 246 {"Incorrect signature", func(com *Commit) { com.Signatures[0].Signature = []byte{0} }, false}, 247 {"Incorrect height", func(com *Commit) { com.Height = int64(-100) }, true}, 248 {"Incorrect round", func(com *Commit) { com.Round = -100 }, true}, 249 } 250 for _, tc := range testCases { 251 tc := tc 252 t.Run(tc.testName, func(t *testing.T) { 253 com := randCommit(time.Now()) 254 tc.malleateCommit(com) 255 assert.Equal(t, tc.expectErr, com.ValidateBasic() != nil, "Validate Basic had an unexpected result") 256 }) 257 } 258 } 259 260 func TestMaxCommitBytes(t *testing.T) { 261 // time is varint encoded so need to pick the max. 262 // year int, month Month, day, hour, min, sec, nsec int, loc *Location 263 timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) 264 265 cs := CommitSig{ 266 BlockIDFlag: BlockIDFlagNil, 267 ValidatorAddress: crypto.AddressHash([]byte("validator_address")), 268 Timestamp: timestamp, 269 Signature: crypto.CRandBytes(MaxSignatureSize), 270 } 271 272 pbSig := cs.ToProto() 273 // test that a single commit sig doesn't exceed max commit sig bytes 274 assert.EqualValues(t, MaxCommitSigBytes, pbSig.Size()) 275 276 // check size with a single commit 277 commit := &Commit{ 278 Height: math.MaxInt64, 279 Round: math.MaxInt32, 280 BlockID: BlockID{ 281 Hash: tmhash.Sum([]byte("blockID_hash")), 282 PartSetHeader: PartSetHeader{ 283 Total: math.MaxInt32, 284 Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")), 285 }, 286 }, 287 Signatures: []CommitSig{cs}, 288 } 289 290 pb := commit.ToProto() 291 292 assert.EqualValues(t, MaxCommitBytes(1), int64(pb.Size())) 293 294 // check the upper bound of the commit size 295 for i := 1; i < MaxVotesCount; i++ { 296 commit.Signatures = append(commit.Signatures, cs) 297 } 298 299 pb = commit.ToProto() 300 301 assert.EqualValues(t, MaxCommitBytes(MaxVotesCount), int64(pb.Size())) 302 303 } 304 305 func TestHeaderHash(t *testing.T) { 306 testCases := []struct { 307 desc string 308 header *Header 309 expectHash bytes.HexBytes 310 }{ 311 {"Generates expected hash", &Header{ 312 Version: tmversion.Consensus{Block: 1, App: 2}, 313 ChainID: "chainId", 314 Height: 3, 315 Time: time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC), 316 LastBlockID: makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)), 317 LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), 318 DataHash: tmhash.Sum([]byte("data_hash")), 319 ValidatorsHash: tmhash.Sum([]byte("validators_hash")), 320 NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), 321 ConsensusHash: tmhash.Sum([]byte("consensus_hash")), 322 AppHash: tmhash.Sum([]byte("app_hash")), 323 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 324 EvidenceHash: tmhash.Sum([]byte("evidence_hash")), 325 ProposerAddress: crypto.AddressHash([]byte("proposer_address")), 326 }, hexBytesFromString("F740121F553B5418C3EFBD343C2DBFE9E007BB67B0D020A0741374BAB65242A4")}, 327 {"nil header yields nil", nil, nil}, 328 {"nil ValidatorsHash yields nil", &Header{ 329 Version: tmversion.Consensus{Block: 1, App: 2}, 330 ChainID: "chainId", 331 Height: 3, 332 Time: time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC), 333 LastBlockID: makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)), 334 LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), 335 DataHash: tmhash.Sum([]byte("data_hash")), 336 ValidatorsHash: nil, 337 NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), 338 ConsensusHash: tmhash.Sum([]byte("consensus_hash")), 339 AppHash: tmhash.Sum([]byte("app_hash")), 340 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 341 EvidenceHash: tmhash.Sum([]byte("evidence_hash")), 342 ProposerAddress: crypto.AddressHash([]byte("proposer_address")), 343 }, nil}, 344 } 345 for _, tc := range testCases { 346 tc := tc 347 t.Run(tc.desc, func(t *testing.T) { 348 assert.Equal(t, tc.expectHash, tc.header.Hash()) 349 350 // We also make sure that all fields are hashed in struct order, and that all 351 // fields in the test struct are non-zero. 352 if tc.header != nil && tc.expectHash != nil { 353 byteSlices := [][]byte{} 354 355 s := reflect.ValueOf(*tc.header) 356 for i := 0; i < s.NumField(); i++ { 357 f := s.Field(i) 358 359 assert.False(t, f.IsZero(), "Found zero-valued field %v", 360 s.Type().Field(i).Name) 361 362 switch f := f.Interface().(type) { 363 case int64, bytes.HexBytes, string: 364 byteSlices = append(byteSlices, cdcEncode(f)) 365 case time.Time: 366 bz, err := gogotypes.StdTimeMarshal(f) 367 require.NoError(t, err) 368 byteSlices = append(byteSlices, bz) 369 case tmversion.Consensus: 370 bz, err := f.Marshal() 371 require.NoError(t, err) 372 byteSlices = append(byteSlices, bz) 373 case BlockID: 374 pbbi := f.ToProto() 375 bz, err := pbbi.Marshal() 376 require.NoError(t, err) 377 byteSlices = append(byteSlices, bz) 378 default: 379 t.Errorf("unknown type %T", f) 380 } 381 } 382 assert.Equal(t, 383 bytes.HexBytes(merkle.HashFromByteSlices(byteSlices)), tc.header.Hash()) 384 } 385 }) 386 } 387 } 388 389 func TestMaxHeaderBytes(t *testing.T) { 390 // Construct a UTF-8 string of MaxChainIDLen length using the supplementary 391 // characters. 392 // Each supplementary character takes 4 bytes. 393 // http://www.i18nguy.com/unicode/supplementary-test.html 394 maxChainID := "" 395 for i := 0; i < MaxChainIDLen; i++ { 396 maxChainID += "𠜎" 397 } 398 399 // time is varint encoded so need to pick the max. 400 // year int, month Month, day, hour, min, sec, nsec int, loc *Location 401 timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) 402 403 h := Header{ 404 Version: tmversion.Consensus{Block: math.MaxInt64, App: math.MaxInt64}, 405 ChainID: maxChainID, 406 Height: math.MaxInt64, 407 Time: timestamp, 408 LastBlockID: makeBlockID(make([]byte, tmhash.Size), math.MaxInt32, make([]byte, tmhash.Size)), 409 LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), 410 DataHash: tmhash.Sum([]byte("data_hash")), 411 ValidatorsHash: tmhash.Sum([]byte("validators_hash")), 412 NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), 413 ConsensusHash: tmhash.Sum([]byte("consensus_hash")), 414 AppHash: tmhash.Sum([]byte("app_hash")), 415 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 416 EvidenceHash: tmhash.Sum([]byte("evidence_hash")), 417 ProposerAddress: crypto.AddressHash([]byte("proposer_address")), 418 } 419 420 bz, err := h.ToProto().Marshal() 421 require.NoError(t, err) 422 423 assert.EqualValues(t, MaxHeaderBytes, int64(len(bz))) 424 } 425 426 func randCommit(now time.Time) *Commit { 427 lastID := makeBlockIDRandom() 428 h := int64(3) 429 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 430 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, now) 431 if err != nil { 432 panic(err) 433 } 434 return commit 435 } 436 437 func hexBytesFromString(s string) bytes.HexBytes { 438 b, err := hex.DecodeString(s) 439 if err != nil { 440 panic(err) 441 } 442 return bytes.HexBytes(b) 443 } 444 445 func TestBlockMaxDataBytes(t *testing.T) { 446 testCases := []struct { 447 maxBytes int64 448 valsCount int 449 evidenceBytes int64 450 panics bool 451 result int64 452 }{ 453 0: {-10, 1, 0, true, 0}, 454 1: {10, 1, 0, true, 0}, 455 2: {841, 1, 0, true, 0}, 456 3: {842, 1, 0, false, 0}, 457 4: {843, 1, 0, false, 1}, 458 5: {954, 2, 0, false, 1}, 459 6: {1053, 2, 100, false, 0}, 460 } 461 462 for i, tc := range testCases { 463 tc := tc 464 if tc.panics { 465 assert.Panics(t, func() { 466 MaxDataBytes(tc.maxBytes, tc.evidenceBytes, tc.valsCount) 467 }, "#%v", i) 468 } else { 469 assert.Equal(t, 470 tc.result, 471 MaxDataBytes(tc.maxBytes, tc.evidenceBytes, tc.valsCount), 472 "#%v", i) 473 } 474 } 475 } 476 477 func TestBlockMaxDataBytesNoEvidence(t *testing.T) { 478 testCases := []struct { 479 maxBytes int64 480 valsCount int 481 panics bool 482 result int64 483 }{ 484 0: {-10, 1, true, 0}, 485 1: {10, 1, true, 0}, 486 2: {841, 1, true, 0}, 487 3: {842, 1, false, 0}, 488 4: {843, 1, false, 1}, 489 } 490 491 for i, tc := range testCases { 492 tc := tc 493 if tc.panics { 494 assert.Panics(t, func() { 495 MaxDataBytesNoEvidence(tc.maxBytes, tc.valsCount) 496 }, "#%v", i) 497 } else { 498 assert.Equal(t, 499 tc.result, 500 MaxDataBytesNoEvidence(tc.maxBytes, tc.valsCount), 501 "#%v", i) 502 } 503 } 504 } 505 506 func TestCommitToVoteSet(t *testing.T) { 507 lastID := makeBlockIDRandom() 508 h := int64(3) 509 510 voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 511 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 512 assert.NoError(t, err) 513 514 chainID := voteSet.ChainID() 515 voteSet2 := CommitToVoteSet(chainID, commit, valSet) 516 517 for i := int32(0); int(i) < len(vals); i++ { 518 vote1 := voteSet.GetByIndex(i) 519 vote2 := voteSet2.GetByIndex(i) 520 vote3 := commit.GetVote(i) 521 522 vote1bz, err := vote1.ToProto().Marshal() 523 require.NoError(t, err) 524 vote2bz, err := vote2.ToProto().Marshal() 525 require.NoError(t, err) 526 vote3bz, err := vote3.ToProto().Marshal() 527 require.NoError(t, err) 528 assert.Equal(t, vote1bz, vote2bz) 529 assert.Equal(t, vote1bz, vote3bz) 530 } 531 } 532 533 func TestCommitToVoteSetWithVotesForNilBlock(t *testing.T) { 534 blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash")) 535 536 const ( 537 height = int64(3) 538 round = 0 539 ) 540 541 type commitVoteTest struct { 542 blockIDs []BlockID 543 numVotes []int // must sum to numValidators 544 numValidators int 545 valid bool 546 } 547 548 testCases := []commitVoteTest{ 549 {[]BlockID{blockID, {}}, []int{67, 33}, 100, true}, 550 } 551 552 for _, tc := range testCases { 553 voteSet, valSet, vals := randVoteSet(height-1, round, tmproto.PrecommitType, tc.numValidators, 1) 554 555 vi := int32(0) 556 for n := range tc.blockIDs { 557 for i := 0; i < tc.numVotes[n]; i++ { 558 pubKey, err := vals[vi].GetPubKey() 559 require.NoError(t, err) 560 vote := &Vote{ 561 ValidatorAddress: pubKey.Address(), 562 ValidatorIndex: vi, 563 Height: height - 1, 564 Round: round, 565 Type: tmproto.PrecommitType, 566 BlockID: tc.blockIDs[n], 567 Timestamp: tmtime.Now(), 568 } 569 570 added, err := signAddVote(vals[vi], vote, voteSet) 571 assert.NoError(t, err) 572 assert.True(t, added) 573 574 vi++ 575 } 576 } 577 578 if tc.valid { 579 commit := voteSet.MakeCommit() // panics without > 2/3 valid votes 580 assert.NotNil(t, commit) 581 err := valSet.VerifyCommit(voteSet.ChainID(), blockID, height-1, commit) 582 assert.Nil(t, err) 583 } else { 584 assert.Panics(t, func() { voteSet.MakeCommit() }) 585 } 586 } 587 } 588 589 func TestBlockIDValidateBasic(t *testing.T) { 590 validBlockID := BlockID{ 591 Hash: bytes.HexBytes{}, 592 PartSetHeader: PartSetHeader{ 593 Total: 1, 594 Hash: bytes.HexBytes{}, 595 }, 596 } 597 598 invalidBlockID := BlockID{ 599 Hash: []byte{0}, 600 PartSetHeader: PartSetHeader{ 601 Total: 1, 602 Hash: []byte{0}, 603 }, 604 } 605 606 testCases := []struct { 607 testName string 608 blockIDHash bytes.HexBytes 609 blockIDPartSetHeader PartSetHeader 610 expectErr bool 611 }{ 612 {"Valid BlockID", validBlockID.Hash, validBlockID.PartSetHeader, false}, 613 {"Invalid BlockID", invalidBlockID.Hash, validBlockID.PartSetHeader, true}, 614 {"Invalid BlockID", validBlockID.Hash, invalidBlockID.PartSetHeader, true}, 615 } 616 617 for _, tc := range testCases { 618 tc := tc 619 t.Run(tc.testName, func(t *testing.T) { 620 blockID := BlockID{ 621 Hash: tc.blockIDHash, 622 PartSetHeader: tc.blockIDPartSetHeader, 623 } 624 assert.Equal(t, tc.expectErr, blockID.ValidateBasic() != nil, "Validate Basic had an unexpected result") 625 }) 626 } 627 } 628 629 func TestBlockProtoBuf(t *testing.T) { 630 h := tmrand.Int63() 631 c1 := randCommit(time.Now()) 632 b1 := MakeBlock(h, []Tx{Tx([]byte{1})}, &Commit{Signatures: []CommitSig{}}, []Evidence{}) 633 b1.ProposerAddress = tmrand.Bytes(crypto.AddressSize) 634 635 b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{}) 636 b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize) 637 evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) 638 evi := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain") 639 b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}} 640 b2.EvidenceHash = b2.Evidence.Hash() 641 642 b3 := MakeBlock(h, []Tx{}, c1, []Evidence{}) 643 b3.ProposerAddress = tmrand.Bytes(crypto.AddressSize) 644 testCases := []struct { 645 msg string 646 b1 *Block 647 expPass bool 648 expPass2 bool 649 }{ 650 {"nil block", nil, false, false}, 651 {"b1", b1, true, true}, 652 {"b2", b2, true, true}, 653 {"b3", b3, true, true}, 654 } 655 for _, tc := range testCases { 656 pb, err := tc.b1.ToProto() 657 if tc.expPass { 658 require.NoError(t, err, tc.msg) 659 } else { 660 require.Error(t, err, tc.msg) 661 } 662 663 block, err := BlockFromProto(pb) 664 if tc.expPass2 { 665 require.NoError(t, err, tc.msg) 666 require.EqualValues(t, tc.b1.Header, block.Header, tc.msg) 667 require.EqualValues(t, tc.b1.Data, block.Data, tc.msg) 668 require.EqualValues(t, tc.b1.Evidence.Evidence, block.Evidence.Evidence, tc.msg) 669 require.EqualValues(t, *tc.b1.LastCommit, *block.LastCommit, tc.msg) 670 } else { 671 require.Error(t, err, tc.msg) 672 } 673 } 674 } 675 676 func TestDataProtoBuf(t *testing.T) { 677 data := &Data{Txs: Txs{Tx([]byte{1}), Tx([]byte{2}), Tx([]byte{3})}} 678 data2 := &Data{Txs: Txs{}} 679 testCases := []struct { 680 msg string 681 data1 *Data 682 expPass bool 683 }{ 684 {"success", data, true}, 685 {"success data2", data2, true}, 686 } 687 for _, tc := range testCases { 688 protoData := tc.data1.ToProto() 689 d, err := DataFromProto(&protoData) 690 if tc.expPass { 691 require.NoError(t, err, tc.msg) 692 require.EqualValues(t, tc.data1, &d, tc.msg) 693 } else { 694 require.Error(t, err, tc.msg) 695 } 696 } 697 } 698 699 // TestEvidenceDataProtoBuf ensures parity in converting to and from proto. 700 func TestEvidenceDataProtoBuf(t *testing.T) { 701 const chainID = "mychain" 702 ev := NewMockDuplicateVoteEvidence(math.MaxInt64, time.Now(), chainID) 703 data := &EvidenceData{Evidence: EvidenceList{ev}} 704 _ = data.ByteSize() 705 testCases := []struct { 706 msg string 707 data1 *EvidenceData 708 expPass1 bool 709 expPass2 bool 710 }{ 711 {"success", data, true, true}, 712 {"empty evidenceData", &EvidenceData{Evidence: EvidenceList{}}, true, true}, 713 {"fail nil Data", nil, false, false}, 714 } 715 716 for _, tc := range testCases { 717 protoData, err := tc.data1.ToProto() 718 if tc.expPass1 { 719 require.NoError(t, err, tc.msg) 720 } else { 721 require.Error(t, err, tc.msg) 722 } 723 724 eviD := new(EvidenceData) 725 err = eviD.FromProto(protoData) 726 if tc.expPass2 { 727 require.NoError(t, err, tc.msg) 728 require.Equal(t, tc.data1, eviD, tc.msg) 729 } else { 730 require.Error(t, err, tc.msg) 731 } 732 } 733 } 734 735 func makeRandHeader() Header { 736 chainID := "test" 737 t := time.Now() 738 height := tmrand.Int63() 739 randBytes := tmrand.Bytes(tmhash.Size) 740 randAddress := tmrand.Bytes(crypto.AddressSize) 741 h := Header{ 742 Version: tmversion.Consensus{Block: version.BlockProtocol, App: 1}, 743 ChainID: chainID, 744 Height: height, 745 Time: t, 746 LastBlockID: BlockID{}, 747 LastCommitHash: randBytes, 748 DataHash: randBytes, 749 ValidatorsHash: randBytes, 750 NextValidatorsHash: randBytes, 751 ConsensusHash: randBytes, 752 AppHash: randBytes, 753 754 LastResultsHash: randBytes, 755 756 EvidenceHash: randBytes, 757 ProposerAddress: randAddress, 758 } 759 760 return h 761 } 762 763 func TestHeaderProto(t *testing.T) { 764 h1 := makeRandHeader() 765 tc := []struct { 766 msg string 767 h1 *Header 768 expPass bool 769 }{ 770 {"success", &h1, true}, 771 {"failure empty Header", &Header{}, false}, 772 } 773 774 for _, tt := range tc { 775 tt := tt 776 t.Run(tt.msg, func(t *testing.T) { 777 pb := tt.h1.ToProto() 778 h, err := HeaderFromProto(pb) 779 if tt.expPass { 780 require.NoError(t, err, tt.msg) 781 require.Equal(t, tt.h1, &h, tt.msg) 782 } else { 783 require.Error(t, err, tt.msg) 784 } 785 786 }) 787 } 788 } 789 790 func TestBlockIDProtoBuf(t *testing.T) { 791 blockID := makeBlockID([]byte("hash"), 2, []byte("part_set_hash")) 792 testCases := []struct { 793 msg string 794 bid1 *BlockID 795 expPass bool 796 }{ 797 {"success", &blockID, true}, 798 {"success empty", &BlockID{}, true}, 799 {"failure BlockID nil", nil, false}, 800 } 801 for _, tc := range testCases { 802 protoBlockID := tc.bid1.ToProto() 803 804 bi, err := BlockIDFromProto(&protoBlockID) 805 if tc.expPass { 806 require.NoError(t, err) 807 require.Equal(t, tc.bid1, bi, tc.msg) 808 } else { 809 require.NotEqual(t, tc.bid1, bi, tc.msg) 810 } 811 } 812 } 813 814 func TestSignedHeaderProtoBuf(t *testing.T) { 815 commit := randCommit(time.Now()) 816 h := makeRandHeader() 817 818 sh := SignedHeader{Header: &h, Commit: commit} 819 820 testCases := []struct { 821 msg string 822 sh1 *SignedHeader 823 expPass bool 824 }{ 825 {"empty SignedHeader 2", &SignedHeader{}, true}, 826 {"success", &sh, true}, 827 {"failure nil", nil, false}, 828 } 829 for _, tc := range testCases { 830 protoSignedHeader := tc.sh1.ToProto() 831 832 sh, err := SignedHeaderFromProto(protoSignedHeader) 833 834 if tc.expPass { 835 require.NoError(t, err, tc.msg) 836 require.Equal(t, tc.sh1, sh, tc.msg) 837 } else { 838 require.Error(t, err, tc.msg) 839 } 840 } 841 } 842 843 func TestBlockIDEquals(t *testing.T) { 844 var ( 845 blockID = makeBlockID([]byte("hash"), 2, []byte("part_set_hash")) 846 blockIDDuplicate = makeBlockID([]byte("hash"), 2, []byte("part_set_hash")) 847 blockIDDifferent = makeBlockID([]byte("different_hash"), 2, []byte("part_set_hash")) 848 blockIDEmpty = BlockID{} 849 ) 850 851 assert.True(t, blockID.Equals(blockIDDuplicate)) 852 assert.False(t, blockID.Equals(blockIDDifferent)) 853 assert.False(t, blockID.Equals(blockIDEmpty)) 854 assert.True(t, blockIDEmpty.Equals(blockIDEmpty)) 855 assert.False(t, blockIDEmpty.Equals(blockIDDifferent)) 856 }