From 3cf646663524dbde38b4e6bc0eb0e0db5dbbe98e Mon Sep 17 00:00:00 2001 From: ledgerwatch <akhounov@gmail.com> Date: Sat, 16 May 2020 10:48:02 +0100 Subject: [PATCH] Separation of DB iterations from GenStructStep in the SubTrieLoader (#552) * Use stream type constants * More changes * Fixes * Diagnostics * go.mod * Fixes * Fixes * Tests * Fixes * Remove printf * Remove Current() from RetainList * Fix tests --- go.mod | 2 +- trie/flatdb_sub_trie_loader.go | 336 ++++++++++++++-------------- trie/flatdb_sub_trie_loader_test.go | 7 +- trie/retain_list.go | 15 +- trie/stream.go | 2 + trie/trie.go | 2 +- trie/witness_builder.go | 5 - 7 files changed, 183 insertions(+), 186 deletions(-) diff --git a/go.mod b/go.mod index 73582f17d4..bd22edb2af 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/dlclark/regexp2 v1.2.0 // indirect github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87 + github.com/dustin/go-humanize v1.0.0 github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa github.com/fatih/color v1.7.0 @@ -73,5 +74,4 @@ require ( gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9 - github.com/dustin/go-humanize v1.0.0 ) diff --git a/trie/flatdb_sub_trie_loader.go b/trie/flatdb_sub_trie_loader.go index f0f16a0327..1b5fa735dd 100644 --- a/trie/flatdb_sub_trie_loader.go +++ b/trie/flatdb_sub_trie_loader.go @@ -40,10 +40,9 @@ type FlatDbSubTrieLoader struct { hashData GenStructStepHashData trace bool - currStorage bytes.Buffer // Current key for the structure generation algorithm, as well as the input tape for the hash builder - succStorage bytes.Buffer - valueStorage bytes.Buffer // Current value to be used as the value tape for the hash builder - groupsStorage []uint16 + currStorage bytes.Buffer // Current key for the structure generation algorithm, as well as the input tape for the hash builder + succStorage bytes.Buffer + valueStorage bytes.Buffer // Current value to be used as the value tape for the hash builder witnessLenAccount uint64 witnessLenStorage uint64 @@ -54,31 +53,28 @@ type FlatDbSubTrieLoader struct { masks []byte cutoffs []int boltDB *bolt.DB - c *bolt.Cursor - ih *bolt.Cursor nextAccountKey [32]byte k, v []byte ihK, ihV []byte minKeyAsNibbles bytes.Buffer + itemPresent bool + itemType StreamItem getWitnessLen func(prefix []byte) uint64 // Storage item buffer - storageItemPresent bool - storageIsHash bool - storageKeyPart1 []byte - storageKeyPart2 []byte - storageHash []byte - storageValue []byte - storageWitnessLen uint64 + storageKeyPart1 []byte + storageKeyPart2 []byte + storageHash []byte + storageValue []byte + storageWitnessLen uint64 // Acount item buffer - accountItemPresent bool - accountIsHash bool - accountKey []byte - accountHash []byte - accountValue accounts.Account - accountWitnessLen uint64 + accountKey []byte + accountHash []byte + accountValue accounts.Account + streamCutoff int + accountWitnessLen uint64 } func NewFlatDbSubTrieLoader() *FlatDbSubTrieLoader { @@ -103,15 +99,13 @@ func (fstl *FlatDbSubTrieLoader) Reset(db ethdb.Database, rl RetainDecider, dbPr fstl.succStorage.Reset() fstl.valueStorage.Reset() fstl.minKeyAsNibbles.Reset() - fstl.groupsStorage = fstl.groupsStorage[:0] fstl.wasIHStorage = false fstl.subTries = SubTries{} fstl.trace = trace fstl.hb.trace = trace fstl.rl = rl fstl.dbPrefixes = dbPrefixes - fstl.storageItemPresent = false - fstl.accountItemPresent = false + fstl.itemPresent = false if fstl.trace { fmt.Printf("----------\n") fmt.Printf("RebuildTrie\n") @@ -148,7 +142,9 @@ func (fstl *FlatDbSubTrieLoader) Reset(db ethdb.Database, rl RetainDecider, dbPr return nil } -func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { +// iteration moves through the database buckets and creates at most +// one stream item, which is indicated by setting the field fstl.itemPresent to true +func (fstl *FlatDbSubTrieLoader) iteration(c, ih *bolt.Cursor, first bool) error { var isIH bool var minKey []byte if !first { @@ -156,94 +152,87 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { } fixedbytes := fstl.fixedbytes[fstl.rangeIdx] cutoff := fstl.cutoffs[fstl.rangeIdx] - if first || fixedbytes > 0 { - dbPrefix := fstl.dbPrefixes[fstl.rangeIdx] - mask := fstl.masks[fstl.rangeIdx] - // Adjust rangeIdx if needed - var cmp int = -1 - for cmp != 0 { - if minKey != nil { // In the first iteration, we do not have valid minKey, so we skip this part - if len(minKey) < fixedbytes { - cmp = bytes.Compare(minKey, dbPrefix[:len(minKey)]) - if cmp == 0 { - cmp = -1 - } - } else { - cmp = bytes.Compare(minKey[:fixedbytes-1], dbPrefix[:fixedbytes-1]) - if cmp == 0 { - k1 := minKey[fixedbytes-1] & mask - k2 := dbPrefix[fixedbytes-1] & mask - if k1 < k2 { - cmp = -1 - } else if k1 > k2 { - cmp = 1 - } - } - } + dbPrefix := fstl.dbPrefixes[fstl.rangeIdx] + mask := fstl.masks[fstl.rangeIdx] + // Adjust rangeIdx if needed + var cmp int = -1 + for cmp != 0 { + if minKey == nil { + if !first { + cmp = 1 } - if cmp < 0 { - // This happens after we have just incremented rangeIdx or on the very first iteration - if first && len(dbPrefix) > common.HashLength { - // Looking for storage sub-tree - copy(fstl.accAddrHashWithInc[:], dbPrefix[:common.HashLength+common.IncarnationLength]) + } else if fixedbytes > 0 { // In the first iteration, we do not have valid minKey, so we skip this part + if len(minKey) < fixedbytes { + cmp = bytes.Compare(minKey, dbPrefix[:len(minKey)]) + if cmp == 0 { + cmp = -1 } - fstl.k, fstl.v = fstl.c.SeekTo(dbPrefix) - if len(dbPrefix) <= common.HashLength && len(fstl.k) > common.HashLength { - // Advance past the storage to the first account - if nextAccount(fstl.k, fstl.nextAccountKey[:]) { - fstl.k, fstl.v = fstl.c.SeekTo(fstl.nextAccountKey[:]) - } else { - fstl.k = nil - } - } - fstl.ihK, fstl.ihV = fstl.ih.SeekTo(dbPrefix) - if len(dbPrefix) <= common.HashLength && len(fstl.ihK) > common.HashLength { - // Advance to the first account - if nextAccount(fstl.ihK, fstl.nextAccountKey[:]) { - fstl.ihK, fstl.ihV = fstl.ih.SeekTo(fstl.nextAccountKey[:]) - } else { - fstl.ihK = nil + } else { + cmp = bytes.Compare(minKey[:fixedbytes-1], dbPrefix[:fixedbytes-1]) + if cmp == 0 { + k1 := minKey[fixedbytes-1] & mask + k2 := dbPrefix[fixedbytes-1] & mask + if k1 < k2 { + cmp = -1 + } else if k1 > k2 { + cmp = 1 } } - if first { // This is enough for the first iteration - return nil - } - if fstl.k == nil && fstl.ihK == nil { - return nil - } - isIH, minKey = keyIsBefore(fstl.ihK, fstl.k) - } else if cmp > 0 { - if !first { - fstl.rangeIdx++ - } - if fstl.rangeIdx == len(fstl.dbPrefixes) { + } + } else { + cmp = 0 + } + if cmp == 0 && fstl.itemPresent { + return nil + } + if cmp < 0 { + // This happens after we have just incremented rangeIdx or on the very first iteration + if first && len(dbPrefix) > common.HashLength { + // Looking for storage sub-tree + copy(fstl.accAddrHashWithInc[:], dbPrefix[:common.HashLength+common.IncarnationLength]) + } + fstl.k, fstl.v = c.SeekTo(dbPrefix) + if len(dbPrefix) <= common.HashLength && len(fstl.k) > common.HashLength { + // Advance past the storage to the first account + if nextAccount(fstl.k, fstl.nextAccountKey[:]) { + fstl.k, fstl.v = c.SeekTo(fstl.nextAccountKey[:]) + } else { fstl.k = nil - fstl.ihK = nil - return nil } - if !first { - if err := fstl.finaliseRoot(cutoff); err != nil { - return err - } - } - fixedbytes = fstl.fixedbytes[fstl.rangeIdx] - mask = fstl.masks[fstl.rangeIdx] - dbPrefix = fstl.dbPrefixes[fstl.rangeIdx] - if len(dbPrefix) > common.HashLength { - // Looking for storage sub-tree - copy(fstl.accAddrHashWithInc[:], dbPrefix[:common.HashLength+common.IncarnationLength]) + } + fstl.ihK, fstl.ihV = ih.SeekTo(dbPrefix) + if len(dbPrefix) <= common.HashLength && len(fstl.ihK) > common.HashLength { + // Advance to the first account + if nextAccount(fstl.ihK, fstl.nextAccountKey[:]) { + fstl.ihK, fstl.ihV = ih.SeekTo(fstl.nextAccountKey[:]) + } else { + fstl.ihK = nil } - cutoff = fstl.cutoffs[fstl.rangeIdx] - fstl.hb.Reset() - fstl.wasIH = false - fstl.wasIHStorage = false - fstl.groups = fstl.groups[:0] - fstl.groupsStorage = fstl.groupsStorage[:0] - fstl.curr.Reset() - fstl.succ.Reset() - fstl.currStorage.Reset() - fstl.succStorage.Reset() } + isIH, minKey = keyIsBefore(fstl.ihK, fstl.k) + if fixedbytes == 0 { + cmp = 0 + } + } else if cmp > 0 { + if !first { + fstl.rangeIdx++ + } + if !first { + fstl.itemPresent = true + fstl.itemType = CutoffStreamItem + fstl.streamCutoff = cutoff + } + if fstl.rangeIdx == len(fstl.dbPrefixes) { + return nil + } + fixedbytes = fstl.fixedbytes[fstl.rangeIdx] + mask = fstl.masks[fstl.rangeIdx] + dbPrefix = fstl.dbPrefixes[fstl.rangeIdx] + if len(dbPrefix) > common.HashLength { + // Looking for storage sub-tree + copy(fstl.accAddrHashWithInc[:], dbPrefix[:common.HashLength+common.IncarnationLength]) + } + cutoff = fstl.cutoffs[fstl.rangeIdx] } } @@ -251,19 +240,19 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { if len(fstl.k) > common.HashLength && !bytes.HasPrefix(fstl.k, fstl.accAddrHashWithInc[:]) { if bytes.Compare(fstl.k, fstl.accAddrHashWithInc[:]) < 0 { // Skip all the irrelevant storage in the middle - fstl.k, fstl.v = fstl.c.SeekTo(fstl.accAddrHashWithInc[:]) + fstl.k, fstl.v = c.SeekTo(fstl.accAddrHashWithInc[:]) } else { if nextAccount(fstl.k, fstl.nextAccountKey[:]) { - fstl.k, fstl.v = fstl.c.SeekTo(fstl.nextAccountKey[:]) + fstl.k, fstl.v = c.SeekTo(fstl.nextAccountKey[:]) } else { fstl.k = nil } } return nil } + fstl.itemPresent = true if len(fstl.k) > common.HashLength { - fstl.storageItemPresent = true - fstl.storageIsHash = false + fstl.itemType = StorageStreamItem if len(fstl.k) >= common.HashLength { fstl.storageKeyPart1 = fstl.k[:common.HashLength] if len(fstl.k) >= common.HashLength+common.IncarnationLength { @@ -277,13 +266,12 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { } fstl.storageHash = nil fstl.storageValue = fstl.v - fstl.k, fstl.v = fstl.c.Next() + fstl.k, fstl.v = c.Next() if fstl.trace { fmt.Printf("k after storageWalker and Next: %x\n", fstl.k) } } else { - fstl.accountItemPresent = true - fstl.accountIsHash = false + fstl.itemType = AccountStreamItem fstl.accountKey = fstl.k fstl.accountHash = nil if err := fstl.accountValue.DecodeForStorage(fstl.v); err != nil { @@ -294,12 +282,12 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { // Now we know the correct incarnation of the account, and we can skip all irrelevant storage records // Since 0 incarnation if 0xfff...fff, and we do not expect any records like that, this automatically // skips over all storage items - fstl.k, fstl.v = fstl.c.SeekTo(fstl.accAddrHashWithInc[:]) + fstl.k, fstl.v = c.SeekTo(fstl.accAddrHashWithInc[:]) if fstl.trace { fmt.Printf("k after accountWalker and SeekTo: %x\n", fstl.k) } if !bytes.HasPrefix(fstl.ihK, fstl.accAddrHashWithInc[:]) { - fstl.ihK, fstl.ihV = fstl.ih.SeekTo(fstl.accAddrHashWithInc[:]) + fstl.ihK, fstl.ihV = ih.SeekTo(fstl.accAddrHashWithInc[:]) } } return nil @@ -310,7 +298,7 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { keyToNibblesWithoutInc(minKey, &fstl.minKeyAsNibbles) if fstl.minKeyAsNibbles.Len() < cutoff { - fstl.ihK, fstl.ihV = fstl.ih.Next() // go to children, not to sibling + fstl.ihK, fstl.ihV = ih.Next() // go to children, not to sibling return nil } @@ -320,26 +308,26 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { } if retain { // can't use ih as is, need go to children - fstl.ihK, fstl.ihV = fstl.ih.Next() // go to children, not to sibling + fstl.ihK, fstl.ihV = ih.Next() // go to children, not to sibling return nil } if len(fstl.ihK) > common.HashLength && !bytes.HasPrefix(fstl.ihK, fstl.accAddrHashWithInc[:]) { if bytes.Compare(fstl.ihK, fstl.accAddrHashWithInc[:]) < 0 { // Skip all the irrelevant storage in the middle - fstl.ihK, fstl.ihV = fstl.ih.SeekTo(fstl.accAddrHashWithInc[:]) + fstl.ihK, fstl.ihV = ih.SeekTo(fstl.accAddrHashWithInc[:]) } else { if nextAccount(fstl.ihK, fstl.nextAccountKey[:]) { - fstl.ihK, fstl.ihV = fstl.ih.SeekTo(fstl.nextAccountKey[:]) + fstl.ihK, fstl.ihV = ih.SeekTo(fstl.nextAccountKey[:]) } else { fstl.ihK = nil } } return nil } + fstl.itemPresent = true if len(fstl.ihK) > common.HashLength { - fstl.storageItemPresent = true - fstl.storageIsHash = true + fstl.itemType = SHashStreamItem if len(fstl.ihK) >= common.HashLength { fstl.storageKeyPart1 = fstl.ihK[:common.HashLength] if len(fstl.ihK) >= common.HashLength+common.IncarnationLength { @@ -355,8 +343,7 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { fstl.storageValue = nil fstl.storageWitnessLen = fstl.getWitnessLen(fstl.ihK) } else { - fstl.accountItemPresent = true - fstl.accountIsHash = true + fstl.itemType = AHashStreamItem fstl.accountKey = fstl.ihK fstl.accountHash = fstl.ihV fstl.accountWitnessLen = fstl.getWitnessLen(fstl.ihK) @@ -378,12 +365,12 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { } if !bytes.HasPrefix(fstl.k, next) { - fstl.k, fstl.v = fstl.c.SeekTo(next) + fstl.k, fstl.v = c.SeekTo(next) } if len(next) <= common.HashLength && len(fstl.k) > common.HashLength { // Advance past the storage to the first account if nextAccount(fstl.k, fstl.nextAccountKey[:]) { - fstl.k, fstl.v = fstl.c.SeekTo(fstl.nextAccountKey[:]) + fstl.k, fstl.v = c.SeekTo(fstl.nextAccountKey[:]) } else { fstl.k = nil } @@ -392,12 +379,12 @@ func (fstl *FlatDbSubTrieLoader) iteration(first bool) error { fmt.Printf("k after next: %x\n", fstl.k) } if !bytes.HasPrefix(fstl.ihK, next) { - fstl.ihK, fstl.ihV = fstl.ih.SeekTo(next) + fstl.ihK, fstl.ihV = ih.SeekTo(next) } if len(next) <= common.HashLength && len(fstl.ihK) > common.HashLength { // Advance past the storage to the first account if nextAccount(fstl.ihK, fstl.nextAccountKey[:]) { - fstl.ihK, fstl.ihV = fstl.ih.SeekTo(fstl.nextAccountKey[:]) + fstl.ihK, fstl.ihV = ih.SeekTo(fstl.nextAccountKey[:]) } else { fstl.ihK = nil } @@ -469,11 +456,24 @@ func (fstl *FlatDbSubTrieLoader) finaliseRoot(cutoff int) error { if fstl.groups, err = GenStructStep(fstl.rl.Retain, fstl.curr.Bytes(), fstl.succ.Bytes(), fstl.hb, data, fstl.groups, false); err != nil { return err } + if len(fstl.groups) > cutoff { + fstl.groups = fstl.groups[:cutoff] + } + for len(fstl.groups) > 0 && fstl.groups[len(fstl.groups)-1] == 0 { + fstl.groups = fstl.groups[:len(fstl.groups)-1] + } fstl.accData.FieldSet = 0 } - fstl.groups = fstl.groups[:0] fstl.subTries.roots = append(fstl.subTries.roots, fstl.hb.root()) fstl.subTries.Hashes = append(fstl.subTries.Hashes, fstl.hb.rootHash()) + fstl.groups = fstl.groups[:0] + fstl.hb.Reset() + fstl.wasIH = false + fstl.wasIHStorage = false + fstl.curr.Reset() + fstl.succ.Reset() + fstl.currStorage.Reset() + fstl.succStorage.Reset() return nil } @@ -504,11 +504,16 @@ func (fstl *FlatDbSubTrieLoader) finaliseStorageRoot(cutoff int) (bool, error) { data = &fstl.leafData } var err error - fstl.groupsStorage, err = GenStructStep(fstl.rl.Retain, fstl.currStorage.Bytes(), fstl.succStorage.Bytes(), fstl.hb, data, fstl.groupsStorage, false) + fstl.groups, err = GenStructStep(fstl.rl.Retain, fstl.currStorage.Bytes(), fstl.succStorage.Bytes(), fstl.hb, data, fstl.groups, false) if err != nil { return false, err } - fstl.groupsStorage = fstl.groupsStorage[:0] + if len(fstl.groups) >= cutoff { + fstl.groups = fstl.groups[:cutoff-1] + } + for len(fstl.groups) > 0 && fstl.groups[len(fstl.groups)-1] == 0 { + fstl.groups = fstl.groups[:len(fstl.groups)-1] + } fstl.currStorage.Reset() fstl.succStorage.Reset() fstl.wasIHStorage = false @@ -525,13 +530,9 @@ func (fstl *FlatDbSubTrieLoader) LoadSubTries() (SubTries, error) { if len(fstl.dbPrefixes) == 0 { return SubTries{}, nil } - // Create manually managed read transaction - if tx, err := fstl.boltDB.Begin(false); err == nil { - //nolint:errcheck - defer tx.Rollback() - fstl.ih = tx.Bucket(dbutils.IntermediateTrieHashBucket).Cursor() - fstl.c = tx.Bucket(dbutils.CurrentStateBucket).Cursor() - + if err := fstl.boltDB.View(func(tx *bolt.Tx) error { + c := tx.Bucket(dbutils.CurrentStateBucket).Cursor() + ih := tx.Bucket(dbutils.IntermediateTrieHashBucket).Cursor() iwl := tx.Bucket(dbutils.IntermediateTrieWitnessLenBucket).Cursor() fstl.getWitnessLen = func(prefix []byte) uint64 { if !debug.IsTrackWitnessSizeEnabled() { @@ -543,40 +544,44 @@ func (fstl *FlatDbSubTrieLoader) LoadSubTries() (SubTries, error) { } return binary.BigEndian.Uint64(v) } - } else { - if err != nil { - return SubTries{}, fmt.Errorf("opening bolt tx: %v", err) - } - } - if err := fstl.iteration(true /* first */); err != nil { - return fstl.subTries, err - } - for fstl.k != nil || fstl.ihK != nil { - for (fstl.k != nil || fstl.ihK != nil) && !fstl.accountItemPresent && !fstl.storageItemPresent { - if err := fstl.iteration(false /* first */); err != nil { - return fstl.subTries, err - } + if err := fstl.iteration(c, ih, true /* first */); err != nil { + return err } - if fstl.storageItemPresent { - if err := fstl.WalkerStorage(fstl.storageIsHash, fstl.rangeIdx, fstl.storageKeyPart1, fstl.storageKeyPart2, fstl.storageValue, fstl.storageHash, fstl.storageWitnessLen); err != nil { - return fstl.subTries, err + for fstl.rangeIdx < len(fstl.dbPrefixes) { + for !fstl.itemPresent { + if err := fstl.iteration(c, ih, false /* first */); err != nil { + return err + } } - fstl.storageItemPresent = false - } - if fstl.accountItemPresent { - if err := fstl.WalkerAccount(fstl.accountIsHash, fstl.rangeIdx, fstl.accountKey, &fstl.accountValue, fstl.accountHash, fstl.accountWitnessLen); err != nil { - return fstl.subTries, err + if fstl.itemPresent { + switch fstl.itemType { + case StorageStreamItem: + if err := fstl.WalkerStorage(false, fstl.rangeIdx, fstl.storageKeyPart1, fstl.storageKeyPart2, fstl.storageValue, fstl.storageHash, fstl.storageWitnessLen); err != nil { + return err + } + case SHashStreamItem: + if err := fstl.WalkerStorage(true, fstl.rangeIdx, fstl.storageKeyPart1, fstl.storageKeyPart2, fstl.storageValue, fstl.storageHash, fstl.storageWitnessLen); err != nil { + return err + } + case AccountStreamItem: + if err := fstl.WalkerAccount(false, fstl.rangeIdx, fstl.accountKey, &fstl.accountValue, fstl.accountHash, fstl.accountWitnessLen); err != nil { + return err + } + case AHashStreamItem: + if err := fstl.WalkerAccount(true, fstl.rangeIdx, fstl.accountKey, &fstl.accountValue, fstl.accountHash, fstl.accountWitnessLen); err != nil { + return err + } + case CutoffStreamItem: + if err := fstl.finaliseRoot(fstl.streamCutoff); err != nil { + return err + } + } + fstl.itemPresent = false } - fstl.accountItemPresent = false } - } - if err := fstl.finaliseRoot(fstl.cutoffs[len(fstl.cutoffs)-1]); err != nil { - fmt.Println("Err in finalize root, writing down resolve params") - fmt.Printf("fstl.rd: %s\n", fstl.rl) - fmt.Printf("fixedbytes: %d\n", fstl.fixedbytes) - fmt.Printf("masks: %b\n", fstl.masks) - fmt.Printf("dbPrefixes: %x\n", fstl.dbPrefixes) - return fstl.subTries, fmt.Errorf("error in finaliseRoot %w", err) + return nil + }); err != nil { + return fstl.subTries, err } return fstl.subTries, nil } @@ -661,7 +666,7 @@ func (fstl *FlatDbSubTrieLoader) WalkerStorage(isIH bool, rangeIdx int, kPart1, fstl.leafData.Value = rlphacks.RlpSerializableBytes(fstl.valueStorage.Bytes()) data = &fstl.leafData } - fstl.groupsStorage, err = GenStructStep(fstl.rl.Retain, fstl.currStorage.Bytes(), fstl.succStorage.Bytes(), fstl.hb, data, fstl.groupsStorage, false) + fstl.groups, err = GenStructStep(fstl.rl.Retain, fstl.currStorage.Bytes(), fstl.succStorage.Bytes(), fstl.hb, data, fstl.groups, false) if err != nil { return err } @@ -724,7 +729,6 @@ func (fstl *FlatDbSubTrieLoader) WalkerAccount(isIH bool, rangeIdx int, k []byte fstl.wasIHStorage = false fstl.currStorage.Reset() fstl.succStorage.Reset() - fstl.groupsStorage = fstl.groupsStorage[:0] var err error if fstl.groups, err = GenStructStep(fstl.rl.Retain, fstl.curr.Bytes(), fstl.succ.Bytes(), fstl.hb, data, fstl.groups, false); err != nil { return err diff --git a/trie/flatdb_sub_trie_loader_test.go b/trie/flatdb_sub_trie_loader_test.go index b8f44cf5a1..01adcc9e29 100644 --- a/trie/flatdb_sub_trie_loader_test.go +++ b/trie/flatdb_sub_trie_loader_test.go @@ -312,12 +312,12 @@ func TestApiDetails(t *testing.T) { // this IntermediateHash key must not be used, because such key is in ResolveRequest // putIH("01", "0000000000000000000000000000000000000000000000000000000000000000") - loader := NewSubTrieLoader(0) tr := New(common.Hash{}) { expectRootHash := common.HexToHash("8c34d9b522547741fefe2363762026cf821e6b6a9358a56c9af26182403d20d9") + loader := NewSubTrieLoader(0) rs := NewRetainList(0) rs.AddHex(hexf("000101%0122x", 0)) rs.AddHex(common.Hex2Bytes("000202")) @@ -363,13 +363,14 @@ func TestApiDetails(t *testing.T) { } { // storage loader - loader.Reset(1) + loader := NewSubTrieLoader(0) rl := NewRetainList(0) rl.AddHex(append(hexf("000101%0122x", 0), hexf("%0128x", 0)...)) rl.AddHex(append(hexf("000201%0122x", 0), hexf("%0128x", 0)...)) rl.AddHex(append(hexf("000202%0122x", 0), hexf("%0128x", 0)...)) rl.AddHex(append(hexf("0f0f0f%0122x", 0), hexf("%0128x", 0)...)) dbPrefixes, fixedbits, hooks := tr.FindSubTriesToLoad(rl) + rl.Rewind() subTries, err := loader.LoadSubTries(db, 0, rl, dbPrefixes, fixedbits, false) require.NoError(err) @@ -406,7 +407,7 @@ func TestApiDetails(t *testing.T) { } if debug.IsTrackWitnessSizeEnabled() { - loader.Reset(1) + loader := NewSubTrieLoader(0) rs := NewRetainList(0) for _, base := range []string{"0", "f"} { for _, i := range []int{0, 1, 2, 15} { diff --git a/trie/retain_list.go b/trie/retain_list.go index 19cd756f0c..6dd95cc195 100644 --- a/trie/retain_list.go +++ b/trie/retain_list.go @@ -24,6 +24,11 @@ import ( "github.com/ledgerwatch/turbo-geth/common" ) +type RetainDecider interface { + Retain([]byte) bool + IsCodeTouched(common.Hash) bool +} + // RetainList encapsulates the list of keys that are required to be fully available, or loaded // (by using `BRANCH` opcode instead of `HASHER`) after processing of the sequence of key-value // pairs @@ -119,13 +124,6 @@ func (rl *RetainList) Retain(prefix []byte) bool { return false } -// Current returns the hex value that has been used for the latest comparison in `Retain` function -// It is only used in one edge case at the moment - to distinguish between the accounts' key -// and the storage keys of the same account -func (rl *RetainList) Current() []byte { - return rl.hexes[rl.lteIndex] -} - // Rewind lets us reuse this list from the beginning func (rl *RetainList) Rewind() { rl.lteIndex = 0 @@ -187,6 +185,3 @@ func (rr *RetainRange) String() string { return fmt.Sprintf("%x-%x", rr.from, rr.to) } -func (rr *RetainRange) Current() []byte { - panic("don't call me") -} diff --git a/trie/stream.go b/trie/stream.go index 321b6190db..89143c6597 100644 --- a/trie/stream.go +++ b/trie/stream.go @@ -43,6 +43,8 @@ const ( // SHashStreamItem used for marking a key-value pair in the stream as belonging to an intermediate hash // within the storage items (storage tries) SHashStreamItem + // CutoffStremItem used for marking the end of the subtrie + CutoffStreamItem ) // Stream represents the collection of key-value pairs, sorted by keys, where values may belong diff --git a/trie/trie.go b/trie/trie.go index a6b0561881..7e31e31e12 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -766,7 +766,7 @@ func (t *Trie) HookSubTries(subTries SubTries, hooks [][]byte) error { root := subTries.roots[i] hash := subTries.Hashes[i] if err := t.hook(hookNibbles, root, hash[:]); err != nil { - return err + return fmt.Errorf("hook %x: %v", hookNibbles, err) } } return nil diff --git a/trie/witness_builder.go b/trie/witness_builder.go index 3ba6b1d86e..b420621530 100644 --- a/trie/witness_builder.go +++ b/trie/witness_builder.go @@ -8,11 +8,6 @@ import ( ) type HashNodeFunc func(node, bool, []byte) (int, error) -type RetainDecider interface { - Retain([]byte) bool - IsCodeTouched(common.Hash) bool - Current() []byte -} type MerklePathLimiter struct { RetainDecider RetainDecider -- GitLab