github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/mpt/helpers.go (about) 1 package mpt 2 3 import "github.com/nspcc-dev/neo-go/pkg/util" 4 5 // lcp returns the longest common prefix of a and b. 6 // Note: it does no allocations. 7 func lcp(a, b []byte) []byte { 8 if len(a) < len(b) { 9 return lcp(b, a) 10 } 11 12 var i int 13 for i = 0; i < len(b); i++ { 14 if a[i] != b[i] { 15 break 16 } 17 } 18 19 return a[:i] 20 } 21 22 func lcpMany(kv []keyValue) []byte { 23 if len(kv) == 1 { 24 return kv[0].key 25 } 26 p := lcp(kv[0].key, kv[1].key) 27 if len(p) == 0 { 28 return p 29 } 30 for i := range kv[2:] { 31 p = lcp(p, kv[2+i].key) 32 } 33 return p 34 } 35 36 // toNibbles mangles the path by splitting every byte into 2 containing low- and high- 4-byte part. 37 func toNibbles(path []byte) []byte { 38 result := make([]byte, len(path)*2) 39 for i := range path { 40 result[i*2] = path[i] >> 4 41 result[i*2+1] = path[i] & 0x0F 42 } 43 return result 44 } 45 46 // strToNibbles mangles the path by splitting every byte into 2 containing low- and high- 4-byte part, 47 // ignoring the first byte (prefix). 48 func strToNibbles(path string) []byte { 49 result := make([]byte, (len(path)-1)*2) 50 for i := 0; i < len(path)-1; i++ { 51 result[i*2] = path[i+1] >> 4 52 result[i*2+1] = path[i+1] & 0x0F 53 } 54 return result 55 } 56 57 // fromNibbles performs an operation opposite to toNibbles and runs no path validity checks. 58 func fromNibbles(path []byte) []byte { 59 result := make([]byte, len(path)/2) 60 for i := range result { 61 result[i] = path[2*i]<<4 + path[2*i+1] 62 } 63 return result 64 } 65 66 // GetChildrenPaths returns a set of paths to the node's children who are non-empty HashNodes 67 // based on the node's path. 68 func GetChildrenPaths(path []byte, node Node) map[util.Uint256][][]byte { 69 res := make(map[util.Uint256][][]byte) 70 switch n := node.(type) { 71 case *LeafNode, *HashNode, EmptyNode: 72 return nil 73 case *BranchNode: 74 for i, child := range n.Children { 75 if child.Type() == HashT { 76 cPath := make([]byte, len(path), len(path)+1) 77 copy(cPath, path) 78 if i != lastChild { 79 cPath = append(cPath, byte(i)) 80 } 81 paths := res[child.Hash()] 82 paths = append(paths, cPath) 83 res[child.Hash()] = paths 84 } 85 } 86 case *ExtensionNode: 87 if n.next.Type() == HashT { 88 cPath := make([]byte, len(path)+len(n.key)) 89 copy(cPath, path) 90 copy(cPath[len(path):], n.key) 91 res[n.next.Hash()] = [][]byte{cPath} 92 } 93 default: 94 panic("unknown Node type") 95 } 96 return res 97 }