Skip to content

Commit

Permalink
Reuse fast hasher in 'txSnapshotHasher'.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickeskov committed Dec 14, 2023
1 parent 40b0851 commit 62b45a6
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 18 deletions.
9 changes: 7 additions & 2 deletions pkg/state/appender.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,10 +726,15 @@ func (a *txAppender) appendBlock(params *appendBlockParams) error {
if err != nil {
return errors.Wrapf(err, "failed to get current block info, blockchain height is %d", params.blockchainHeight)
}
hasher := newTxSnapshotHasherDefault()
defer hasher.Release()

currentBlockHeight := blockInfo.Height

hasher, err := newTxSnapshotHasherDefault()
if err != nil {
return errors.Wrapf(err, "failed to create tx snapshot default hasher, block height is %d", currentBlockHeight)
}
defer hasher.Release()

// get initial snapshot hash for block
stateHash, err := calculateInitialSnapshotStateHash(
hasher,
Expand Down
32 changes: 18 additions & 14 deletions pkg/state/snapshot_hasher.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package state
import (
"bytes"
"encoding/binary"
"hash"
"sort"

"github.com/pkg/errors"
Expand Down Expand Up @@ -38,23 +39,29 @@ func (h hashEntries) Less(i, j int) bool { return bytes.Compare(h[i].data.B, h[j
func (h hashEntries) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

type txSnapshotHasher struct {
fastHasher hash.Hash
hashEntries hashEntries
blockHeight proto.Height
transactionID []byte
}

var _ = proto.SnapshotApplier((*txSnapshotHasher)(nil)) // use the same interface for applying and hashing

func newTxSnapshotHasherDefault() *txSnapshotHasher {
func newTxSnapshotHasherDefault() (*txSnapshotHasher, error) {
return newTxSnapshotHasher(0, nil)
}

func newTxSnapshotHasher(blockHeight proto.Height, transactionID []byte) *txSnapshotHasher {
func newTxSnapshotHasher(blockHeight proto.Height, transactionID []byte) (*txSnapshotHasher, error) {
fastHasher, err := crypto.NewFastHash()
if err != nil {
return nil, err
}
return &txSnapshotHasher{
fastHasher: fastHasher,
hashEntries: nil,
blockHeight: blockHeight,
transactionID: transactionID,
}
}, nil
}

func calculateTxSnapshotStateHash(
Expand Down Expand Up @@ -106,6 +113,7 @@ func (h *txSnapshotHasher) Release() {
h.hashEntries = h.hashEntries[:0]
h.blockHeight = 0
h.transactionID = nil
h.fastHasher.Reset()
}

// Reset releases the hasher and sets a new state.
Expand All @@ -116,33 +124,29 @@ func (h *txSnapshotHasher) Reset(blockHeight proto.Height, transactionID []byte)
}

func (h *txSnapshotHasher) CalculateHash(prevHash crypto.Digest) (crypto.Digest, error) {
defer h.fastHasher.Reset() // reset saved hasher
// scala node uses stable sort, thought it's unnecessary to use stable sort because:
// - every byte sequence is unique for each snapshot
// - if two byte sequences are equal then they are indistinguishable and order doesn't matter
sort.Sort(h.hashEntries)

fh, errH := crypto.NewFastHash()
if errH != nil {
return crypto.Digest{}, errors.Wrap(errH, "failed to create new fast blake2b hasher")
}

for i, entry := range h.hashEntries {
if _, err := fh.Write(entry.data.Bytes()); err != nil {
if _, err := h.fastHasher.Write(entry.data.Bytes()); err != nil {
return crypto.Digest{}, errors.Wrapf(err, "failed to write to hasher %d-th hash entry", i)
}
}
var txSnapshotsDigest crypto.Digest
fh.Sum(txSnapshotsDigest[:0])
h.fastHasher.Sum(txSnapshotsDigest[:0])

fh.Reset() // reuse the same hasher
if _, err := fh.Write(prevHash[:]); err != nil {
h.fastHasher.Reset() // reuse the same hasher
if _, err := h.fastHasher.Write(prevHash[:]); err != nil {
return crypto.Digest{}, errors.Wrapf(err, "failed to write to hasher previous tx state snapshot hash")
}
if _, err := fh.Write(txSnapshotsDigest[:]); err != nil {
if _, err := h.fastHasher.Write(txSnapshotsDigest[:]); err != nil {
return crypto.Digest{}, errors.Wrapf(err, "failed to write to hasher current tx snapshots hash")
}
var newHash crypto.Digest
fh.Sum(newHash[:0])
h.fastHasher.Sum(newHash[:0])

return newHash, nil
}
Expand Down
6 changes: 4 additions & 2 deletions pkg/state/snapshot_hasher_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ func TestTxSnapshotHasher(t *testing.T) {
},
}

hasher := newTxSnapshotHasherDefault()
hasher, hErr := newTxSnapshotHasherDefault()
require.NoError(t, hErr)
defer hasher.Release()

for _, testCase := range testCases {
Expand Down Expand Up @@ -215,7 +216,8 @@ func BenchmarkTxSnapshotHasher(b *testing.B) {
expectedHash, err := crypto.NewDigestFromBytes(expectedHashBytes)
require.NoError(b, err)

hasher := newTxSnapshotHasherDefault()
hasher, err := newTxSnapshotHasherDefault()
require.NoError(b, err)
defer hasher.Release()

b.ResetTimer()
Expand Down

0 comments on commit 62b45a6

Please sign in to comment.