diff --git a/types/block_test.go b/types/block_test.go index 1bf2a15ff..23ada58ec 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -4,8 +4,10 @@ import ( // it is ok to use math/rand here: we do not need a cryptographically secure random // number generator here and we can run the tests a bit faster "crypto/rand" + "encoding/hex" "math" "os" + "reflect" "testing" "time" @@ -13,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" cmn "github.com/tendermint/tendermint/libs/common" tmtime "github.com/tendermint/tendermint/types/time" @@ -240,6 +243,73 @@ func TestCommitValidateBasic(t *testing.T) { } } +func TestHeaderHash(t *testing.T) { + testCases := []struct { + desc string + header *Header + expectHash cmn.HexBytes + }{ + {"Generates expected hash", &Header{ + Version: version.Consensus{Block: 1, App: 2}, + ChainID: "chainId", + Height: 3, + Time: time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC), + NumTxs: 4, + TotalTxs: 5, + LastBlockID: makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)), + LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), + DataHash: tmhash.Sum([]byte("data_hash")), + ValidatorsHash: tmhash.Sum([]byte("validators_hash")), + NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), + ConsensusHash: tmhash.Sum([]byte("consensus_hash")), + AppHash: tmhash.Sum([]byte("app_hash")), + LastResultsHash: tmhash.Sum([]byte("last_results_hash")), + EvidenceHash: tmhash.Sum([]byte("evidence_hash")), + ProposerAddress: crypto.AddressHash([]byte("proposer_address")), + }, hexBytesFromString("A37A7A69D89D3A66D599B0914A53F959EFE490EE9B449C95852F6FB331D58D07")}, + {"nil header yields nil", nil, nil}, + {"nil ValidatorsHash yields nil", &Header{ + Version: version.Consensus{Block: 1, App: 2}, + ChainID: "chainId", + Height: 3, + Time: time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC), + NumTxs: 4, + TotalTxs: 5, + LastBlockID: makeBlockID(make([]byte, tmhash.Size), 6, make([]byte, tmhash.Size)), + LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), + DataHash: tmhash.Sum([]byte("data_hash")), + ValidatorsHash: nil, + NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), + ConsensusHash: tmhash.Sum([]byte("consensus_hash")), + AppHash: tmhash.Sum([]byte("app_hash")), + LastResultsHash: tmhash.Sum([]byte("last_results_hash")), + EvidenceHash: tmhash.Sum([]byte("evidence_hash")), + ProposerAddress: crypto.AddressHash([]byte("proposer_address")), + }, nil}, + } + for _, tc := range testCases { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + assert.Equal(t, tc.expectHash, tc.header.Hash()) + + // We also make sure that all fields are hashed in struct order, and that all + // fields in the test struct are non-zero. + if tc.header != nil && tc.expectHash != nil { + byteSlices := [][]byte{} + s := reflect.ValueOf(*tc.header) + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + assert.False(t, f.IsZero(), "Found zero-valued field %v", + s.Type().Field(i).Name) + byteSlices = append(byteSlices, cdcEncode(f.Interface())) + } + assert.Equal(t, + cmn.HexBytes(merkle.SimpleHashFromByteSlices(byteSlices)), tc.header.Hash()) + } + }) + } +} + func TestMaxHeaderBytes(t *testing.T) { // Construct a UTF-8 string of MaxChainIDLen length using the supplementary // characters. @@ -290,6 +360,14 @@ func randCommit() *Commit { return commit } +func hexBytesFromString(s string) cmn.HexBytes { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return cmn.HexBytes(b) +} + func TestBlockMaxDataBytes(t *testing.T) { testCases := []struct { maxBytes int64