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