From a5537627273e299d2e70dfda0350d049675fab1f Mon Sep 17 00:00:00 2001 From: suhasagg Date: Fri, 26 Jul 2019 14:18:07 +0530 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 d8a0fa9c53..452dbc7299 100644 --- a/trie/database.go +++ b/trie/database.go @@ -17,11 +17,13 @@ package trie import ( + "bytes" "encoding/binary" "errors" "fmt" "io" "reflect" + "sort" "sync" "time" @@ -705,9 +707,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) return err }