github.com/lbryio/lbcd@v0.22.119/claimtrie/merkletrie/collapsedtrie.go (about) 1 package merkletrie 2 3 import ( 4 "github.com/lbryio/lbcd/chaincfg/chainhash" 5 ) 6 7 type KeyType []byte 8 9 type collapsedVertex struct { 10 children []*collapsedVertex 11 key KeyType 12 merkleHash *chainhash.Hash 13 claimHash *chainhash.Hash 14 } 15 16 // insertAt inserts v into s at index i and returns the new slice. 17 // https://stackoverflow.com/questions/42746972/golang-insert-to-a-sorted-slice 18 func insertAt(data []*collapsedVertex, i int, v *collapsedVertex) []*collapsedVertex { 19 if i == len(data) { 20 // Insert at end is the easy case. 21 return append(data, v) 22 } 23 24 // Make space for the inserted element by shifting 25 // values at the insertion index up one index. The call 26 // to append does not allocate memory when cap(data) is 27 // greater than len(data). 28 data = append(data[:i+1], data[i:]...) 29 data[i] = v 30 return data 31 } 32 33 func (ptn *collapsedVertex) Insert(value *collapsedVertex) *collapsedVertex { 34 // keep it sorted (and sort.Sort is too slow) 35 index := sortSearch(ptn.children, value.key[0]) 36 ptn.children = insertAt(ptn.children, index, value) 37 38 return value 39 } 40 41 // this sort.Search is stolen shamelessly from search.go, 42 // and modified for performance to not need a closure 43 func sortSearch(nodes []*collapsedVertex, b byte) int { 44 i, j := 0, len(nodes) 45 for i < j { 46 h := int(uint(i+j) >> 1) // avoid overflow when computing h 47 // i ≤ h < j 48 if nodes[h].key[0] < b { 49 i = h + 1 // preserves f(i-1) == false 50 } else { 51 j = h // preserves f(j) == true 52 } 53 } 54 // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. 55 return i 56 } 57 58 func (ptn *collapsedVertex) findNearest(key KeyType) (int, *collapsedVertex) { 59 // none of the children overlap on the first char or we would have a parent node with that char 60 index := sortSearch(ptn.children, key[0]) 61 hits := ptn.children[index:] 62 if len(hits) > 0 { 63 return index, hits[0] 64 } 65 return -1, nil 66 } 67 68 type collapsedTrie struct { 69 Root *collapsedVertex 70 Nodes int 71 } 72 73 func NewCollapsedTrie() *collapsedTrie { 74 // we never delete the Root node 75 return &collapsedTrie{Root: &collapsedVertex{key: make(KeyType, 0)}, Nodes: 1} 76 } 77 78 func (pt *collapsedTrie) NodeCount() int { 79 return pt.Nodes 80 } 81 82 func matchLength(a, b KeyType) int { 83 minLen := len(a) 84 if len(b) < minLen { 85 minLen = len(b) 86 } 87 for i := 0; i < minLen; i++ { 88 if a[i] != b[i] { 89 return i 90 } 91 } 92 return minLen 93 } 94 95 func (pt *collapsedTrie) insert(value KeyType, node *collapsedVertex) (bool, *collapsedVertex) { 96 index, child := node.findNearest(value) 97 match := 0 98 if index >= 0 { // if we found a child 99 child.merkleHash = nil 100 match = matchLength(value, child.key) 101 if len(value) == match && len(child.key) == match { 102 return false, child 103 } 104 } 105 if match <= 0 { 106 pt.Nodes++ 107 return true, node.Insert(&collapsedVertex{key: value}) 108 } 109 if match < len(child.key) { 110 grandChild := collapsedVertex{key: child.key[match:], children: child.children, 111 claimHash: child.claimHash, merkleHash: child.merkleHash} 112 newChild := collapsedVertex{key: child.key[0:match], children: []*collapsedVertex{&grandChild}} 113 child = &newChild 114 node.children[index] = child 115 pt.Nodes++ 116 if len(value) == match { 117 return true, child 118 } 119 } 120 return pt.insert(value[match:], child) 121 } 122 123 func (pt *collapsedTrie) InsertOrFind(value KeyType) (bool, *collapsedVertex) { 124 pt.Root.merkleHash = nil 125 if len(value) <= 0 { 126 return false, pt.Root 127 } 128 129 // we store the name so we need to make our own copy of it 130 // this avoids errors where this function is called via the DB iterator 131 v2 := make([]byte, len(value)) 132 copy(v2, value) 133 return pt.insert(v2, pt.Root) 134 } 135 136 func find(value KeyType, node *collapsedVertex, pathIndexes *[]int, path *[]*collapsedVertex) *collapsedVertex { 137 index, child := node.findNearest(value) 138 if index < 0 { 139 return nil 140 } 141 match := matchLength(value, child.key) 142 if len(value) == match && len(child.key) == match { 143 if pathIndexes != nil { 144 *pathIndexes = append(*pathIndexes, index) 145 } 146 if path != nil { 147 *path = append(*path, child) 148 } 149 return child 150 } 151 if match < len(child.key) || match == len(value) { 152 return nil 153 } 154 if pathIndexes != nil { 155 *pathIndexes = append(*pathIndexes, index) 156 } 157 if path != nil { 158 *path = append(*path, child) 159 } 160 return find(value[match:], child, pathIndexes, path) 161 } 162 163 func (pt *collapsedTrie) Find(value KeyType) *collapsedVertex { 164 if len(value) <= 0 { 165 return pt.Root 166 } 167 return find(value, pt.Root, nil, nil) 168 } 169 170 func (pt *collapsedTrie) FindPath(value KeyType) ([]int, []*collapsedVertex) { 171 pathIndexes := []int{-1} 172 path := []*collapsedVertex{pt.Root} 173 if len(value) > 0 { 174 result := find(value, pt.Root, &pathIndexes, &path) 175 if result == nil { // not sure I want this line 176 return nil, nil 177 } 178 } 179 return pathIndexes, path 180 } 181 182 // IterateFrom can be used to find a value and run a function on that value. 183 // If the handler returns true it continues to iterate through the children of value. 184 func (pt *collapsedTrie) IterateFrom(start KeyType, handler func(name KeyType, value *collapsedVertex) bool) { 185 node := find(start, pt.Root, nil, nil) 186 if node == nil { 187 return 188 } 189 iterateFrom(start, node, handler) 190 } 191 192 func iterateFrom(name KeyType, node *collapsedVertex, handler func(name KeyType, value *collapsedVertex) bool) { 193 for handler(name, node) { 194 for _, child := range node.children { 195 iterateFrom(append(name, child.key...), child, handler) 196 } 197 } 198 } 199 200 func (pt *collapsedTrie) Erase(value KeyType) bool { 201 indexes, path := pt.FindPath(value) 202 if path == nil || len(path) <= 1 { 203 if len(path) == 1 { 204 path[0].merkleHash = nil 205 path[0].claimHash = nil 206 } 207 return false 208 } 209 nodes := pt.Nodes 210 i := len(path) - 1 211 path[i].claimHash = nil // this is the thing we are erasing; the rest is book-keeping 212 for ; i > 0; i-- { 213 childCount := len(path[i].children) 214 noClaimData := path[i].claimHash == nil 215 path[i].merkleHash = nil 216 if childCount == 1 && noClaimData { 217 path[i].key = append(path[i].key, path[i].children[0].key...) 218 path[i].claimHash = path[i].children[0].claimHash 219 path[i].children = path[i].children[0].children 220 pt.Nodes-- 221 continue 222 } 223 if childCount == 0 && noClaimData { 224 index := indexes[i] 225 path[i-1].children = append(path[i-1].children[:index], path[i-1].children[index+1:]...) 226 pt.Nodes-- 227 continue 228 } 229 break 230 } 231 for ; i >= 0; i-- { 232 path[i].merkleHash = nil 233 } 234 return nodes > pt.Nodes 235 }