github.com/DFWallet/tendermint-cosmos@v0.0.2/types/block_test.go (about)

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