diff --git a/header/header.go b/header/header.go index 4db80d0ac3..fe7df77616 100644 --- a/header/header.go +++ b/header/header.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "sync" "time" tmjson "github.com/tendermint/tendermint/libs/json" @@ -38,6 +39,9 @@ type ExtendedHeader struct { Commit *core.Commit `json:"commit"` ValidatorSet *core.ValidatorSet `json:"validator_set"` DAH *da.DataAvailabilityHeader `json:"dah"` + + hashOnce sync.Once + hash []byte } // MakeExtendedHeader assembles new ExtendedHeader. @@ -90,11 +94,13 @@ func (eh *ExtendedHeader) Time() time.Time { return eh.RawHeader.Time } -// Hash returns Hash of the wrapped RawHeader. -// NOTE: It purposely overrides Hash method of RawHeader to get it directly from Commit without -// recomputing. +// Hash returns Hash of the wrapped [RawHeader]. +// Value is cached to not be recomuted every call. func (eh *ExtendedHeader) Hash() libhead.Hash { - return eh.Commit.BlockID.Hash.Bytes() + eh.hashOnce.Do(func() { + eh.hash = eh.RawHeader.Hash() + }) + return eh.hash } // LastHeader returns the Hash of the last wrapped RawHeader. @@ -147,7 +153,7 @@ func (eh *ExtendedHeader) Validate() error { if eh.Commit.Height != eh.RawHeader.Height { return fmt.Errorf("header and commit height mismatch: %d vs %d", eh.RawHeader.Height, eh.Commit.Height) } - if hhash, chash := eh.RawHeader.Hash(), eh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) { + if hhash, chash := eh.Hash(), eh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) { return fmt.Errorf("commit signs block %X, header is block %X", chash, hhash) } @@ -223,7 +229,12 @@ func (eh *ExtendedHeader) UnmarshalBinary(data []byte) error { return err } - *eh = *out + *eh = ExtendedHeader{ + RawHeader: out.RawHeader, + Commit: out.Commit, + ValidatorSet: out.ValidatorSet, + DAH: out.DAH, + } return nil } diff --git a/header/headertest/verify_test.go b/header/headertest/verify_test.go index c55d810593..f1140f3601 100644 --- a/header/headertest/verify_test.go +++ b/header/headertest/verify_test.go @@ -30,7 +30,12 @@ func TestVerify(t *testing.T) { }, { prepare: func() *header.ExtendedHeader { - untrusted := *untrustedAdj + untrusted := header.ExtendedHeader{ + RawHeader: untrustedAdj.RawHeader, + Commit: untrustedAdj.Commit, + ValidatorSet: untrustedAdj.ValidatorSet, + DAH: untrustedAdj.DAH, + } untrusted.ValidatorsHash = tmrand.Bytes(32) return &untrusted }, @@ -38,7 +43,12 @@ func TestVerify(t *testing.T) { }, { prepare: func() *header.ExtendedHeader { - untrusted := *untrustedAdj + untrusted := header.ExtendedHeader{ + RawHeader: untrustedAdj.RawHeader, + Commit: untrustedAdj.Commit, + ValidatorSet: untrustedAdj.ValidatorSet, + DAH: untrustedAdj.DAH, + } untrusted.RawHeader.LastBlockID.Hash = tmrand.Bytes(32) return &untrusted }, @@ -46,7 +56,12 @@ func TestVerify(t *testing.T) { }, { prepare: func() *header.ExtendedHeader { - untrusted := *untrustedNonAdj + untrusted := header.ExtendedHeader{ + RawHeader: untrustedNonAdj.RawHeader, + Commit: untrustedNonAdj.Commit, + ValidatorSet: untrustedNonAdj.ValidatorSet, + DAH: untrustedNonAdj.DAH, + } untrusted.Commit = NewTestSuite(t, 2, 0).Commit(RandRawHeader(t)) return &untrusted },