github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/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  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/tendermint/tendermint/crypto"
    18  	"github.com/tendermint/tendermint/crypto/merkle"
    19  	"github.com/tendermint/tendermint/crypto/tmhash"
    20  	"github.com/tendermint/tendermint/libs/bits"
    21  	"github.com/tendermint/tendermint/libs/bytes"
    22  	tmrand "github.com/tendermint/tendermint/libs/rand"
    23  	tmtime "github.com/tendermint/tendermint/types/time"
    24  	"github.com/tendermint/tendermint/version"
    25  )
    26  
    27  func TestMain(m *testing.M) {
    28  	RegisterMockEvidences(cdc)
    29  
    30  	code := m.Run()
    31  	os.Exit(code)
    32  }
    33  
    34  func TestBlockAddEvidence(t *testing.T) {
    35  	txs := []Tx{Tx("foo"), Tx("bar")}
    36  	lastID := makeBlockIDRandom()
    37  	h := int64(3)
    38  
    39  	voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
    40  	commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
    41  	require.NoError(t, err)
    42  
    43  	ev := NewMockEvidence(h, time.Now(), 0, valSet.Validators[0].Address)
    44  	evList := []Evidence{ev}
    45  
    46  	block := MakeBlock(h, txs, commit, evList)
    47  	require.NotNil(t, block)
    48  	require.Equal(t, 1, len(block.Evidence.Evidence))
    49  	require.NotNil(t, block.EvidenceHash)
    50  }
    51  
    52  func TestBlockValidateBasic(t *testing.T) {
    53  	require.Error(t, (*Block)(nil).ValidateBasic())
    54  
    55  	txs := []Tx{Tx("foo"), Tx("bar")}
    56  	lastID := makeBlockIDRandom()
    57  	h := int64(3)
    58  
    59  	voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
    60  	commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
    61  	require.NoError(t, err)
    62  
    63  	ev := NewMockEvidence(h, time.Now(), 0, valSet.Validators[0].Address)
    64  	evList := []Evidence{ev}
    65  
    66  	testCases := []struct {
    67  		testName      string
    68  		malleateBlock func(*Block)
    69  		expErr        bool
    70  	}{
    71  		{"Make Block", func(blk *Block) {}, false},
    72  		{"Make Block w/ proposer Addr", func(blk *Block) { blk.ProposerAddress = valSet.GetProposer().Address }, false},
    73  		{"Negative Height", func(blk *Block) { blk.Height = -1 }, true},
    74  		{"Increase NumTxs", func(blk *Block) { blk.NumTxs++ }, true},
    75  		{"Remove 1/2 the commits", func(blk *Block) {
    76  			blk.LastCommit.Precommits = commit.Precommits[: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  	}
    91  	for i, tc := range testCases {
    92  		tc := tc
    93  		i := i
    94  		t.Run(tc.testName, func(t *testing.T) {
    95  			block := MakeBlock(h, txs, commit, evList)
    96  			block.ProposerAddress = valSet.GetProposer().Address
    97  			tc.malleateBlock(block)
    98  			err = block.ValidateBasic()
    99  			assert.Equal(t, tc.expErr, err != nil, "#%d: %v", i, err)
   100  		})
   101  	}
   102  }
   103  
   104  func TestBlockHash(t *testing.T) {
   105  	assert.Nil(t, (*Block)(nil).Hash())
   106  	assert.Nil(t, MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).Hash())
   107  }
   108  
   109  func TestBlockMakePartSet(t *testing.T) {
   110  	assert.Nil(t, (*Block)(nil).MakePartSet(2))
   111  
   112  	partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).MakePartSet(1024)
   113  	assert.NotNil(t, partSet)
   114  	assert.Equal(t, 1, partSet.Total())
   115  }
   116  
   117  func TestBlockMakePartSetWithEvidence(t *testing.T) {
   118  	assert.Nil(t, (*Block)(nil).MakePartSet(2))
   119  
   120  	lastID := makeBlockIDRandom()
   121  	h := int64(3)
   122  
   123  	voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
   124  	commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
   125  	require.NoError(t, err)
   126  
   127  	ev := NewMockEvidence(h, time.Now(), 0, valSet.Validators[0].Address)
   128  	evList := []Evidence{ev}
   129  
   130  	partSet := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(1024)
   131  	assert.NotNil(t, partSet)
   132  	assert.Equal(t, 3, partSet.Total())
   133  }
   134  
   135  func TestBlockHashesTo(t *testing.T) {
   136  	assert.False(t, (*Block)(nil).HashesTo(nil))
   137  
   138  	lastID := makeBlockIDRandom()
   139  	h := int64(3)
   140  	voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
   141  	commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
   142  	require.NoError(t, err)
   143  
   144  	ev := NewMockEvidence(h, time.Now(), 0, valSet.Validators[0].Address)
   145  	evList := []Evidence{ev}
   146  
   147  	block := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList)
   148  	block.ValidatorsHash = valSet.Hash()
   149  	assert.False(t, block.HashesTo([]byte{}))
   150  	assert.False(t, block.HashesTo([]byte("something else")))
   151  	assert.True(t, block.HashesTo(block.Hash()))
   152  }
   153  
   154  func TestBlockSize(t *testing.T) {
   155  	size := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).Size()
   156  	if size <= 0 {
   157  		t.Fatal("Size of the block is zero or negative")
   158  	}
   159  }
   160  
   161  func TestBlockString(t *testing.T) {
   162  	assert.Equal(t, "nil-Block", (*Block)(nil).String())
   163  	assert.Equal(t, "nil-Block", (*Block)(nil).StringIndented(""))
   164  	assert.Equal(t, "nil-Block", (*Block)(nil).StringShort())
   165  
   166  	block := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil)
   167  	assert.NotEqual(t, "nil-Block", block.String())
   168  	assert.NotEqual(t, "nil-Block", block.StringIndented(""))
   169  	assert.NotEqual(t, "nil-Block", block.StringShort())
   170  }
   171  
   172  func makeBlockIDRandom() BlockID {
   173  	var (
   174  		blockHash   = make([]byte, tmhash.Size)
   175  		partSetHash = make([]byte, tmhash.Size)
   176  	)
   177  	rand.Read(blockHash)   //nolint: gosec
   178  	rand.Read(partSetHash) //nolint: gosec
   179  	return BlockID{blockHash, PartSetHeader{123, partSetHash}}
   180  }
   181  
   182  func makeBlockID(hash []byte, partSetSize int, partSetHash []byte) BlockID {
   183  	var (
   184  		h   = make([]byte, tmhash.Size)
   185  		psH = make([]byte, tmhash.Size)
   186  	)
   187  	copy(h, hash)
   188  	copy(psH, partSetHash)
   189  	return BlockID{
   190  		Hash: h,
   191  		PartsHeader: PartSetHeader{
   192  			Total: partSetSize,
   193  			Hash:  psH,
   194  		},
   195  	}
   196  }
   197  
   198  var nilBytes []byte
   199  
   200  func TestNilHeaderHashDoesntCrash(t *testing.T) {
   201  	assert.Equal(t, []byte((*Header)(nil).Hash()), nilBytes)
   202  	assert.Equal(t, []byte((new(Header)).Hash()), nilBytes)
   203  }
   204  
   205  func TestNilDataHashDoesntCrash(t *testing.T) {
   206  	assert.Equal(t, []byte((*Data)(nil).Hash()), nilBytes)
   207  	assert.Equal(t, []byte(new(Data).Hash()), nilBytes)
   208  }
   209  
   210  func TestCommit(t *testing.T) {
   211  	lastID := makeBlockIDRandom()
   212  	h := int64(3)
   213  	voteSet, _, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
   214  	commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
   215  	require.NoError(t, err)
   216  
   217  	assert.Equal(t, h-1, commit.Height())
   218  	assert.Equal(t, 1, commit.Round())
   219  	assert.Equal(t, PrecommitType, SignedMsgType(commit.Type()))
   220  	if commit.Size() <= 0 {
   221  		t.Fatalf("commit %v has a zero or negative size: %d", commit, commit.Size())
   222  	}
   223  
   224  	require.NotNil(t, commit.BitArray())
   225  	assert.Equal(t, bits.NewBitArray(10).Size(), commit.BitArray().Size())
   226  
   227  	assert.Equal(t, voteSet.GetByIndex(0), commit.GetByIndex(0))
   228  	assert.True(t, commit.IsCommit())
   229  }
   230  
   231  func TestCommitValidateBasic(t *testing.T) {
   232  	testCases := []struct {
   233  		testName       string
   234  		malleateCommit func(*Commit)
   235  		expectErr      bool
   236  	}{
   237  		{"Random Commit", func(com *Commit) {}, false},
   238  		{"Nil precommit", func(com *Commit) { com.Precommits[0] = nil }, false},
   239  		{"Incorrect signature", func(com *Commit) { com.Precommits[0].Signature = []byte{0} }, false},
   240  		{"Incorrect type", func(com *Commit) { com.Precommits[0].Type = PrevoteType }, true},
   241  		{"Incorrect height", func(com *Commit) { com.Precommits[0].Height = int64(100) }, true},
   242  		{"Incorrect round", func(com *Commit) { com.Precommits[0].Round = 100 }, true},
   243  	}
   244  	for _, tc := range testCases {
   245  		tc := tc
   246  		t.Run(tc.testName, func(t *testing.T) {
   247  			com := randCommit(time.Now())
   248  			tc.malleateCommit(com)
   249  			assert.Equal(t, tc.expectErr, com.ValidateBasic() != nil, "Validate Basic had an unexpected result")
   250  		})
   251  	}
   252  }
   253  
   254  func TestHeaderHash(t *testing.T) {
   255  	testCases := []struct {
   256  		desc       string
   257  		header     *Header
   258  		expectHash bytes.HexBytes
   259  	}{
   260  		{"Generates expected hash", &Header{
   261  			Version:            version.Consensus{Block: 1, App: 2},
   262  			ChainID:            "chainId",
   263  			Height:             3,
   264  			Time:               time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC),
   265  			NumTxs:             4,
   266  			TotalTxs:           5,
   267  			LastBlockID:        makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)),
   268  			LastCommitHash:     tmhash.Sum([]byte("last_commit_hash")),
   269  			DataHash:           tmhash.Sum([]byte("data_hash")),
   270  			ValidatorsHash:     tmhash.Sum([]byte("validators_hash")),
   271  			NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")),
   272  			ConsensusHash:      tmhash.Sum([]byte("consensus_hash")),
   273  			AppHash:            tmhash.Sum([]byte("app_hash")),
   274  			LastResultsHash:    tmhash.Sum([]byte("last_results_hash")),
   275  			EvidenceHash:       tmhash.Sum([]byte("evidence_hash")),
   276  			ProposerAddress:    crypto.AddressHash([]byte("proposer_address")),
   277  		}, hexBytesFromString("A37A7A69D89D3A66D599B0914A53F959EFE490EE9B449C95852F6FB331D58D07")},
   278  		{"nil header yields nil", nil, nil},
   279  		{"nil ValidatorsHash yields nil", &Header{
   280  			Version:            version.Consensus{Block: 1, App: 2},
   281  			ChainID:            "chainId",
   282  			Height:             3,
   283  			Time:               time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC),
   284  			NumTxs:             4,
   285  			TotalTxs:           5,
   286  			LastBlockID:        makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)),
   287  			LastCommitHash:     tmhash.Sum([]byte("last_commit_hash")),
   288  			DataHash:           tmhash.Sum([]byte("data_hash")),
   289  			ValidatorsHash:     nil,
   290  			NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")),
   291  			ConsensusHash:      tmhash.Sum([]byte("consensus_hash")),
   292  			AppHash:            tmhash.Sum([]byte("app_hash")),
   293  			LastResultsHash:    tmhash.Sum([]byte("last_results_hash")),
   294  			EvidenceHash:       tmhash.Sum([]byte("evidence_hash")),
   295  			ProposerAddress:    crypto.AddressHash([]byte("proposer_address")),
   296  		}, nil},
   297  	}
   298  	for _, tc := range testCases {
   299  		tc := tc
   300  		t.Run(tc.desc, func(t *testing.T) {
   301  			assert.Equal(t, tc.expectHash, tc.header.Hash())
   302  
   303  			// We also make sure that all fields are hashed in struct order, and that all
   304  			// fields in the test struct are non-zero.
   305  			if tc.header != nil && tc.expectHash != nil {
   306  				byteSlices := [][]byte{}
   307  				s := reflect.ValueOf(*tc.header)
   308  				for i := 0; i < s.NumField(); i++ {
   309  					f := s.Field(i)
   310  					assert.False(t, f.IsZero(), "Found zero-valued field %v",
   311  						s.Type().Field(i).Name)
   312  					byteSlices = append(byteSlices, cdcEncode(f.Interface()))
   313  				}
   314  				assert.Equal(t,
   315  					bytes.HexBytes(merkle.SimpleHashFromByteSlices(byteSlices)), tc.header.Hash())
   316  			}
   317  		})
   318  	}
   319  }
   320  
   321  func TestMaxHeaderBytes(t *testing.T) {
   322  	// Construct a UTF-8 string of MaxChainIDLen length using the supplementary
   323  	// characters.
   324  	// Each supplementary character takes 4 bytes.
   325  	// http://www.i18nguy.com/unicode/supplementary-test.html
   326  	maxChainID := ""
   327  	for i := 0; i < MaxChainIDLen; i++ {
   328  		maxChainID += "𠜎"
   329  	}
   330  
   331  	// time is varint encoded so need to pick the max.
   332  	// year int, month Month, day, hour, min, sec, nsec int, loc *Location
   333  	timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
   334  
   335  	h := Header{
   336  		Version:            version.Consensus{Block: math.MaxInt64, App: math.MaxInt64},
   337  		ChainID:            maxChainID,
   338  		Height:             math.MaxInt64,
   339  		Time:               timestamp,
   340  		NumTxs:             math.MaxInt64,
   341  		TotalTxs:           math.MaxInt64,
   342  		LastBlockID:        makeBlockID(make([]byte, tmhash.Size), math.MaxInt64, make([]byte, tmhash.Size)),
   343  		LastCommitHash:     tmhash.Sum([]byte("last_commit_hash")),
   344  		DataHash:           tmhash.Sum([]byte("data_hash")),
   345  		ValidatorsHash:     tmhash.Sum([]byte("validators_hash")),
   346  		NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")),
   347  		ConsensusHash:      tmhash.Sum([]byte("consensus_hash")),
   348  		AppHash:            tmhash.Sum([]byte("app_hash")),
   349  		LastResultsHash:    tmhash.Sum([]byte("last_results_hash")),
   350  		EvidenceHash:       tmhash.Sum([]byte("evidence_hash")),
   351  		ProposerAddress:    crypto.AddressHash([]byte("proposer_address")),
   352  	}
   353  
   354  	bz, err := cdc.MarshalBinaryLengthPrefixed(h)
   355  	require.NoError(t, err)
   356  
   357  	assert.EqualValues(t, MaxHeaderBytes, int64(len(bz)))
   358  }
   359  
   360  func randCommit(now time.Time) *Commit {
   361  	lastID := makeBlockIDRandom()
   362  	h := int64(3)
   363  	voteSet, _, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
   364  	commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, now)
   365  	if err != nil {
   366  		panic(err)
   367  	}
   368  	commit.memoizeHeightRound()
   369  	return commit
   370  }
   371  
   372  func hexBytesFromString(s string) bytes.HexBytes {
   373  	b, err := hex.DecodeString(s)
   374  	if err != nil {
   375  		panic(err)
   376  	}
   377  	return bytes.HexBytes(b)
   378  }
   379  
   380  func TestBlockMaxDataBytes(t *testing.T) {
   381  	testCases := []struct {
   382  		maxBytes      int64
   383  		valsCount     int
   384  		evidenceCount int
   385  		panics        bool
   386  		result        int64
   387  	}{
   388  		0: {-10, 1, 0, true, 0},
   389  		1: {10, 1, 0, true, 0},
   390  		2: {886, 1, 0, true, 0},
   391  		3: {887, 1, 0, false, 0},
   392  		4: {888, 1, 0, false, 1},
   393  	}
   394  
   395  	for i, tc := range testCases {
   396  		tc := tc
   397  		if tc.panics {
   398  			assert.Panics(t, func() {
   399  				MaxDataBytes(tc.maxBytes, tc.valsCount, tc.evidenceCount)
   400  			}, "#%v", i)
   401  		} else {
   402  			assert.Equal(t,
   403  				tc.result,
   404  				MaxDataBytes(tc.maxBytes, tc.valsCount, tc.evidenceCount),
   405  				"#%v", i)
   406  		}
   407  	}
   408  }
   409  
   410  func TestBlockMaxDataBytesUnknownEvidence(t *testing.T) {
   411  	testCases := []struct {
   412  		maxBytes  int64
   413  		valsCount int
   414  		panics    bool
   415  		result    int64
   416  	}{
   417  		0: {-10, 1, true, 0},
   418  		1: {10, 1, true, 0},
   419  		2: {984, 1, true, 0},
   420  		3: {985, 1, false, 0},
   421  		4: {986, 1, false, 1},
   422  	}
   423  
   424  	for i, tc := range testCases {
   425  		tc := tc
   426  		if tc.panics {
   427  			assert.Panics(t, func() {
   428  				MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount)
   429  			}, "#%v", i)
   430  		} else {
   431  			assert.Equal(t,
   432  				tc.result,
   433  				MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount),
   434  				"#%v", i)
   435  		}
   436  	}
   437  }
   438  
   439  func TestCommitToVoteSet(t *testing.T) {
   440  	lastID := makeBlockIDRandom()
   441  	h := int64(3)
   442  
   443  	voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
   444  	commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
   445  	assert.NoError(t, err)
   446  
   447  	chainID := voteSet.ChainID()
   448  	voteSet2 := CommitToVoteSet(chainID, commit, valSet)
   449  
   450  	for i := 0; i < len(vals); i++ {
   451  		vote1 := voteSet.GetByIndex(i)
   452  		vote2 := voteSet2.GetByIndex(i)
   453  		vote3 := commit.GetVote(i)
   454  
   455  		vote1bz := cdc.MustMarshalBinaryBare(vote1)
   456  		vote2bz := cdc.MustMarshalBinaryBare(vote2)
   457  		vote3bz := cdc.MustMarshalBinaryBare(vote3)
   458  		assert.Equal(t, vote1bz, vote2bz)
   459  		assert.Equal(t, vote1bz, vote3bz)
   460  	}
   461  }
   462  
   463  func TestCommitToVoteSetWithVotesForNilBlock(t *testing.T) {
   464  	blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
   465  	blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
   466  	blockID3 := makeBlockID([]byte("blockhash3"), 10000, []byte("partshash"))
   467  
   468  	const (
   469  		height = int64(3)
   470  		round  = 0
   471  	)
   472  
   473  	type commitVoteTest struct {
   474  		blockIDs      []BlockID
   475  		numVotes      []int // must sum to numValidators
   476  		numValidators int
   477  		valid         bool
   478  	}
   479  
   480  	testCases := []commitVoteTest{
   481  		{[]BlockID{blockID, blockID2, blockID3}, []int{8, 1, 1}, 10, true},
   482  		{[]BlockID{blockID, blockID2, blockID3}, []int{67, 20, 13}, 100, true},
   483  		{[]BlockID{blockID, blockID2, blockID3}, []int{1, 1, 1}, 3, false},
   484  		{[]BlockID{blockID, blockID2, blockID3}, []int{3, 1, 1}, 5, false},
   485  		{[]BlockID{blockID, {}}, []int{67, 33}, 100, true},
   486  		{[]BlockID{blockID, blockID2, {}}, []int{10, 5, 5}, 20, false},
   487  	}
   488  
   489  	for _, tc := range testCases {
   490  		voteSet, valSet, vals := randVoteSet(height-1, round, PrecommitType, tc.numValidators, 1)
   491  
   492  		vi := 0
   493  		for n := range tc.blockIDs {
   494  			for i := 0; i < tc.numVotes[n]; i++ {
   495  				pubKey, err := vals[vi].GetPubKey()
   496  				require.NoError(t, err)
   497  				vote := &Vote{
   498  					ValidatorAddress: pubKey.Address(),
   499  					ValidatorIndex:   vi,
   500  					Height:           height - 1,
   501  					Round:            round,
   502  					Type:             PrecommitType,
   503  					BlockID:          tc.blockIDs[n],
   504  					Timestamp:        tmtime.Now(),
   505  				}
   506  
   507  				added, err := signAddVote(vals[vi], vote, voteSet)
   508  				assert.NoError(t, err)
   509  				assert.True(t, added)
   510  
   511  				vi++
   512  			}
   513  		}
   514  
   515  		if tc.valid {
   516  			commit := voteSet.MakeCommit() // panics without > 2/3 valid votes
   517  			assert.NotNil(t, commit)
   518  			err := valSet.VerifyCommit(voteSet.ChainID(), blockID, height-1, commit)
   519  			assert.Nil(t, err)
   520  		} else {
   521  			assert.Panics(t, func() { voteSet.MakeCommit() })
   522  		}
   523  	}
   524  }
   525  
   526  func TestSignedHeaderValidateBasic(t *testing.T) {
   527  	commit := randCommit(time.Now())
   528  	chainID := "𠜎"
   529  	timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
   530  	h := Header{
   531  		Version:            version.Consensus{Block: math.MaxInt64, App: math.MaxInt64},
   532  		ChainID:            chainID,
   533  		Height:             commit.Height(),
   534  		Time:               timestamp,
   535  		NumTxs:             math.MaxInt64,
   536  		TotalTxs:           math.MaxInt64,
   537  		LastBlockID:        commit.BlockID,
   538  		LastCommitHash:     commit.Hash(),
   539  		DataHash:           commit.Hash(),
   540  		ValidatorsHash:     commit.Hash(),
   541  		NextValidatorsHash: commit.Hash(),
   542  		ConsensusHash:      commit.Hash(),
   543  		AppHash:            commit.Hash(),
   544  		LastResultsHash:    commit.Hash(),
   545  		EvidenceHash:       commit.Hash(),
   546  		ProposerAddress:    crypto.AddressHash([]byte("proposer_address")),
   547  	}
   548  
   549  	validSignedHeader := SignedHeader{Header: &h, Commit: commit}
   550  	validSignedHeader.Commit.BlockID.Hash = validSignedHeader.Hash()
   551  	invalidSignedHeader := SignedHeader{}
   552  
   553  	testCases := []struct {
   554  		testName  string
   555  		shHeader  *Header
   556  		shCommit  *Commit
   557  		expectErr bool
   558  	}{
   559  		{"Valid Signed Header", validSignedHeader.Header, validSignedHeader.Commit, false},
   560  		{"Invalid Signed Header", invalidSignedHeader.Header, validSignedHeader.Commit, true},
   561  		{"Invalid Signed Header", validSignedHeader.Header, invalidSignedHeader.Commit, true},
   562  	}
   563  
   564  	for _, tc := range testCases {
   565  		tc := tc
   566  		t.Run(tc.testName, func(t *testing.T) {
   567  			sh := SignedHeader{
   568  				Header: tc.shHeader,
   569  				Commit: tc.shCommit,
   570  			}
   571  			assert.Equal(
   572  				t,
   573  				tc.expectErr,
   574  				sh.ValidateBasic(validSignedHeader.Header.ChainID) != nil,
   575  				"Validate Basic had an unexpected result",
   576  			)
   577  		})
   578  	}
   579  }
   580  
   581  func TestBlockIDValidateBasic(t *testing.T) {
   582  	validBlockID := BlockID{
   583  		Hash: bytes.HexBytes{},
   584  		PartsHeader: PartSetHeader{
   585  			Total: 1,
   586  			Hash:  bytes.HexBytes{},
   587  		},
   588  	}
   589  
   590  	invalidBlockID := BlockID{
   591  		Hash: []byte{0},
   592  		PartsHeader: PartSetHeader{
   593  			Total: -1,
   594  			Hash:  bytes.HexBytes{},
   595  		},
   596  	}
   597  
   598  	testCases := []struct {
   599  		testName           string
   600  		blockIDHash        bytes.HexBytes
   601  		blockIDPartsHeader PartSetHeader
   602  		expectErr          bool
   603  	}{
   604  		{"Valid BlockID", validBlockID.Hash, validBlockID.PartsHeader, false},
   605  		{"Invalid BlockID", invalidBlockID.Hash, validBlockID.PartsHeader, true},
   606  		{"Invalid BlockID", validBlockID.Hash, invalidBlockID.PartsHeader, true},
   607  	}
   608  
   609  	for _, tc := range testCases {
   610  		tc := tc
   611  		t.Run(tc.testName, func(t *testing.T) {
   612  			blockID := BlockID{
   613  				Hash:        tc.blockIDHash,
   614  				PartsHeader: tc.blockIDPartsHeader,
   615  			}
   616  			assert.Equal(t, tc.expectErr, blockID.ValidateBasic() != nil, "Validate Basic had an unexpected result")
   617  		})
   618  	}
   619  }
   620  
   621  func makeRandHeader() Header {
   622  	chainID := "test"
   623  	t := time.Now()
   624  	height := tmrand.Int63()
   625  	randBytes := tmrand.Bytes(tmhash.Size)
   626  	randAddress := tmrand.Bytes(crypto.AddressSize)
   627  	h := Header{
   628  		Version:            version.Consensus{Block: 1, App: 1},
   629  		ChainID:            chainID,
   630  		Height:             height,
   631  		Time:               t,
   632  		LastBlockID:        BlockID{},
   633  		LastCommitHash:     randBytes,
   634  		DataHash:           randBytes,
   635  		ValidatorsHash:     randBytes,
   636  		NextValidatorsHash: randBytes,
   637  		ConsensusHash:      randBytes,
   638  		AppHash:            randBytes,
   639  
   640  		LastResultsHash: randBytes,
   641  
   642  		EvidenceHash:    randBytes,
   643  		ProposerAddress: randAddress,
   644  	}
   645  
   646  	return h
   647  }
   648  
   649  func TestHeaderProto(t *testing.T) {
   650  	h1 := makeRandHeader()
   651  	tc := []struct {
   652  		msg     string
   653  		h1      *Header
   654  		expPass bool
   655  	}{
   656  		{"success", &h1, true},
   657  		{"failure empty Header", &Header{}, false},
   658  	}
   659  
   660  	for _, tt := range tc {
   661  		tt := tt
   662  		t.Run(tt.msg, func(t *testing.T) {
   663  			pb := tt.h1.ToProto()
   664  			h, err := HeaderFromProto(pb)
   665  			if tt.expPass {
   666  				require.NoError(t, err, tt.msg)
   667  				require.Equal(t, tt.h1, &h, tt.msg)
   668  			} else {
   669  				require.Error(t, err, tt.msg)
   670  			}
   671  
   672  		})
   673  	}
   674  }
   675  
   676  func TestBlockIDProtoBuf(t *testing.T) {
   677  	blockID := makeBlockID([]byte("hash"), 2, []byte("part_set_hash"))
   678  	testCases := []struct {
   679  		msg     string
   680  		bid1    *BlockID
   681  		expPass bool
   682  	}{
   683  		{"success", &blockID, true},
   684  		{"success empty", &BlockID{}, true},
   685  		{"failure BlockID nil", nil, false},
   686  	}
   687  	for _, tc := range testCases {
   688  		protoBlockID := tc.bid1.ToProto()
   689  
   690  		bi, err := BlockIDFromProto(&protoBlockID)
   691  		if tc.expPass {
   692  			require.NoError(t, err)
   693  			require.Equal(t, tc.bid1, bi, tc.msg)
   694  		} else {
   695  			require.NotEqual(t, tc.bid1, bi, tc.msg)
   696  		}
   697  	}
   698  }
   699  
   700  func TestSignedHeaderProtoBuf(t *testing.T) {
   701  	commit := randCommit(time.Now())
   702  	h := makeRandHeader()
   703  
   704  	sh := SignedHeader{Header: &h, Commit: commit}
   705  
   706  	testCases := []struct {
   707  		msg     string
   708  		sh1     *SignedHeader
   709  		expPass bool
   710  	}{
   711  		{"empty SignedHeader 2", &SignedHeader{}, true},
   712  		{"success", &sh, true},
   713  		{"failure nil", nil, false},
   714  	}
   715  	for _, tc := range testCases {
   716  		protoSignedHeader := tc.sh1.ToProto()
   717  
   718  		sh, err := SignedHeaderFromProto(protoSignedHeader)
   719  
   720  		if tc.expPass {
   721  			require.NoError(t, err, tc.msg)
   722  			require.Equal(t, tc.sh1, sh, tc.msg)
   723  		} else {
   724  			require.Error(t, err, tc.msg)
   725  		}
   726  	}
   727  }
   728  
   729  func TestCommitProtoBuf(t *testing.T) {
   730  	commit := randCommit(time.Now())
   731  
   732  	testCases := []struct {
   733  		msg     string
   734  		c1      *Commit
   735  		expPass bool
   736  	}{
   737  		{"success", commit, true},
   738  		// Empty value sets signatures to nil, signatures should not be nillable
   739  		{"empty commit", &Commit{Precommits: []*CommitSig{}}, true},
   740  		{"fail Commit nil", nil, false},
   741  	}
   742  	for _, tc := range testCases {
   743  		tc := tc
   744  		protoCommit := tc.c1.ToProto()
   745  
   746  		c, err := CommitFromProto(protoCommit)
   747  
   748  		if tc.expPass {
   749  			require.NoError(t, err, tc.msg)
   750  			require.Equal(t, tc.c1, c, tc.msg)
   751  		} else {
   752  			require.Error(t, err, tc.msg)
   753  		}
   754  	}
   755  }