From 500eef96c8c93a6d6a2103419fb3d4aca7d023ac Mon Sep 17 00:00:00 2001 From: Vadim Macagon Date: Wed, 30 Jan 2019 16:03:14 +0700 Subject: [PATCH] Make trie.Database.Commit() write out preimages in deterministic order Iteration order over db.preimages was not deterministic, sorting the batch contents when the batch is written wasn't enough to work around this if preimages didn't fit into a single batch. So now Commit() will pre-sort preimages to ensure their order is always deterministic, even when split across multiple batches. --- trie/database.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/trie/database.go b/trie/database.go index d0691b637e..7a755c043a 100644 --- a/trie/database.go +++ b/trie/database.go @@ -17,8 +17,10 @@ package trie import ( + "bytes" "fmt" "io" + "sort" "sync" "time" @@ -615,9 +617,26 @@ func (db *Database) Commit(node common.Hash, report bool) error { start := time.Now() batch := db.diskdb.NewBatch() + type kvPair struct { + key []byte + value []byte + } + + // Sort preimages to ensure they are written out in deterministic order + orderedPreimages := make([]kvPair, 0, len(db.preimages)) + for hash := range db.preimages { + orderedPreimages = append(orderedPreimages, kvPair{ + key: common.CopyBytes(hash[:]), + value: db.preimages[hash], + }) + } + sort.Slice(orderedPreimages, func(j, k int) bool { + return bytes.Compare(orderedPreimages[j].key, orderedPreimages[k].key) < 0 + }) + // Move all of the accumulated preimages into a write batch - for hash, preimage := range db.preimages { - if err := batch.Put(db.secureKey(hash[:]), preimage); err != nil { + for _, preimage := range orderedPreimages { + if err := batch.Put(db.secureKey(preimage.key), preimage.value); err != nil { log.Error("Failed to commit preimage from trie database", "err", err) db.lock.RUnlock() return err