diff --git a/cmd/pics/pics.go b/cmd/pics/pics.go index 64ba7fe454a..f1cbd702bd9 100644 --- a/cmd/pics/pics.go +++ b/cmd/pics/pics.go @@ -24,11 +24,8 @@ import ( "sort" "strconv" - libcommon "github.com/erigontech/erigon-lib/common" - + "github.com/erigontech/erigon/cmd/pics/visual" "github.com/erigontech/erigon/crypto" - "github.com/erigontech/erigon/turbo/trie" - "github.com/erigontech/erigon/visual" ) var pic = flag.String("pic", "", "specifies picture to regenerate") @@ -203,221 +200,6 @@ q_%x->q_%x; } } -func prefixGroups4() { - fmt.Printf("Prefix groups 4\n") - filename := "prefix_groups_4.dot" - f, err := os.Create(filename) - if err != nil { - panic(err) - } - keys := generatePrefixGroups() - sort.Strings(keys) - tr := trie.New(libcommon.Hash{}) - var hightlights = make([][]byte, 0, len(keys)) - for i, key := range keys { - hexKey := make([]byte, len(key)/2) - for j := 0; j < len(hexKey); j++ { - hexKey[j] = key[2*j+1] | (key[2*j] << 4) - } - vs := strconv.Itoa(i) - tr.Update(hexKey, []byte(vs)) - hightlights = append(hightlights, []byte(key)) - } - visual.StartGraph(f, false) - trie.Visual(tr, f, &trie.VisualOpts{ - Highlights: hightlights, - IndexColors: visual.QuadIndexColors, - FontColors: visual.QuadFontColors, - Values: true, - SameLevel: true, - }) - visual.EndGraph(f) - if err := f.Close(); err != nil { - panic(err) - } - //nolint:gosec - cmd := exec.Command("dot", "-Tpng:gd", "-o"+dot2png(filename), filename) - if output, err := cmd.CombinedOutput(); err != nil { - fmt.Printf("error: %v, output: %s\n", err, output) - } -} - -func prefixGroups5() { - fmt.Printf("Prefix groups 5\n") - filename := "prefix_groups_5.dot" - f, err := os.Create(filename) - if err != nil { - panic(err) - } - keys := generatePrefixGroups() - sort.Strings(keys) - tr := trie.New(libcommon.Hash{}) - var hightlights = make([][]byte, 0, len(keys)) - var folds = make([][]byte, 0, len(keys)) - for i, key := range keys { - hexKey := make([]byte, len(key)/2) - for j := 0; j < len(hexKey); j++ { - hexKey[j] = key[2*j+1] | (key[2*j] << 4) - } - vs := strconv.Itoa(i) - tr.Update(hexKey, []byte(vs)) - hightlights = append(hightlights, []byte(key)) - folds = append(folds, hexKey) - } - tr.Fold(folds[:8]) - visual.StartGraph(f, false) - trie.Visual(tr, f, &trie.VisualOpts{ - Highlights: hightlights, - IndexColors: visual.QuadIndexColors, - FontColors: visual.QuadFontColors, - Values: true, - SameLevel: true, - }) - visual.EndGraph(f) - if err := f.Close(); err != nil { - panic(err) - } - //nolint:gosec - cmd := exec.Command("dot", "-Tpng:gd", "-o"+dot2png(filename), filename) - if output, err := cmd.CombinedOutput(); err != nil { - fmt.Printf("error: %v, output: %s\n", err, output) - } -} - -func prefixGroups6() { - fmt.Printf("Prefix groups 6\n") - filename := "prefix_groups_6.dot" - f, err := os.Create(filename) - if err != nil { - panic(err) - } - keys := generatePrefixGroups() - sort.Strings(keys) - tr := trie.New(libcommon.Hash{}) - var hightlights = make([][]byte, 0, len(keys)) - var folds = make([][]byte, 0, len(keys)) - for i, key := range keys { - hexKey := make([]byte, len(key)/2) - for j := 0; j < len(hexKey); j++ { - hexKey[j] = key[2*j+1] | (key[2*j] << 4) - } - vs := strconv.Itoa(i) - tr.Update(hexKey, []byte(vs)) - hightlights = append(hightlights, []byte(key)) - folds = append(folds, hexKey) - } - tr.Fold(folds[:8]) - tr.Fold(folds[8:16]) - visual.StartGraph(f, false) - trie.Visual(tr, f, &trie.VisualOpts{ - Highlights: hightlights, - IndexColors: visual.QuadIndexColors, - FontColors: visual.QuadFontColors, - Values: true, - SameLevel: true, - }) - visual.EndGraph(f) - if err := f.Close(); err != nil { - panic(err) - } - //nolint:gosec - cmd := exec.Command("dot", "-Tpng:gd", "-o"+dot2png(filename), filename) - if output, err := cmd.CombinedOutput(); err != nil { - fmt.Printf("error: %v, output: %s\n", err, output) - } -} - -func prefixGroups7() { - fmt.Printf("Prefix groups 7\n") - filename := "prefix_groups_7.dot" - f, err := os.Create(filename) - if err != nil { - panic(err) - } - keys := generatePrefixGroups() - sort.Strings(keys) - tr := trie.New(libcommon.Hash{}) - var hightlights = make([][]byte, 0, len(keys)) - var folds = make([][]byte, 0, len(keys)) - for i, key := range keys { - hexKey := make([]byte, len(key)/2) - for j := 0; j < len(hexKey); j++ { - hexKey[j] = key[2*j+1] | (key[2*j] << 4) - } - vs := strconv.Itoa(i) - tr.Update(hexKey, []byte(vs)) - hightlights = append(hightlights, []byte(key)) - folds = append(folds, hexKey) - } - tr.Fold(folds[:8]) - tr.Fold(folds[8:16]) - tr.Fold(folds[16:24]) - tr.Fold(folds[24:]) - visual.StartGraph(f, false) - trie.Visual(tr, f, &trie.VisualOpts{ - Highlights: hightlights, - IndexColors: visual.QuadIndexColors, - FontColors: visual.QuadFontColors, - Values: true, - SameLevel: true, - }) - visual.EndGraph(f) - if err := f.Close(); err != nil { - panic(err) - } - //nolint:gosec - cmd := exec.Command("dot", "-Tpng:gd", "-o"+dot2png(filename), filename) - if output, err := cmd.CombinedOutput(); err != nil { - fmt.Printf("error: %v, output: %s\n", err, output) - } -} - -func prefixGroups8() { - fmt.Printf("Prefix groups 8\n") - filename := "prefix_groups_8.dot" - f, err := os.Create(filename) - if err != nil { - panic(err) - } - keys := generatePrefixGroups() - sort.Strings(keys) - tr := trie.New(libcommon.Hash{}) - var hightlights = make([][]byte, 0, len(keys)) - var folds [][]byte - for i, key := range keys { - hexKey := make([]byte, len(key)/2) - for j := 0; j < len(hexKey); j++ { - hexKey[j] = key[2*j+1] | (key[2*j] << 4) - } - vs := strconv.Itoa(i) - tr.Update(hexKey, []byte(vs)) - hightlights = append(hightlights, []byte(key)) - switch i { - case 3, 8, 22, 23: - default: - folds = append(folds, hexKey) - } - } - tr.Fold(folds) - visual.StartGraph(f, false) - trie.Visual(tr, f, &trie.VisualOpts{ - Highlights: hightlights, - IndexColors: visual.QuadIndexColors, - FontColors: visual.QuadFontColors, - Values: true, - SameLevel: true, - }) - visual.EndGraph(f) - if err := f.Close(); err != nil { - panic(err) - } - //nolint:gosec - cmd := exec.Command("dot", "-Tpng:gd", "-o"+dot2png(filename), filename) - if output, err := cmd.CombinedOutput(); err != nil { - fmt.Printf("error: %v, output: %s\n", err, output) - } -} - func main() { flag.Parse() switch *pic { @@ -427,16 +209,6 @@ func main() { prefixGroups2() case "prefix_groups_3": prefixGroups3() - case "prefix_groups_4": - prefixGroups4() - case "prefix_groups_5": - prefixGroups5() - case "prefix_groups_6": - prefixGroups6() - case "prefix_groups_7": - prefixGroups7() - case "prefix_groups_8": - prefixGroups8() case "initial_state_1": if err := initialState1(); err != nil { fmt.Printf("%v\n", err) diff --git a/cmd/pics/state.go b/cmd/pics/state.go index 2025153813b..7da9a520212 100644 --- a/cmd/pics/state.go +++ b/cmd/pics/state.go @@ -37,6 +37,7 @@ import ( "github.com/erigontech/erigon/accounts/abi/bind" "github.com/erigontech/erigon/accounts/abi/bind/backends" "github.com/erigontech/erigon/cmd/pics/contracts" + "github.com/erigontech/erigon/cmd/pics/visual" "github.com/erigontech/erigon/common" "github.com/erigontech/erigon/core" "github.com/erigontech/erigon/core/types" @@ -44,7 +45,6 @@ import ( "github.com/erigontech/erigon/params" "github.com/erigontech/erigon/turbo/stages/mock" "github.com/erigontech/erigon/turbo/trie" - "github.com/erigontech/erigon/visual" ) /*func statePicture(t *trie.Trie, number int, keyCompression int, codeCompressed bool, valCompressed bool, diff --git a/visual/common.go b/cmd/pics/visual/common.go similarity index 100% rename from visual/common.go rename to cmd/pics/visual/common.go diff --git a/visual/hexary.go b/cmd/pics/visual/hexary.go similarity index 100% rename from visual/hexary.go rename to cmd/pics/visual/hexary.go diff --git a/visual/quad.go b/cmd/pics/visual/quad.go similarity index 100% rename from visual/quad.go rename to cmd/pics/visual/quad.go diff --git a/design/logos/Illustrator/readme.md b/design/logos/Illustrator/readme.md deleted file mode 100644 index 8b137891791..00000000000 --- a/design/logos/Illustrator/readme.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/design/logos/png/readme.md b/design/logos/png/readme.md deleted file mode 100644 index 8b137891791..00000000000 --- a/design/logos/png/readme.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/design/logos/svg/readme.md b/design/logos/svg/readme.md deleted file mode 100644 index 8b137891791..00000000000 --- a/design/logos/svg/readme.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/design/logos/test b/design/logos/test deleted file mode 100644 index 8b137891791..00000000000 --- a/design/logos/test +++ /dev/null @@ -1 +0,0 @@ - diff --git a/design/wallpapers/readme.md b/design/wallpapers/readme.md deleted file mode 100644 index 8b137891791..00000000000 --- a/design/wallpapers/readme.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/design/logos/Illustrator/logo.ai b/docs/design/logos/Illustrator/logo.ai similarity index 100% rename from design/logos/Illustrator/logo.ai rename to docs/design/logos/Illustrator/logo.ai diff --git a/design/logos/png/Logo.png b/docs/design/logos/png/Logo.png similarity index 100% rename from design/logos/png/Logo.png rename to docs/design/logos/png/Logo.png diff --git a/design/logos/png/Outlines-Black.png b/docs/design/logos/png/Outlines-Black.png similarity index 100% rename from design/logos/png/Outlines-Black.png rename to docs/design/logos/png/Outlines-Black.png diff --git a/design/logos/png/Outlines-White.png b/docs/design/logos/png/Outlines-White.png similarity index 100% rename from design/logos/png/Outlines-White.png rename to docs/design/logos/png/Outlines-White.png diff --git a/design/logos/png/Symbol-Black.png b/docs/design/logos/png/Symbol-Black.png similarity index 100% rename from design/logos/png/Symbol-Black.png rename to docs/design/logos/png/Symbol-Black.png diff --git a/design/logos/png/Symbol-White.png b/docs/design/logos/png/Symbol-White.png similarity index 100% rename from design/logos/png/Symbol-White.png rename to docs/design/logos/png/Symbol-White.png diff --git a/design/logos/svg/Logo.svg b/docs/design/logos/svg/Logo.svg similarity index 100% rename from design/logos/svg/Logo.svg rename to docs/design/logos/svg/Logo.svg diff --git a/design/logos/svg/Outlines-Black.svg b/docs/design/logos/svg/Outlines-Black.svg similarity index 100% rename from design/logos/svg/Outlines-Black.svg rename to docs/design/logos/svg/Outlines-Black.svg diff --git a/design/logos/svg/Outlines-White.svg b/docs/design/logos/svg/Outlines-White.svg similarity index 100% rename from design/logos/svg/Outlines-White.svg rename to docs/design/logos/svg/Outlines-White.svg diff --git a/design/logos/svg/Symbol-Black.svg b/docs/design/logos/svg/Symbol-Black.svg similarity index 100% rename from design/logos/svg/Symbol-Black.svg rename to docs/design/logos/svg/Symbol-Black.svg diff --git a/design/logos/svg/Symbol-White.svg b/docs/design/logos/svg/Symbol-White.svg similarity index 100% rename from design/logos/svg/Symbol-White.svg rename to docs/design/logos/svg/Symbol-White.svg diff --git a/design/readme.MD b/docs/design/readme.MD similarity index 100% rename from design/readme.MD rename to docs/design/readme.MD diff --git a/design/styleguide/colors.png b/docs/design/styleguide/colors.png similarity index 100% rename from design/styleguide/colors.png rename to docs/design/styleguide/colors.png diff --git a/design/styleguide/colors.sketch b/docs/design/styleguide/colors.sketch similarity index 100% rename from design/styleguide/colors.sketch rename to docs/design/styleguide/colors.sketch diff --git a/design/styleguide/readme.md b/docs/design/styleguide/readme.md similarity index 100% rename from design/styleguide/readme.md rename to docs/design/styleguide/readme.md diff --git a/design/wallpapers/wallpaper-day.png b/docs/design/wallpapers/wallpaper-day.png similarity index 100% rename from design/wallpapers/wallpaper-day.png rename to docs/design/wallpapers/wallpaper-day.png diff --git a/design/wallpapers/wallpaper-morning.png b/docs/design/wallpapers/wallpaper-morning.png similarity index 100% rename from design/wallpapers/wallpaper-morning.png rename to docs/design/wallpapers/wallpaper-morning.png diff --git a/design/wallpapers/wallpaper-night.png b/docs/design/wallpapers/wallpaper-night.png similarity index 100% rename from design/wallpapers/wallpaper-night.png rename to docs/design/wallpapers/wallpaper-night.png diff --git a/design/wallpapers/wallpapers.sketch b/docs/design/wallpapers/wallpapers.sketch similarity index 100% rename from design/wallpapers/wallpapers.sketch rename to docs/design/wallpapers/wallpapers.sketch diff --git a/turbo/trie/visual.go b/turbo/trie/visual.go deleted file mode 100644 index 8151cc50ec0..00000000000 --- a/turbo/trie/visual.go +++ /dev/null @@ -1,451 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// (original work) -// Copyright 2024 The Erigon Authors -// (modifications) -// This file is part of Erigon. -// -// Erigon is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Erigon is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Erigon. If not, see . - -// Visualisation of Merkle Patricia Tries. -package trie - -import ( - "bytes" - "fmt" - "io" - "math/big" - - libcommon "github.com/erigontech/erigon-lib/common" - - "github.com/erigontech/erigon/visual" -) - -// VisualOpts contains various configuration options fo the Visual function -// It has been introduced as a replacement for too many arguments with options -type VisualOpts struct { - Highlights [][]byte // Collection of keys, in the HEX encoding, that need to be highlighted with digits - IndexColors []string // Array of colors for representing digits as colored boxes - FontColors []string // Array of colors, the same length as indexColors, for the textual digits inside the coloured boxes - CutTerminals int // Specifies how many digits to cut from the terminal short node keys for a more convinient display - Values bool // Whether to display value nodes (as box with rounded corners) - CodeCompressed bool // Whether to turn the code from a large rectangle to a small square for a more convinient display - ValCompressed bool // Whether long values (over 10 characters) are shortened using ... in the middle - ValHex bool // Whether values should be displayed as hex numbers (otherwise they are displayed as just strings) - SameLevel bool // Whether the leaves (and hashes) need to be on the same horizontal level -} - -// Visual creates visualisation of trie with highlighting -func Visual(t *Trie, w io.Writer, opts *VisualOpts) { - var leaves map[string]struct{} - if opts.Values { - leaves = make(map[string]struct{}) - } - hashes := make(map[string]struct{}) - visualNode(t.root, []byte{}, w, opts.Highlights, opts, leaves, hashes) - if opts.SameLevel { - fmt.Fprintf(w, "{rank = same;") - for leaf := range leaves { - fmt.Fprintf(w, "n_%x;", leaf) - } - fmt.Fprintf(w, `}; - `) - fmt.Fprintf(w, "{rank = same;") - for hash := range hashes { - fmt.Fprintf(w, "n_%x;", hash) - } - fmt.Fprintf(w, `}; - `) - } -} - -func visualNode(nd node, hex []byte, w io.Writer, highlights [][]byte, opts *VisualOpts, - leaves map[string]struct{}, hashes map[string]struct{}) { - switch n := nd.(type) { - case nil: - case *shortNode: - var pLenMax int - for _, h := range highlights { - pLen := prefixLen(n.Key, h) - if pLen > pLenMax { - pLenMax = pLen - } - } - visual.Vertical(w, n.Key, pLenMax, fmt.Sprintf("n_%x", hex), opts.IndexColors, opts.FontColors, opts.CutTerminals) - if v, ok := n.Val.(valueNode); ok { - if leaves != nil { - leaves[string(hex)] = struct{}{} - /* - var valStr string - if opts.ValHex { - valStr = fmt.Sprintf("%x", []byte(v)) - } else { - valStr = string(v) - } - if opts.ValCompressed && len(valStr) > 10 { - valStr = fmt.Sprintf("%x..%x", []byte(v)[:2], []byte(v)[len(v)-2:]) - } - */ - valHex := keybytesToHex(v) - valHex = valHex[:len(valHex)-1] - visual.HexBox(w, fmt.Sprintf("e_%x", concat(hex, n.Key...)), valHex, 32, opts.ValCompressed, false) - fmt.Fprintf(w, - `n_%x -> e_%x; - `, hex, concat(hex, n.Key...)) - } - } else if a, ok := n.Val.(*accountNode); ok { - balance := float64(big.NewInt(0).Div(a.Balance.ToBig(), big.NewInt(1000000000000000)).Uint64()) / 1000.0 - visual.Circle(w, fmt.Sprintf("e_%x", concat(hex, n.Key...)), fmt.Sprintf("%d \u039E%.3f", a.Nonce, balance), true) - accountHex := concat(hex, n.Key...) - fmt.Fprintf(w, - `n_%x -> e_%x; -`, hex, accountHex) - if !a.IsEmptyCodeHash() { - if code := a.code; code != nil { - codeHex := keybytesToHex(code) - codeHex = codeHex[:len(codeHex)-1] - visual.HexBox(w, fmt.Sprintf("c_%x", accountHex), codeHex, 32, opts.CodeCompressed, false) - } else { - visual.Box(w, fmt.Sprintf("c_%x", accountHex), "codeHash") - } - fmt.Fprintf(w, - `e_%x -> c_%x; - `, accountHex, accountHex) - } - if !a.IsEmptyRoot() { - if a.storage != nil { - nKey := n.Key - if nKey[len(nKey)-1] == 16 { - nKey = nKey[:len(nKey)-1] - } - var newHighlights [][]byte - for _, h := range highlights { - if h != nil && bytes.HasPrefix(h, nKey) { - newHighlights = append(newHighlights, h[len(nKey):]) - } - } - visualNode(a.storage, accountHex[:len(accountHex)-1], w, newHighlights, opts, leaves, hashes) - } else { - visual.Box(w, fmt.Sprintf("n_%x", accountHex[:len(accountHex)-1]), "storHash") - } - fmt.Fprintf(w, - `e_%x -> n_%x; - `, accountHex, accountHex[:len(accountHex)-1]) - } - } else { - fmt.Fprintf(w, - ` - - n_%x -> n_%x; -`, hex, concat(hex, n.Key...)) - var newHighlights [][]byte - for _, h := range highlights { - if h != nil && bytes.HasPrefix(h, n.Key) { - newHighlights = append(newHighlights, h[len(n.Key):]) - } - } - visualNode(n.Val, concat(hex, n.Key...), w, newHighlights, opts, leaves, hashes) - } - case *duoNode: - i1, i2 := n.childrenIdx() - fmt.Fprintf(w, - ` - n_%x [label=< - - -`, hex) - var hOn1, hOn2 bool - var highlights1, highlights2 [][]byte - for _, h := range highlights { - if len(h) > 0 && h[0] == i1 { - highlights1 = append(highlights1, h[1:]) - hOn1 = true - } - if len(h) > 0 && h[0] == i2 { - highlights2 = append(highlights2, h[1:]) - hOn2 = true - } - } - if hOn1 { - fmt.Fprintf(w, - ` - -`, opts.IndexColors[i1], i1, opts.FontColors[i1], indices[i1]) - } else { - fmt.Fprintf(w, - ` - -`, opts.IndexColors[i1], i1) - } - if hOn2 { - fmt.Fprintf(w, - ` - -`, opts.IndexColors[i2], i2, opts.FontColors[i2], indices[i2]) - } else { - fmt.Fprintf(w, - ` - -`, opts.IndexColors[i2], i2) - } - fmt.Fprintf(w, - ` - -
%s%s
- >]; - n_%x:h%d -> n_%x; - n_%x:h%d -> n_%x; -`, hex, i1, concat(hex, i1), hex, i2, concat(hex, i2)) - visualNode(n.child1, concat(hex, i1), w, highlights1, opts, leaves, hashes) - visualNode(n.child2, concat(hex, i2), w, highlights2, opts, leaves, hashes) - case *fullNode: - fmt.Fprintf(w, - ` - n_%x [label=< - - -`, hex) - hOn := make(map[byte]struct{}) - for _, h := range highlights { - if len(h) > 0 { - hOn[h[0]] = struct{}{} - } - } - for i, child := range n.Children { - if child == nil { - continue - } - if _, ok := hOn[byte(i)]; ok { - fmt.Fprintf(w, - ` - -`, opts.IndexColors[i], i, opts.FontColors[i], indices[i]) - } else { - fmt.Fprintf(w, - ` - -`, opts.IndexColors[i], i) - } - } - fmt.Fprintf(w, - ` - -
%s
- >]; -`) - for i, child := range n.Children { - if child == nil { - continue - } - fmt.Fprintf(w, - ` n_%x:h%d -> n_%x; -`, hex, i, concat(hex, byte(i))) - } - for i, child := range n.Children { - if child == nil { - continue - } - var newHighlights [][]byte - for _, h := range highlights { - if len(h) > 0 && h[0] == byte(i) { - newHighlights = append(newHighlights, h[1:]) - } - } - visualNode(child, concat(hex, byte(i)), w, newHighlights, opts, leaves, hashes) - } - case hashNode: - hashes[string(hex)] = struct{}{} - visual.Box(w, fmt.Sprintf("n_%x", hex), "hash") - } -} - -// Fold modifies the trie by folding the given set of keys, making sure that they are inaccessible -// without resolution via DB -func (t *Trie) Fold(keys [][]byte) { - var hexes = make([][]byte, 0, len(keys)) - for _, key := range keys { - hexes = append(hexes, keybytesToHex(key)) - } - h := newHasher(false) - defer returnHasherToPool(h) - _, t.root = fold(t.root, hexes, h, true) -} - -func fold(nd node, hexes [][]byte, h *hasher, isRoot bool) (bool, node) { - switch n := nd.(type) { - case *shortNode: - var newHexes [][]byte - for _, hex := range hexes { - if bytes.Equal(n.Key, hex) { - var hn libcommon.Hash - h.hash(n, isRoot, hn[:]) - return true, hashNode{hash: hn[:]} - } - pLen := prefixLen(n.Key, hex) - if pLen > 0 { - newHexes = append(newHexes, hex[pLen:]) - } - } - if len(newHexes) > 0 { - folded, nn := fold(n.Val, newHexes, h, false) - n.Val = nn - if folded { - var hn libcommon.Hash - h.hash(n, isRoot, hn[:]) - return true, hashNode{hash: hn[:]} - } - return false, n - } - case *duoNode: - i1, i2 := n.childrenIdx() - var hexes1, hexes2 [][]byte - for _, h := range hexes { - if len(h) > 0 && h[0] == i1 { - hexes1 = append(hexes1, h[1:]) - } - if len(h) > 0 && h[0] == i2 { - hexes2 = append(hexes2, h[1:]) - } - } - var folded1, folded2 bool - var nn1, nn2 node - if len(hexes1) > 0 { - folded1, nn1 = fold(n.child1, hexes1, h, false) - n.child1 = nn1 - } - if len(hexes2) > 0 { - folded2, nn2 = fold(n.child2, hexes2, h, false) - n.child2 = nn2 - } - if folded1 && folded2 { - var hn libcommon.Hash - h.hash(n, isRoot, hn[:]) - return true, hashNode{hash: hn[:]} - } - return false, n - case *fullNode: - var unfolded bool - for i, child := range n.Children { - if child == nil { - continue - } - var newHexes [][]byte - for _, h := range hexes { - if len(h) > 0 && h[0] == byte(i) { - newHexes = append(newHexes, h[1:]) - } - } - if len(newHexes) > 0 { - folded, nn := fold(child, newHexes, h, false) - n.Children[i] = nn - if !folded { - unfolded = true - } - } else { - unfolded = true - } - } - if !unfolded { - var hn libcommon.Hash - h.hash(n, isRoot, hn[:]) - return true, hashNode{hash: hn[:]} - } - return false, n - } - return false, nd -} - -// HexToQuad converts hexary trie to quad trie with the same set of keys -func HexToQuad(t *Trie) *Trie { - newTrie := New(libcommon.Hash{}) - transformSubTrie(t.root, []byte{}, newTrie, keyHexToQuad) - return newTrie -} - -// KeyToQuad converts a key in KEY encoding to QUAD encoding (similar to HEX encoding, but uses digits 0..3 instead of digits 0..15) -func KeyToQuad(key []byte) []byte { - l := len(key)*2 + 1 - var nibbles = make([]byte, l) - for i, b := range key { - nibbles[i*2] = b / 16 - nibbles[i*2+1] = b % 16 - } - nibbles[l-1] = 16 - return keyHexToQuad(nibbles) -} - -func keyHexToQuad(hex []byte) []byte { - quadLen := len(hex) * 2 - if hex[len(hex)-1] == 16 { - quadLen-- - } - quad := make([]byte, quadLen) - qi := 0 - for _, h := range hex { - if h == 16 { - quad[qi] = 16 - qi++ - } else { - quad[qi] = h / 4 - qi++ - quad[qi] = h % 4 - qi++ - } - } - return quad -} - -// FullKeys construct the list of full keys (i.e. keys that can be accessed without resolution via DB) that are present in -// the given trie -func FullKeys(t *Trie) []string { - return fullKeys(t.root, nil, nil) -} - -func fullKeys(nd node, hex []byte, fk []string) []string { - switch n := nd.(type) { - case nil: - return fk - case hashNode: - return fk - case valueNode: - return append(fk, string(concat(hex, 16))) - case *shortNode: - h := n.Key - // Remove terminator - if h[len(h)-1] == 16 { - h = h[:len(h)-1] - } - hexVal := concat(hex, h...) - return fullKeys(n.Val, hexVal, fk) - case *duoNode: - i1, i2 := n.childrenIdx() - hex1 := make([]byte, len(hex)+1) - copy(hex1, hex) - hex1[len(hex)] = i1 - hex2 := make([]byte, len(hex)+1) - copy(hex2, hex) - hex2[len(hex)] = i2 - return fullKeys(n.child2, hex2, fullKeys(n.child1, hex1, fk)) - case *fullNode: - for i, child := range n.Children { - if child != nil { - fk = fullKeys(child, concat(hex, byte(i)), fk) - } - } - return fk - case *accountNode: - return append(fullKeys(n.storage, hex, fk), string(concat(hex, 16))) - default: - panic(fmt.Sprintf("%T", nd)) - } -}