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  }