github.com/Finschia/ostracon@v1.1.5/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 "strings" 12 "testing" 13 "time" 14 15 gogotypes "github.com/gogo/protobuf/types" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 19 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 20 tmversion "github.com/tendermint/tendermint/proto/tendermint/version" 21 22 vrf "github.com/oasisprotocol/curve25519-voi/primitives/ed25519/extra/ecvrf" 23 24 "github.com/Finschia/ostracon/crypto" 25 "github.com/Finschia/ostracon/crypto/merkle" 26 "github.com/Finschia/ostracon/crypto/tmhash" 27 "github.com/Finschia/ostracon/libs/bits" 28 "github.com/Finschia/ostracon/libs/bytes" 29 tmrand "github.com/Finschia/ostracon/libs/rand" 30 tmtime "github.com/Finschia/ostracon/types/time" 31 "github.com/Finschia/ostracon/version" 32 ) 33 34 var TestConsensusVersion = tmversion.Consensus{ 35 Block: version.BlockProtocol, 36 App: version.AppProtocol, 37 } 38 39 func TestMain(m *testing.M) { 40 code := m.Run() 41 os.Exit(code) 42 } 43 44 func TestBlockAddEvidence(t *testing.T) { 45 txs := []Tx{Tx("foo"), Tx("bar")} 46 lastID := makeBlockIDRandom() 47 h := int64(3) 48 49 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 50 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 51 require.NoError(t, err) 52 53 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 54 evList := []Evidence{ev} 55 56 block := MakeBlock(h, txs, commit, evList, TestConsensusVersion) 57 require.NotNil(t, block) 58 require.Equal(t, 1, len(block.Evidence.Evidence)) 59 require.NotNil(t, block.EvidenceHash) 60 } 61 62 func TestBlockValidateBasic(t *testing.T) { 63 require.Error(t, (*Block)(nil).ValidateBasic()) 64 65 txs := []Tx{Tx("foo"), Tx("bar")} 66 lastID := makeBlockIDRandom() 67 h := int64(3) 68 69 voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 70 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 71 require.NoError(t, err) 72 73 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 74 evList := []Evidence{ev} 75 76 testCases := []struct { 77 testName string 78 malleateBlock func(*Block) 79 expErr bool 80 }{ 81 {"Make Block", func(blk *Block) {}, false}, 82 {"Make Block w/ proposer Addr", func(blk *Block) { 83 blk.ProposerAddress = valSet.SelectProposer([]byte{}, blk.Height, 0).Address 84 }, false}, 85 {"Tampered ProposerAddress", func(blk *Block) { 86 blk.ProposerAddress = []byte("something else") 87 }, true}, 88 {"Incorrect chain id", func(blk *Block) { 89 blk.ChainID = "123456789012345678901234567890123456789012345678901" 90 }, true}, 91 {"Negative Height", func(blk *Block) { blk.Height = -1 }, true}, 92 {"Height is zero", func(blk *Block) { blk.Height = 0 }, true}, 93 {"Remove 1/2 the commits", func(blk *Block) { 94 blk.LastCommit.Signatures = commit.Signatures[:commit.Size()/2] 95 blk.LastCommit.hash = nil // clear hash or change wont be noticed 96 }, true}, 97 {"Remove LastCommitHash", func(blk *Block) { blk.LastCommitHash = []byte("something else") }, true}, 98 {"Tampered Data", func(blk *Block) { 99 blk.Data.Txs[0] = Tx("something else") 100 blk.Data.hash = nil // clear hash or change wont be noticed 101 }, true}, 102 {"Tampered DataHash", func(blk *Block) { 103 blk.DataHash = tmrand.Bytes(len(blk.DataHash)) 104 }, true}, 105 {"Tampered DataHash", func(blk *Block) { 106 blk.DataHash = []byte("something else") 107 }, true}, 108 {"Tampered EvidenceHash", func(blk *Block) { 109 blk.EvidenceHash = []byte("something else") 110 }, true}, 111 {"Incorrect block protocol version", func(blk *Block) { 112 blk.Version.Block = 1 113 }, true}, 114 {"Tampered ValidatorsHash", func(blk *Block) { 115 blk.ValidatorsHash = []byte("something else") 116 }, true}, 117 {"Tampered NextValidatorsHash", func(blk *Block) { 118 blk.NextValidatorsHash = []byte("something else") 119 }, true}, 120 {"Tampered ConsensusHash", func(blk *Block) { 121 blk.ConsensusHash = []byte("something else") 122 }, true}, 123 {"Tampered LastResultsHash", func(blk *Block) { 124 blk.LastResultsHash = []byte("something else") 125 }, true}, 126 {"Tampered LastBlockID", func(blk *Block) { 127 blk.LastBlockID = BlockID{Hash: []byte("something else")} 128 }, true}, 129 {"Negative Round", func(blk *Block) { 130 blk.Round = -1 131 }, true}, 132 {"Incorrect Proof Size", func(blk *Block) { 133 blk.Proof = []byte("wrong proof size") 134 }, true}, 135 } 136 for i, tc := range testCases { 137 tc := tc 138 i := i 139 t.Run(tc.testName, func(t *testing.T) { 140 block := MakeBlock(h, txs, commit, evList, TestConsensusVersion) 141 round := int32(0) 142 block.ProposerAddress = valSet.SelectProposer([]byte{}, block.Height, round).Address 143 proof := make([]byte, vrf.ProofSize) 144 block.Entropy.Populate(round, proof) 145 tc.malleateBlock(block) 146 err = block.ValidateBasic() 147 assert.Equal(t, tc.expErr, err != nil, "#%d: %v", i, err) 148 }) 149 } 150 } 151 152 func TestBlockHash(t *testing.T) { 153 assert.Nil(t, (*Block)(nil).Hash()) 154 assert.Nil(t, MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, TestConsensusVersion).Hash()) 155 } 156 157 func TestBlockMakePartSet(t *testing.T) { 158 assert.Nil(t, (*Block)(nil).MakePartSet(2)) 159 160 partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, TestConsensusVersion).MakePartSet(1024) 161 assert.NotNil(t, partSet) 162 assert.EqualValues(t, 1, partSet.Total()) 163 } 164 165 func TestBlockMakePartSetWithEvidence(t *testing.T) { 166 assert.Nil(t, (*Block)(nil).MakePartSet(2)) 167 168 lastID := makeBlockIDRandom() 169 h := int64(3) 170 171 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 172 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 173 require.NoError(t, err) 174 175 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 176 evList := []Evidence{ev} 177 178 block := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList, TestConsensusVersion) 179 blockProto, err := block.ToProto() 180 assert.NoError(t, err) 181 bz, err := blockProto.Marshal() 182 assert.NoError(t, err) 183 blockSize := len(bz) 184 partSet := block.MakePartSet(512) 185 assert.NotNil(t, partSet) 186 assert.Equal(t, uint32(math.Ceil(float64(blockSize)/512.0)), partSet.Total()) 187 } 188 189 func TestBlockHashesTo(t *testing.T) { 190 assert.False(t, (*Block)(nil).HashesTo(nil)) 191 192 lastID := makeBlockIDRandom() 193 h := int64(3) 194 voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 195 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 196 require.NoError(t, err) 197 198 ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") 199 evList := []Evidence{ev} 200 201 block := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList, TestConsensusVersion) 202 block.ValidatorsHash = valSet.Hash() 203 assert.False(t, block.HashesTo([]byte{})) 204 assert.False(t, block.HashesTo([]byte("something else"))) 205 assert.True(t, block.HashesTo(block.Hash())) 206 } 207 208 func TestBlockSize(t *testing.T) { 209 size := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, TestConsensusVersion).Size() 210 if size <= 0 { 211 t.Fatal("Size of the block is zero or negative") 212 } 213 } 214 215 func TestBlockString(t *testing.T) { 216 assert.Equal(t, "nil-Block", (*Block)(nil).String()) 217 assert.Equal(t, "nil-Block", (*Block)(nil).StringIndented("")) 218 assert.Equal(t, "nil-Block", (*Block)(nil).StringShort()) 219 220 block := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, TestConsensusVersion) 221 assert.NotEqual(t, "nil-Block", block.String()) 222 assert.NotEqual(t, "nil-Block", block.StringIndented("")) 223 assert.NotEqual(t, "nil-Block", block.StringShort()) 224 } 225 226 func makeBlockIDRandom() BlockID { 227 var ( 228 blockHash = make([]byte, tmhash.Size) 229 partSetHash = make([]byte, tmhash.Size) 230 ) 231 rand.Read(blockHash) //nolint: errcheck // ignore errcheck for read 232 rand.Read(partSetHash) //nolint: errcheck // ignore errcheck for read 233 return BlockID{blockHash, PartSetHeader{123, partSetHash}} 234 } 235 236 func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) BlockID { 237 var ( 238 h = make([]byte, tmhash.Size) 239 psH = make([]byte, tmhash.Size) 240 ) 241 copy(h, hash) 242 copy(psH, partSetHash) 243 return BlockID{ 244 Hash: h, 245 PartSetHeader: PartSetHeader{ 246 Total: partSetSize, 247 Hash: psH, 248 }, 249 } 250 } 251 252 var nilBytes []byte 253 254 // This follows RFC-6962, i.e. `echo -n ” | sha256sum` 255 var emptyBytes = []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 256 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 257 0x78, 0x52, 0xb8, 0x55} 258 259 func TestNilHeaderHashDoesntCrash(t *testing.T) { 260 assert.Equal(t, nilBytes, []byte((*Header)(nil).Hash())) 261 assert.Equal(t, nilBytes, []byte((new(Header)).Hash())) 262 } 263 264 func TestNilDataHashDoesntCrash(t *testing.T) { 265 assert.Equal(t, emptyBytes, []byte((*Data)(nil).Hash())) 266 assert.Equal(t, emptyBytes, []byte(new(Data).Hash())) 267 } 268 269 func TestCommit(t *testing.T) { 270 lastID := makeBlockIDRandom() 271 h := int64(3) 272 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 273 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 274 require.NoError(t, err) 275 276 assert.Equal(t, h-1, commit.Height) 277 assert.EqualValues(t, 1, commit.Round) 278 assert.Equal(t, tmproto.PrecommitType, tmproto.SignedMsgType(commit.Type())) 279 if commit.Size() <= 0 { 280 t.Fatalf("commit %v has a zero or negative size: %d", commit, commit.Size()) 281 } 282 283 require.NotNil(t, commit.BitArray()) 284 assert.Equal(t, bits.NewBitArray(10).Size(), commit.BitArray().Size()) 285 286 assert.Equal(t, voteSet.GetByIndex(0), commit.GetByIndex(0)) 287 assert.True(t, commit.IsCommit()) 288 } 289 290 func TestCommitValidateBasic(t *testing.T) { 291 testCases := []struct { 292 testName string 293 malleateCommit func(*Commit) 294 expectErr bool 295 }{ 296 {"Random Commit", func(com *Commit) {}, false}, 297 {"Incorrect signature", func(com *Commit) { com.Signatures[0].Signature = []byte{0} }, false}, 298 {"Incorrect height", func(com *Commit) { com.Height = int64(-100) }, true}, 299 {"Incorrect round", func(com *Commit) { com.Round = -100 }, true}, 300 } 301 for _, tc := range testCases { 302 tc := tc 303 t.Run(tc.testName, func(t *testing.T) { 304 com := randCommit(time.Now()) 305 tc.malleateCommit(com) 306 assert.Equal(t, tc.expectErr, com.ValidateBasic() != nil, "Validate Basic had an unexpected result") 307 }) 308 } 309 } 310 311 func TestMaxCommitBytes(t *testing.T) { 312 // time is varint encoded so need to pick the max. 313 // year int, month Month, day, hour, min, sec, nsec int, loc *Location 314 timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) 315 316 cs := CommitSig{ 317 BlockIDFlag: BlockIDFlagNil, 318 ValidatorAddress: crypto.AddressHash([]byte("validator_address")), 319 Timestamp: timestamp, 320 Signature: crypto.CRandBytes(MaxSignatureSize), 321 } 322 323 pbSig := cs.ToProto() 324 // test that a single commit sig doesn't exceed max commit sig bytes 325 assert.EqualValues(t, MaxCommitSigBytes, int64(pbSig.Size())) 326 327 // check size with a single commit 328 commit := &Commit{ 329 Height: math.MaxInt64, 330 Round: math.MaxInt32, 331 BlockID: BlockID{ 332 Hash: tmhash.Sum([]byte("blockID_hash")), 333 PartSetHeader: PartSetHeader{ 334 Total: math.MaxUint32, 335 Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")), 336 }, 337 }, 338 Signatures: []CommitSig{cs}, 339 } 340 341 pb := commit.ToProto() 342 343 assert.EqualValues(t, MaxCommitBytes(1), int64(pb.Size())) 344 345 // check the upper bound of the commit size 346 for i := 1; i < MaxVotesCount; i++ { 347 commit.Signatures = append(commit.Signatures, cs) 348 } 349 350 pb = commit.ToProto() 351 352 assert.EqualValues(t, MaxCommitBytes(MaxVotesCount), int64(pb.Size())) 353 } 354 355 func TestCommitHash(t *testing.T) { 356 t.Run("receiver is nil", func(t *testing.T) { 357 var commit *Commit 358 assert.Nil(t, commit.Hash()) 359 }) 360 361 t.Run("without any signatures", func(t *testing.T) { 362 commit := &Commit{ 363 hash: nil, 364 Signatures: nil, 365 } 366 expected := []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 367 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55} 368 assert.Equal(t, expected, commit.Hash().Bytes()) 369 }) 370 371 t.Run("with signatures", func(t *testing.T) { 372 signature := []byte{0, 0, 0, 0} 373 address := []byte{0, 0, 0, 0} 374 tm := time.Unix(0, 0) 375 commit := &Commit{ 376 hash: nil, 377 Signatures: []CommitSig{ 378 NewCommitSigAbsent(), 379 NewCommitSigForBlock(signature, address, tm), 380 }, 381 } 382 expected := []byte{0xf9, 0x3c, 0x17, 0x4b, 0x5c, 0x27, 0x56, 0xef, 0x81, 0x7a, 0x43, 0x83, 0x63, 0x15, 0x60, 383 0x84, 0xc1, 0x3d, 0x6, 0x10, 0xfd, 0x94, 0xb9, 0x5d, 0xb0, 0x46, 0xbb, 0x11, 0x1d, 0x6c, 0x65, 0x2a} 384 assert.Equal(t, expected, commit.Hash().Bytes()) 385 386 commit.hash = nil 387 expected = []byte{0xf9, 0x3c, 0x17, 0x4b, 0x5c, 0x27, 0x56, 0xef, 0x81, 0x7a, 0x43, 0x83, 0x63, 0x15, 0x60, 388 0x84, 0xc1, 0x3d, 0x6, 0x10, 0xfd, 0x94, 0xb9, 0x5d, 0xb0, 0x46, 0xbb, 0x11, 0x1d, 0x6c, 0x65, 0x2a} 389 assert.Equal(t, expected, commit.Hash().Bytes()) 390 }) 391 } 392 393 func TestHeaderHash(t *testing.T) { 394 testCases := []struct { 395 desc string 396 header *Header 397 expectHash bytes.HexBytes 398 }{ 399 {"Generates expected hash", &Header{ 400 Version: tmversion.Consensus{Block: 1, App: 2}, 401 ChainID: "chainId", 402 Height: 3, 403 Time: time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC), 404 LastBlockID: makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)), 405 LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), 406 DataHash: tmhash.Sum([]byte("data_hash")), 407 ValidatorsHash: tmhash.Sum([]byte("validators_hash")), 408 NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), 409 ConsensusHash: tmhash.Sum([]byte("consensus_hash")), 410 AppHash: tmhash.Sum([]byte("app_hash")), 411 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 412 EvidenceHash: tmhash.Sum([]byte("evidence_hash")), 413 ProposerAddress: crypto.AddressHash([]byte("proposer_address")), 414 }, hexBytesFromString("F740121F553B5418C3EFBD343C2DBFE9E007BB67B0D020A0741374BAB65242A4")}, 415 {"nil header yields nil", nil, nil}, 416 {"nil ValidatorsHash yields nil", &Header{ 417 Version: tmversion.Consensus{Block: 1, App: 2}, 418 ChainID: "chainId", 419 Height: 3, 420 Time: time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC), 421 LastBlockID: makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)), 422 LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), 423 DataHash: tmhash.Sum([]byte("data_hash")), 424 ValidatorsHash: nil, 425 NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), 426 ConsensusHash: tmhash.Sum([]byte("consensus_hash")), 427 AppHash: tmhash.Sum([]byte("app_hash")), 428 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 429 EvidenceHash: tmhash.Sum([]byte("evidence_hash")), 430 ProposerAddress: crypto.AddressHash([]byte("proposer_address")), 431 }, nil}, 432 } 433 for _, tc := range testCases { 434 tc := tc 435 t.Run(tc.desc, func(t *testing.T) { 436 assert.Equal(t, tc.expectHash, tc.header.Hash()) 437 438 // We also make sure that all fields are hashed in struct order, and that all 439 // fields in the test struct are non-zero. 440 if tc.header != nil && tc.expectHash != nil { 441 byteSlices := [][]byte{} 442 443 s := reflect.ValueOf(*tc.header) 444 for i := 0; i < s.NumField(); i++ { 445 f := s.Field(i) 446 447 assert.False(t, f.IsZero(), "Found zero-valued field %v", 448 s.Type().Field(i).Name) 449 450 switch f := f.Interface().(type) { 451 case int32, int64, bytes.HexBytes, []byte, string: 452 byteSlices = append(byteSlices, cdcEncode(f)) 453 case time.Time: 454 bz, err := gogotypes.StdTimeMarshal(f) 455 require.NoError(t, err) 456 byteSlices = append(byteSlices, bz) 457 case tmversion.Consensus: 458 bz, err := f.Marshal() 459 require.NoError(t, err) 460 byteSlices = append(byteSlices, bz) 461 case BlockID: 462 pbbi := f.ToProto() 463 bz, err := pbbi.Marshal() 464 require.NoError(t, err) 465 byteSlices = append(byteSlices, bz) 466 default: 467 t.Errorf("unknown type %T", f) 468 } 469 } 470 assert.Equal(t, 471 bytes.HexBytes(merkle.HashFromByteSlices(byteSlices)), tc.header.Hash()) 472 } 473 }) 474 } 475 } 476 477 func TestHeaderValidateBasic(t *testing.T) { 478 invalidHashLength := tmhash.Size - 1 479 480 testCases := []struct { 481 testName string 482 malleateHeader func(*Header) 483 expErr bool 484 }{ 485 {"Make Header", func(header *Header) {}, false}, 486 {"Incorrect block protocol version", func(header *Header) { 487 header.Version.Block = uint64(1) 488 }, true}, 489 {"Too long chainID", func(header *Header) { 490 header.ChainID = "long chainID" + strings.Repeat("-", MaxChainIDLen) 491 }, true}, 492 {"Negative Height", func(header *Header) { 493 header.Height = -1 494 }, true}, 495 {"Zero Height", func(header *Header) { 496 header.Height = 0 497 }, true}, 498 {"Invalid Last Block ID", func(header *Header) { 499 header.LastBlockID = BlockID{ 500 Hash: make([]byte, invalidHashLength), 501 PartSetHeader: PartSetHeader{ 502 Total: 6, 503 Hash: make([]byte, invalidHashLength), 504 }, 505 } 506 }, true}, 507 {"Invalid Last Commit Hash", func(header *Header) { 508 header.LastCommitHash = []byte(strings.Repeat("h", invalidHashLength)) 509 }, true}, 510 {"Invalid Data Hash", func(header *Header) { 511 header.DataHash = []byte(strings.Repeat("h", invalidHashLength)) 512 }, true}, 513 {"Invalid Evidence Hash", func(header *Header) { 514 header.EvidenceHash = []byte(strings.Repeat("h", invalidHashLength)) 515 }, true}, 516 {"Invalid Proposer Address length", func(header *Header) { 517 header.ProposerAddress = make([]byte, crypto.AddressSize-1) 518 }, true}, 519 {"Invalid Next Validators Hash", func(header *Header) { 520 header.NextValidatorsHash = []byte(strings.Repeat("h", invalidHashLength)) 521 }, true}, 522 {"Invalid Consensus Hash", func(header *Header) { 523 header.ConsensusHash = []byte(strings.Repeat("h", invalidHashLength)) 524 }, true}, 525 {"Invalid Results Hash", func(header *Header) { 526 header.LastResultsHash = []byte(strings.Repeat("h", invalidHashLength)) 527 }, true}, 528 {"Invalid Validators Hash", func(header *Header) { 529 header.ValidatorsHash = []byte(strings.Repeat("h", invalidHashLength)) 530 }, true}, 531 } 532 for i, tc := range testCases { 533 tc := tc 534 i := i 535 t.Run(tc.testName, func(t *testing.T) { 536 header := &Header{ 537 Version: tmversion.Consensus{Block: version.BlockProtocol, App: version.AppProtocol}, 538 ChainID: "chainId", 539 Height: 3, 540 Time: time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC), 541 LastBlockID: makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)), 542 LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), 543 DataHash: tmhash.Sum([]byte("data_hash")), 544 ValidatorsHash: tmhash.Sum([]byte("validators_hash")), 545 NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), 546 ConsensusHash: tmhash.Sum([]byte("consensus_hash")), 547 AppHash: tmhash.Sum([]byte("app_hash")), 548 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 549 EvidenceHash: tmhash.Sum([]byte("evidence_hash")), 550 ProposerAddress: crypto.AddressHash([]byte("proposer_address")), 551 } 552 tc.malleateHeader(header) 553 err := header.ValidateBasic() 554 assert.Equal(t, tc.expErr, err != nil, "#%d: %v", i, err) 555 }) 556 } 557 } 558 559 func TestMaxHeaderBytes(t *testing.T) { 560 // Construct a UTF-8 string of MaxChainIDLen length using the supplementary 561 // characters. 562 // Each supplementary character takes 4 bytes. 563 // http://www.i18nguy.com/unicode/supplementary-test.html 564 maxChainID := "" 565 for i := 0; i < MaxChainIDLen; i++ { 566 maxChainID += "𠜎" 567 } 568 569 // time is varint encoded so need to pick the max. 570 // year int, month Month, day, hour, min, sec, nsec int, loc *Location 571 timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) 572 573 proof := make([]byte, vrf.ProofSize) 574 for i := 0; i < len(proof); i++ { 575 proof[i] = 0xFF 576 } 577 578 h := Header{ 579 Version: tmversion.Consensus{Block: math.MaxInt64, App: math.MaxInt64}, 580 ChainID: maxChainID, 581 Height: math.MaxInt64, 582 Time: timestamp, 583 LastBlockID: makeBlockID(make([]byte, tmhash.Size), math.MaxInt32, make([]byte, tmhash.Size)), 584 LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), 585 DataHash: tmhash.Sum([]byte("data_hash")), 586 ValidatorsHash: tmhash.Sum([]byte("validators_hash")), 587 NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), 588 ConsensusHash: tmhash.Sum([]byte("consensus_hash")), 589 AppHash: tmhash.Sum([]byte("app_hash")), 590 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 591 EvidenceHash: tmhash.Sum([]byte("evidence_hash")), 592 ProposerAddress: crypto.AddressHash([]byte("proposer_address")), 593 } 594 595 bz, err := h.ToProto().Marshal() 596 require.NoError(t, err) 597 598 assert.EqualValues(t, MaxHeaderBytes, int64(len(bz))) 599 } 600 601 func randCommit(now time.Time) *Commit { 602 lastID := makeBlockIDRandom() 603 h := int64(3) 604 voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 605 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, now) 606 if err != nil { 607 panic(err) 608 } 609 return commit 610 } 611 612 func hexBytesFromString(s string) bytes.HexBytes { 613 b, err := hex.DecodeString(s) 614 if err != nil { 615 panic(err) 616 } 617 return bytes.HexBytes(b) 618 } 619 620 func TestBlockMaxDataBytes(t *testing.T) { 621 testCases := []struct { 622 maxBytes int64 623 valsCount int 624 evidenceBytes int64 625 panics bool 626 result int64 627 }{ 628 0: {-10, 1, 0, true, 0}, 629 1: {10, 1, 0, true, 0}, 630 2: {849 + int64(vrf.ProofSize), 1, 0, true, 0}, 631 3: {850 + int64(vrf.ProofSize), 1, 0, false, 0}, 632 4: {851 + int64(vrf.ProofSize), 1, 0, false, 1}, 633 5: {960 + int64(vrf.ProofSize), 2, 0, true, 0}, 634 6: {961 + int64(vrf.ProofSize), 2, 0, false, 0}, 635 7: {962 + int64(vrf.ProofSize), 2, 0, false, 1}, 636 8: {1060 + int64(vrf.ProofSize), 2, 100, true, 0}, 637 9: {1061 + int64(vrf.ProofSize), 2, 100, false, 0}, 638 10: {1062 + int64(vrf.ProofSize), 2, 100, false, 1}, 639 } 640 641 for i, tc := range testCases { 642 tc := tc 643 if tc.panics { 644 assert.Panics(t, func() { 645 MaxDataBytes(tc.maxBytes, tc.evidenceBytes, tc.valsCount) 646 }, "#%v", i) 647 } else { 648 assert.Equal(t, 649 tc.result, 650 MaxDataBytes(tc.maxBytes, tc.evidenceBytes, tc.valsCount), 651 "#%v", i) 652 } 653 } 654 } 655 656 func TestBlockMaxDataBytesNoEvidence(t *testing.T) { 657 testCases := []struct { 658 maxBytes int64 659 valsCount int 660 panics bool 661 result int64 662 }{ 663 0: {-10, 1, true, 0}, 664 1: {10, 1, true, 0}, 665 2: {849 + int64(vrf.ProofSize), 1, true, 0}, 666 3: {850 + int64(vrf.ProofSize), 1, false, 0}, 667 4: {851 + int64(vrf.ProofSize), 1, false, 1}, 668 5: {960 + int64(vrf.ProofSize), 2, true, 0}, 669 6: {961 + int64(vrf.ProofSize), 2, false, 0}, 670 7: {962 + int64(vrf.ProofSize), 2, false, 1}, 671 } 672 673 for i, tc := range testCases { 674 tc := tc 675 if tc.panics { 676 assert.Panics(t, func() { 677 MaxDataBytesNoEvidence(tc.maxBytes, tc.valsCount) 678 }, "#%v", i) 679 } else { 680 assert.NotPanics(t, func() { 681 MaxDataBytesNoEvidence(tc.maxBytes, tc.valsCount) 682 }, "#%v", i) 683 assert.Equal(t, 684 tc.result, 685 MaxDataBytesNoEvidence(tc.maxBytes, tc.valsCount), 686 "#%v", i) 687 } 688 } 689 } 690 691 func TestCommitToVoteSet(t *testing.T) { 692 lastID := makeBlockIDRandom() 693 h := int64(3) 694 695 voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1) 696 commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now()) 697 assert.NoError(t, err) 698 699 chainID := voteSet.ChainID() 700 voteSet2 := CommitToVoteSet(chainID, commit, valSet) 701 702 for i := int32(0); int(i) < len(vals); i++ { 703 // This is the vote before `MakeCommit`. 704 vote1 := voteSet.GetByIndex(i) 705 // This is the vote created from `CommitToVoteSet` 706 vote2 := voteSet2.GetByIndex(i) 707 // This is the vote created from `MakeCommit` 708 vote3 := commit.GetVote(i) 709 710 vote1bz, err := vote1.ToProto().Marshal() 711 require.NoError(t, err) 712 vote2bz, err := vote2.ToProto().Marshal() 713 require.NoError(t, err) 714 vote3bz, err := vote3.ToProto().Marshal() 715 require.NoError(t, err) 716 assert.Equal(t, vote1bz, vote2bz) 717 assert.Equal(t, vote1bz, vote3bz) 718 } 719 } 720 721 func TestCommitToVoteSetShouldPanicWhenInvalidVote(t *testing.T) { 722 voteSet, valSet, _ := randVoteSet(1, 1, tmproto.PrecommitType, 10, 1) 723 chainID := voteSet.ChainID() 724 commitWithInvalidVote := &Commit{ 725 Height: 1, 726 Signatures: []CommitSig{{ 727 BlockIDFlag: BlockIDFlagCommit, 728 }}, 729 } 730 731 assert.Panics(t, func() { 732 CommitToVoteSet(chainID, commitWithInvalidVote, valSet) 733 }) 734 } 735 736 func TestCommitToVoteSetWithVotesForNilBlock(t *testing.T) { 737 blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash")) 738 739 const ( 740 height = int64(3) 741 round = 0 742 ) 743 744 type commitVoteTest struct { 745 blockIDs []BlockID 746 numVotes []int // must sum to numValidators 747 numValidators int 748 valid bool 749 } 750 751 testCases := []commitVoteTest{ 752 {[]BlockID{blockID, {}}, []int{67, 33}, 100, true}, 753 } 754 755 for _, tc := range testCases { 756 voteSet, valSet, vals := randVoteSet(height-1, round, tmproto.PrecommitType, tc.numValidators, 1) 757 758 vi := int32(0) 759 for n := range tc.blockIDs { 760 for i := 0; i < tc.numVotes[n]; i++ { 761 pubKey, err := vals[vi].GetPubKey() 762 require.NoError(t, err) 763 vote := &Vote{ 764 ValidatorAddress: pubKey.Address(), 765 ValidatorIndex: vi, 766 Height: height - 1, 767 Round: round, 768 Type: tmproto.PrecommitType, 769 BlockID: tc.blockIDs[n], 770 Timestamp: tmtime.Now(), 771 } 772 773 added, err := signAddVote(vals[vi], vote, voteSet) 774 assert.NoError(t, err) 775 assert.True(t, added) 776 777 vi++ 778 } 779 } 780 781 if tc.valid { 782 commit := voteSet.MakeCommit() // panics without > 2/3 valid votes 783 assert.NotNil(t, commit) 784 err := valSet.VerifyCommit(voteSet.ChainID(), blockID, height-1, commit) 785 assert.Nil(t, err) 786 } else { 787 assert.Panics(t, func() { voteSet.MakeCommit() }) 788 } 789 } 790 } 791 792 func TestBlockIDValidateBasic(t *testing.T) { 793 validBlockID := BlockID{ 794 Hash: bytes.HexBytes{}, 795 PartSetHeader: PartSetHeader{ 796 Total: 1, 797 Hash: bytes.HexBytes{}, 798 }, 799 } 800 801 invalidBlockID := BlockID{ 802 Hash: []byte{0}, 803 PartSetHeader: PartSetHeader{ 804 Total: 1, 805 Hash: []byte{0}, 806 }, 807 } 808 809 testCases := []struct { 810 testName string 811 blockIDHash bytes.HexBytes 812 blockIDPartSetHeader PartSetHeader 813 expectErr bool 814 }{ 815 {"Valid BlockID", validBlockID.Hash, validBlockID.PartSetHeader, false}, 816 {"Invalid BlockID", invalidBlockID.Hash, validBlockID.PartSetHeader, true}, 817 {"Invalid BlockID", validBlockID.Hash, invalidBlockID.PartSetHeader, true}, 818 } 819 820 for _, tc := range testCases { 821 tc := tc 822 t.Run(tc.testName, func(t *testing.T) { 823 blockID := BlockID{ 824 Hash: tc.blockIDHash, 825 PartSetHeader: tc.blockIDPartSetHeader, 826 } 827 assert.Equal(t, tc.expectErr, blockID.ValidateBasic() != nil, "Validate Basic had an unexpected result") 828 }) 829 } 830 } 831 832 func TestBlockProtoBuf(t *testing.T) { 833 h := tmrand.Int63() 834 round := int32(0) 835 proof := make([]byte, vrf.ProofSize) 836 c1 := randCommit(time.Now()) 837 b1 := MakeBlock(h, []Tx{Tx([]byte{1})}, &Commit{Signatures: []CommitSig{}}, []Evidence{}, TestConsensusVersion) 838 b1.ProposerAddress = tmrand.Bytes(crypto.AddressSize) 839 b1.Entropy.Populate(round, proof) 840 841 b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{}, TestConsensusVersion) 842 b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize) 843 evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) 844 evi := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain") 845 b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}} 846 b2.EvidenceHash = b2.Evidence.Hash() 847 b2.Entropy.Populate(round, proof) 848 849 b3 := MakeBlock(h, []Tx{}, c1, []Evidence{}, TestConsensusVersion) 850 b3.ProposerAddress = tmrand.Bytes(crypto.AddressSize) 851 b3.Entropy.Populate(round, proof) 852 testCases := []struct { 853 msg string 854 b1 *Block 855 expPass bool 856 expPass2 bool 857 }{ 858 {"nil block", nil, false, false}, 859 {"b1", b1, true, true}, 860 {"b2", b2, true, true}, 861 {"b3", b3, true, true}, 862 } 863 for _, tc := range testCases { 864 pb, err := tc.b1.ToProto() 865 if tc.expPass { 866 require.NoError(t, err, tc.msg) 867 } else { 868 require.Error(t, err, tc.msg) 869 } 870 871 block, err := BlockFromProto(pb) 872 if tc.expPass2 { 873 require.NoError(t, err, tc.msg) 874 require.EqualValues(t, tc.b1.Header, block.Header, tc.msg) 875 require.EqualValues(t, tc.b1.Data, block.Data, tc.msg) 876 require.EqualValues(t, tc.b1.Evidence.Evidence, block.Evidence.Evidence, tc.msg) 877 require.EqualValues(t, *tc.b1.LastCommit, *block.LastCommit, tc.msg) 878 require.EqualValues(t, tc.b1.Entropy, block.Entropy, tc.msg) 879 } else { 880 require.Error(t, err, tc.msg) 881 } 882 } 883 } 884 885 func TestDataProtoBuf(t *testing.T) { 886 data := &Data{Txs: Txs{Tx([]byte{1}), Tx([]byte{2}), Tx([]byte{3})}} 887 data2 := &Data{Txs: Txs{}} 888 testCases := []struct { 889 msg string 890 data1 *Data 891 expPass bool 892 }{ 893 {"success", data, true}, 894 {"success data2", data2, true}, 895 } 896 for _, tc := range testCases { 897 protoData := tc.data1.ToProto() 898 d, err := DataFromProto(&protoData) 899 if tc.expPass { 900 require.NoError(t, err, tc.msg) 901 require.EqualValues(t, tc.data1, &d, tc.msg) 902 } else { 903 require.Error(t, err, tc.msg) 904 } 905 } 906 } 907 908 // TestEvidenceDataProtoBuf ensures parity in converting to and from proto. 909 func TestEvidenceDataProtoBuf(t *testing.T) { 910 const chainID = "mychain" 911 ev := NewMockDuplicateVoteEvidence(math.MaxInt64, time.Now(), chainID) 912 data := &EvidenceData{Evidence: EvidenceList{ev}} 913 _ = data.ByteSize() 914 testCases := []struct { 915 msg string 916 data1 *EvidenceData 917 expPass1 bool 918 expPass2 bool 919 }{ 920 {"success", data, true, true}, 921 {"empty evidenceData", &EvidenceData{Evidence: EvidenceList{}}, true, true}, 922 {"fail nil Data", nil, false, false}, 923 } 924 925 for _, tc := range testCases { 926 protoData, err := tc.data1.ToProto() 927 if tc.expPass1 { 928 require.NoError(t, err, tc.msg) 929 } else { 930 require.Error(t, err, tc.msg) 931 } 932 933 eviD := new(EvidenceData) 934 err = eviD.FromProto(protoData) 935 if tc.expPass2 { 936 require.NoError(t, err, tc.msg) 937 require.Equal(t, tc.data1, eviD, tc.msg) 938 } else { 939 require.Error(t, err, tc.msg) 940 } 941 } 942 } 943 944 func makeRandHeader() Header { 945 chainID := "test" 946 t := time.Now() 947 height := tmrand.Int63() 948 randBytes := tmrand.Bytes(tmhash.Size) 949 randAddress := tmrand.Bytes(crypto.AddressSize) 950 h := Header{ 951 Version: tmversion.Consensus{Block: version.BlockProtocol, App: version.AppProtocol}, 952 ChainID: chainID, 953 Height: height, 954 Time: t, 955 LastBlockID: BlockID{}, 956 LastCommitHash: randBytes, 957 DataHash: randBytes, 958 ValidatorsHash: randBytes, 959 NextValidatorsHash: randBytes, 960 ConsensusHash: randBytes, 961 AppHash: randBytes, 962 963 LastResultsHash: randBytes, 964 965 EvidenceHash: randBytes, 966 ProposerAddress: randAddress, 967 } 968 969 return h 970 } 971 972 func TestHeaderProto(t *testing.T) { 973 h1 := makeRandHeader() 974 tc := []struct { 975 msg string 976 h1 *Header 977 expPass bool 978 }{ 979 {"success", &h1, true}, 980 {"failure empty Header", &Header{}, false}, 981 } 982 983 for _, tt := range tc { 984 tt := tt 985 t.Run(tt.msg, func(t *testing.T) { 986 pb := tt.h1.ToProto() 987 h, err := HeaderFromProto(pb) 988 if tt.expPass { 989 require.NoError(t, err, tt.msg) 990 require.Equal(t, tt.h1, &h, tt.msg) 991 } else { 992 require.Error(t, err, tt.msg) 993 } 994 995 }) 996 } 997 } 998 999 func TestBlockIDProtoBuf(t *testing.T) { 1000 blockID := makeBlockID([]byte("hash"), 2, []byte("part_set_hash")) 1001 testCases := []struct { 1002 msg string 1003 bid1 *BlockID 1004 expPass bool 1005 }{ 1006 {"success", &blockID, true}, 1007 {"success empty", &BlockID{}, true}, 1008 {"failure BlockID nil", nil, false}, 1009 } 1010 for _, tc := range testCases { 1011 protoBlockID := tc.bid1.ToProto() 1012 1013 bi, err := BlockIDFromProto(&protoBlockID) 1014 if tc.expPass { 1015 require.NoError(t, err) 1016 require.Equal(t, tc.bid1, bi, tc.msg) 1017 } else { 1018 require.NotEqual(t, tc.bid1, bi, tc.msg) 1019 } 1020 } 1021 } 1022 1023 func TestSignedHeaderProtoBuf(t *testing.T) { 1024 commit := randCommit(time.Now()) 1025 h := makeRandHeader() 1026 1027 sh := SignedHeader{Header: &h, Commit: commit} 1028 1029 testCases := []struct { 1030 msg string 1031 sh1 *SignedHeader 1032 expPass bool 1033 }{ 1034 {"empty SignedHeader 2", &SignedHeader{}, true}, 1035 {"success", &sh, true}, 1036 {"failure nil", nil, false}, 1037 } 1038 for _, tc := range testCases { 1039 protoSignedHeader := tc.sh1.ToProto() 1040 1041 sh, err := SignedHeaderFromProto(protoSignedHeader) 1042 1043 if tc.expPass { 1044 require.NoError(t, err, tc.msg) 1045 require.Equal(t, tc.sh1, sh, tc.msg) 1046 } else { 1047 require.Error(t, err, tc.msg) 1048 } 1049 } 1050 } 1051 1052 func TestBlockIDEquals(t *testing.T) { 1053 var ( 1054 blockID = makeBlockID([]byte("hash"), 2, []byte("part_set_hash")) 1055 blockIDDuplicate = makeBlockID([]byte("hash"), 2, []byte("part_set_hash")) 1056 blockIDDifferent = makeBlockID([]byte("different_hash"), 2, []byte("part_set_hash")) 1057 blockIDEmpty = BlockID{} 1058 ) 1059 1060 assert.True(t, blockID.Equals(blockIDDuplicate)) 1061 assert.False(t, blockID.Equals(blockIDDifferent)) 1062 assert.False(t, blockID.Equals(blockIDEmpty)) 1063 assert.True(t, blockIDEmpty.Equals(blockIDEmpty)) 1064 assert.False(t, blockIDEmpty.Equals(blockIDDifferent)) 1065 } 1066 1067 func TestEntropyHash(t *testing.T) { 1068 testCases := []struct { 1069 desc string 1070 entropy *Entropy 1071 expectHash bytes.HexBytes 1072 }{ 1073 {"Generates expected hash", &Entropy{ 1074 Round: 1, 1075 // The Proof defined here does not depend on the vrf ProofLength, 1076 // but it is a fixed value for the purpose of calculating the Hash value. 1077 Proof: tmhash.Sum([]byte("proof")), 1078 }, hexBytesFromString("3EEC62453202DEF45126D758F5DF58962147B358E7B135E19D4CDB79B0CDA5C7")}, 1079 {"nil entropy yields nil", nil, nil}, 1080 } 1081 for _, tc := range testCases { 1082 tc := tc 1083 t.Run(tc.desc, func(t *testing.T) { 1084 assert.Equal(t, tc.expectHash, tc.entropy.Hash()) 1085 1086 // We also make sure that all fields are hashed in struct order, and that all 1087 // fields in the test struct are non-zero. 1088 if tc.entropy != nil && tc.expectHash != nil { 1089 byteSlices := [][]byte{} 1090 1091 s := reflect.ValueOf(*tc.entropy) 1092 for i := 0; i < s.NumField(); i++ { 1093 f := s.Field(i) 1094 1095 assert.False(t, f.IsZero(), "Found zero-valued field %v", 1096 s.Type().Field(i).Name) 1097 1098 switch f := f.Interface().(type) { 1099 case int32, int64, bytes.HexBytes, []byte, string: 1100 byteSlices = append(byteSlices, cdcEncode(f)) 1101 case time.Time: 1102 bz, err := gogotypes.StdTimeMarshal(f) 1103 require.NoError(t, err) 1104 byteSlices = append(byteSlices, bz) 1105 case tmversion.Consensus: 1106 bz, err := f.Marshal() 1107 require.NoError(t, err) 1108 byteSlices = append(byteSlices, bz) 1109 case BlockID: 1110 pbbi := f.ToProto() 1111 bz, err := pbbi.Marshal() 1112 require.NoError(t, err) 1113 byteSlices = append(byteSlices, bz) 1114 default: 1115 t.Errorf("unknown type %T", f) 1116 } 1117 } 1118 assert.Equal(t, 1119 bytes.HexBytes(merkle.HashFromByteSlices(byteSlices)), tc.entropy.Hash()) 1120 } 1121 }) 1122 } 1123 } 1124 1125 func TestEntropyValidateBasic(t *testing.T) { 1126 testCases := []struct { 1127 testName string 1128 malleateEntropy func(*Entropy) 1129 expErr bool 1130 }{ 1131 {"Make Entropy", func(entropy *Entropy) {}, false}, 1132 {"Negative Round", func(entropy *Entropy) { 1133 entropy.Round = -1 1134 }, true}, 1135 {"Invalid Proof", func(entropy *Entropy) { 1136 entropy.Proof = make([]byte, vrf.ProofSize-1) 1137 }, true}, 1138 } 1139 for i, tc := range testCases { 1140 tc := tc 1141 i := i 1142 t.Run(tc.testName, func(t *testing.T) { 1143 header := &Entropy{ 1144 Round: 1, 1145 Proof: make([]byte, vrf.ProofSize), 1146 } 1147 tc.malleateEntropy(header) 1148 err := header.ValidateBasic() 1149 assert.Equal(t, tc.expErr, err != nil, "#%d: %v", i, err) 1150 }) 1151 } 1152 } 1153 1154 func TestMaxEntropyBytes(t *testing.T) { 1155 proof := make([]byte, vrf.ProofSize) 1156 for i := 0; i < len(proof); i++ { 1157 proof[i] = 0xFF 1158 } 1159 1160 h := Entropy{ 1161 Round: math.MaxInt32, 1162 Proof: proof, 1163 } 1164 1165 bz, err := h.ToProto().Marshal() 1166 require.NoError(t, err) 1167 1168 assert.EqualValues(t, MaxEntropyBytes, int64(len(bz))) 1169 } 1170 1171 func makeEntropyHeader() Entropy { 1172 round := tmrand.Int31() 1173 randProof := tmrand.Bytes(vrf.ProofSize) 1174 vp := Entropy{ 1175 Round: round, 1176 Proof: randProof, 1177 } 1178 1179 return vp 1180 } 1181 1182 func TestEntropyProto(t *testing.T) { 1183 vp1 := makeEntropyHeader() 1184 tc := []struct { 1185 msg string 1186 vp1 *Entropy 1187 expPass bool 1188 }{ 1189 {"success", &vp1, true}, 1190 {"failed empty Entropy", &Entropy{}, false}, 1191 } 1192 1193 for _, tt := range tc { 1194 tt := tt 1195 t.Run(tt.msg, func(t *testing.T) { 1196 pb := tt.vp1.ToProto() 1197 h, err := EntropyFromProto(pb) 1198 if tt.expPass { 1199 require.NoError(t, err, tt.msg) 1200 require.Equal(t, tt.vp1, &h, tt.msg) 1201 } else { 1202 require.Error(t, err, tt.msg) 1203 } 1204 1205 }) 1206 } 1207 } 1208 1209 func TestEntropyCorrectness(t *testing.T) { 1210 chainID := "test" 1211 height := int64(1) 1212 tx := []Tx{} 1213 evList := []Evidence{} 1214 commit := &Commit{} 1215 1216 round := int32(0) 1217 proof := []byte("proof") 1218 differentRound := round + 1 1219 differentProof := []byte("different proof") 1220 1221 testBlock := MakeBlock(height, tx, commit, evList, TestConsensusVersion) 1222 testBlock.Entropy.Populate(round, proof) 1223 testBlockId := BlockID{Hash: testBlock.Hash(), PartSetHeader: testBlock.MakePartSet(1024).Header()} 1224 1225 sameBlock := MakeBlock(height, tx, commit, evList, TestConsensusVersion) 1226 sameBlock.Entropy.Populate(round, proof) 1227 sameBlockId := BlockID{Hash: sameBlock.Hash(), PartSetHeader: sameBlock.MakePartSet(1024).Header()} 1228 1229 roundDiffBlock := MakeBlock(height, tx, commit, evList, TestConsensusVersion) 1230 roundDiffBlock.Entropy.Populate(differentRound, proof) 1231 roundDiffBlockId := BlockID{Hash: roundDiffBlock.Hash(), PartSetHeader: roundDiffBlock.MakePartSet(1024).Header()} 1232 1233 proofDiffBlock := MakeBlock(height, tx, commit, evList, TestConsensusVersion) 1234 proofDiffBlock.Entropy.Populate(round, differentProof) 1235 proofDiffBlockId := BlockID{Hash: proofDiffBlock.Hash(), PartSetHeader: proofDiffBlock.MakePartSet(1024).Header()} 1236 1237 entropyDiffBlock := MakeBlock(height, tx, commit, evList, TestConsensusVersion) 1238 entropyDiffBlock.Entropy.Populate(differentRound, differentProof) 1239 entropyDiffBlockId := BlockID{Hash: entropyDiffBlock.Hash(), PartSetHeader: entropyDiffBlock.MakePartSet(1024).Header()} 1240 1241 t.Run("test block id equality with different entropy", func(t *testing.T) { 1242 assert.Equal(t, testBlockId, sameBlockId) 1243 assert.NotEqual(t, testBlockId, roundDiffBlockId) 1244 assert.NotEqual(t, testBlockId, proofDiffBlockId) 1245 assert.NotEqual(t, testBlockId, entropyDiffBlockId) 1246 }) 1247 1248 t.Run("test vote signature verification with different entropy", func(t *testing.T) { 1249 _, privVals := RandValidatorSet(1, 1) 1250 privVal := privVals[0] 1251 pubKey, err := privVal.GetPubKey() 1252 assert.NoError(t, err) 1253 1254 testVote := &Vote{ 1255 ValidatorAddress: pubKey.Address(), 1256 ValidatorIndex: 0, 1257 Height: height, 1258 Round: 0, 1259 Timestamp: tmtime.Now(), 1260 Type: tmproto.PrecommitType, 1261 BlockID: testBlockId, 1262 } 1263 tv := testVote.ToProto() 1264 err = privVal.SignVote(chainID, tv) 1265 assert.NoError(t, err) 1266 testVote.Signature = tv.Signature 1267 1268 sameVote := testVote.Copy() 1269 sameVote.BlockID = sameBlockId 1270 1271 roundDiffVote := testVote.Copy() 1272 roundDiffVote.BlockID = roundDiffBlockId 1273 1274 proofDiffVote := testVote.Copy() 1275 proofDiffVote.BlockID = proofDiffBlockId 1276 1277 entropyDiffVote := testVote.Copy() 1278 entropyDiffVote.BlockID = entropyDiffBlockId 1279 1280 err = testVote.Verify(chainID, pubKey) 1281 assert.NoError(t, err) 1282 err = sameVote.Verify(chainID, pubKey) 1283 assert.NoError(t, err) 1284 err = roundDiffVote.Verify(chainID, pubKey) 1285 assert.Error(t, err) 1286 err = proofDiffVote.Verify(chainID, pubKey) 1287 assert.Error(t, err) 1288 err = entropyDiffVote.Verify(chainID, pubKey) 1289 assert.Error(t, err) 1290 }) 1291 }