github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/trie/iterator_test.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package trie 13 14 import ( 15 "bytes" 16 "fmt" 17 "math/rand" 18 "testing" 19 20 "github.com/Sberex/go-sberex/common" 21 "github.com/Sberex/go-sberex/ethdb" 22 ) 23 24 func TestIterator(t *testing.T) { 25 trie := newEmpty() 26 vals := []struct{ k, v string }{ 27 {"do", "verb"}, 28 {"sbr", "wookiedoo"}, 29 {"horse", "stallion"}, 30 {"shaman", "horse"}, 31 {"doge", "coin"}, 32 {"dog", "puppy"}, 33 {"somethingveryoddindeedthis is", "myothernodedata"}, 34 } 35 all := make(map[string]string) 36 for _, val := range vals { 37 all[val.k] = val.v 38 trie.Update([]byte(val.k), []byte(val.v)) 39 } 40 trie.Commit(nil) 41 42 found := make(map[string]string) 43 it := NewIterator(trie.NodeIterator(nil)) 44 for it.Next() { 45 found[string(it.Key)] = string(it.Value) 46 } 47 48 for k, v := range all { 49 if found[k] != v { 50 t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v) 51 } 52 } 53 } 54 55 type kv struct { 56 k, v []byte 57 t bool 58 } 59 60 func TestIteratorLargeData(t *testing.T) { 61 trie := newEmpty() 62 vals := make(map[string]*kv) 63 64 for i := byte(0); i < 255; i++ { 65 value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} 66 value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} 67 trie.Update(value.k, value.v) 68 trie.Update(value2.k, value2.v) 69 vals[string(value.k)] = value 70 vals[string(value2.k)] = value2 71 } 72 73 it := NewIterator(trie.NodeIterator(nil)) 74 for it.Next() { 75 vals[string(it.Key)].t = true 76 } 77 78 var untouched []*kv 79 for _, value := range vals { 80 if !value.t { 81 untouched = append(untouched, value) 82 } 83 } 84 85 if len(untouched) > 0 { 86 t.Errorf("Missed %d nodes", len(untouched)) 87 for _, value := range untouched { 88 t.Error(value) 89 } 90 } 91 } 92 93 // Tests that the node iterator indeed walks over the entire database contents. 94 func TestNodeIteratorCoverage(t *testing.T) { 95 // Create some arbitrary test trie to iterate 96 db, trie, _ := makeTestTrie() 97 98 // Gather all the node hashes found by the iterator 99 hashes := make(map[common.Hash]struct{}) 100 for it := trie.NodeIterator(nil); it.Next(true); { 101 if it.Hash() != (common.Hash{}) { 102 hashes[it.Hash()] = struct{}{} 103 } 104 } 105 // Cross check the hashes and the database itself 106 for hash := range hashes { 107 if _, err := db.Node(hash); err != nil { 108 t.Errorf("failed to retrieve reported node %x: %v", hash, err) 109 } 110 } 111 for hash, obj := range db.nodes { 112 if obj != nil && hash != (common.Hash{}) { 113 if _, ok := hashes[hash]; !ok { 114 t.Errorf("state entry not reported %x", hash) 115 } 116 } 117 } 118 for _, key := range db.diskdb.(*ethdb.MemDatabase).Keys() { 119 if _, ok := hashes[common.BytesToHash(key)]; !ok { 120 t.Errorf("state entry not reported %x", key) 121 } 122 } 123 } 124 125 type kvs struct{ k, v string } 126 127 var testdata1 = []kvs{ 128 {"barb", "ba"}, 129 {"bard", "bc"}, 130 {"bars", "bb"}, 131 {"bar", "b"}, 132 {"fab", "z"}, 133 {"food", "ab"}, 134 {"foos", "aa"}, 135 {"foo", "a"}, 136 } 137 138 var testdata2 = []kvs{ 139 {"aardvark", "c"}, 140 {"bar", "b"}, 141 {"barb", "bd"}, 142 {"bars", "be"}, 143 {"fab", "z"}, 144 {"foo", "a"}, 145 {"foos", "aa"}, 146 {"food", "ab"}, 147 {"jars", "d"}, 148 } 149 150 func TestIteratorSeek(t *testing.T) { 151 trie := newEmpty() 152 for _, val := range testdata1 { 153 trie.Update([]byte(val.k), []byte(val.v)) 154 } 155 156 // Seek to the middle. 157 it := NewIterator(trie.NodeIterator([]byte("fab"))) 158 if err := checkIteratorOrder(testdata1[4:], it); err != nil { 159 t.Fatal(err) 160 } 161 162 // Seek to a non-existent key. 163 it = NewIterator(trie.NodeIterator([]byte("barc"))) 164 if err := checkIteratorOrder(testdata1[1:], it); err != nil { 165 t.Fatal(err) 166 } 167 168 // Seek beyond the end. 169 it = NewIterator(trie.NodeIterator([]byte("z"))) 170 if err := checkIteratorOrder(nil, it); err != nil { 171 t.Fatal(err) 172 } 173 } 174 175 func checkIteratorOrder(want []kvs, it *Iterator) error { 176 for it.Next() { 177 if len(want) == 0 { 178 return fmt.Errorf("didn't expect any more values, got key %q", it.Key) 179 } 180 if !bytes.Equal(it.Key, []byte(want[0].k)) { 181 return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k) 182 } 183 want = want[1:] 184 } 185 if len(want) > 0 { 186 return fmt.Errorf("iterator ended early, want key %q", want[0]) 187 } 188 return nil 189 } 190 191 func TestDifferenceIterator(t *testing.T) { 192 triea := newEmpty() 193 for _, val := range testdata1 { 194 triea.Update([]byte(val.k), []byte(val.v)) 195 } 196 triea.Commit(nil) 197 198 trieb := newEmpty() 199 for _, val := range testdata2 { 200 trieb.Update([]byte(val.k), []byte(val.v)) 201 } 202 trieb.Commit(nil) 203 204 found := make(map[string]string) 205 di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil)) 206 it := NewIterator(di) 207 for it.Next() { 208 found[string(it.Key)] = string(it.Value) 209 } 210 211 all := []struct{ k, v string }{ 212 {"aardvark", "c"}, 213 {"barb", "bd"}, 214 {"bars", "be"}, 215 {"jars", "d"}, 216 } 217 for _, item := range all { 218 if found[item.k] != item.v { 219 t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v) 220 } 221 } 222 if len(found) != len(all) { 223 t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all)) 224 } 225 } 226 227 func TestUnionIterator(t *testing.T) { 228 triea := newEmpty() 229 for _, val := range testdata1 { 230 triea.Update([]byte(val.k), []byte(val.v)) 231 } 232 triea.Commit(nil) 233 234 trieb := newEmpty() 235 for _, val := range testdata2 { 236 trieb.Update([]byte(val.k), []byte(val.v)) 237 } 238 trieb.Commit(nil) 239 240 di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) 241 it := NewIterator(di) 242 243 all := []struct{ k, v string }{ 244 {"aardvark", "c"}, 245 {"barb", "ba"}, 246 {"barb", "bd"}, 247 {"bard", "bc"}, 248 {"bars", "bb"}, 249 {"bars", "be"}, 250 {"bar", "b"}, 251 {"fab", "z"}, 252 {"food", "ab"}, 253 {"foos", "aa"}, 254 {"foo", "a"}, 255 {"jars", "d"}, 256 } 257 258 for i, kv := range all { 259 if !it.Next() { 260 t.Errorf("Iterator ends prematurely at element %d", i) 261 } 262 if kv.k != string(it.Key) { 263 t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k) 264 } 265 if kv.v != string(it.Value) { 266 t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v) 267 } 268 } 269 if it.Next() { 270 t.Errorf("Iterator returned extra values.") 271 } 272 } 273 274 func TestIteratorNoDups(t *testing.T) { 275 var tr Trie 276 for _, val := range testdata1 { 277 tr.Update([]byte(val.k), []byte(val.v)) 278 } 279 checkIteratorNoDups(t, tr.NodeIterator(nil), nil) 280 } 281 282 // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. 283 func TestIteratorContinueAfterErrorDisk(t *testing.T) { testIteratorContinueAfterError(t, false) } 284 func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) } 285 286 func testIteratorContinueAfterError(t *testing.T, memonly bool) { 287 diskdb, _ := ethdb.NewMemDatabase() 288 triedb := NewDatabase(diskdb) 289 290 tr, _ := New(common.Hash{}, triedb) 291 for _, val := range testdata1 { 292 tr.Update([]byte(val.k), []byte(val.v)) 293 } 294 tr.Commit(nil) 295 if !memonly { 296 triedb.Commit(tr.Hash(), true) 297 } 298 wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil) 299 300 var ( 301 diskKeys [][]byte 302 memKeys []common.Hash 303 ) 304 if memonly { 305 memKeys = triedb.Nodes() 306 } else { 307 diskKeys = diskdb.Keys() 308 } 309 for i := 0; i < 20; i++ { 310 // Create trie that will load all nodes from DB. 311 tr, _ := New(tr.Hash(), triedb) 312 313 // Remove a random node from the database. It can't be the root node 314 // because that one is already loaded. 315 var ( 316 rkey common.Hash 317 rval []byte 318 robj *cachedNode 319 ) 320 for { 321 if memonly { 322 rkey = memKeys[rand.Intn(len(memKeys))] 323 } else { 324 copy(rkey[:], diskKeys[rand.Intn(len(diskKeys))]) 325 } 326 if rkey != tr.Hash() { 327 break 328 } 329 } 330 if memonly { 331 robj = triedb.nodes[rkey] 332 delete(triedb.nodes, rkey) 333 } else { 334 rval, _ = diskdb.Get(rkey[:]) 335 diskdb.Delete(rkey[:]) 336 } 337 // Iterate until the error is hit. 338 seen := make(map[string]bool) 339 it := tr.NodeIterator(nil) 340 checkIteratorNoDups(t, it, seen) 341 missing, ok := it.Error().(*MissingNodeError) 342 if !ok || missing.NodeHash != rkey { 343 t.Fatal("didn't hit missing node, got", it.Error()) 344 } 345 346 // Add the node back and continue iteration. 347 if memonly { 348 triedb.nodes[rkey] = robj 349 } else { 350 diskdb.Put(rkey[:], rval) 351 } 352 checkIteratorNoDups(t, it, seen) 353 if it.Error() != nil { 354 t.Fatal("unexpected error", it.Error()) 355 } 356 if len(seen) != wantNodeCount { 357 t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount) 358 } 359 } 360 } 361 362 // Similar to the test above, this one checks that failure to create nodeIterator at a 363 // certain key prefix behaves correctly when Next is called. The expectation is that Next 364 // should retry seeking before returning true for the first time. 365 func TestIteratorContinueAfterSeekErrorDisk(t *testing.T) { 366 testIteratorContinueAfterSeekError(t, false) 367 } 368 func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) { 369 testIteratorContinueAfterSeekError(t, true) 370 } 371 372 func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { 373 // Commit test trie to db, then remove the node containing "bars". 374 diskdb, _ := ethdb.NewMemDatabase() 375 triedb := NewDatabase(diskdb) 376 377 ctr, _ := New(common.Hash{}, triedb) 378 for _, val := range testdata1 { 379 ctr.Update([]byte(val.k), []byte(val.v)) 380 } 381 root, _ := ctr.Commit(nil) 382 if !memonly { 383 triedb.Commit(root, true) 384 } 385 barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") 386 var ( 387 barNodeBlob []byte 388 barNodeObj *cachedNode 389 ) 390 if memonly { 391 barNodeObj = triedb.nodes[barNodeHash] 392 delete(triedb.nodes, barNodeHash) 393 } else { 394 barNodeBlob, _ = diskdb.Get(barNodeHash[:]) 395 diskdb.Delete(barNodeHash[:]) 396 } 397 // Create a new iterator that seeks to "bars". Seeking can't proceed because 398 // the node is missing. 399 tr, _ := New(root, triedb) 400 it := tr.NodeIterator([]byte("bars")) 401 missing, ok := it.Error().(*MissingNodeError) 402 if !ok { 403 t.Fatal("want MissingNodeError, got", it.Error()) 404 } else if missing.NodeHash != barNodeHash { 405 t.Fatal("wrong node missing") 406 } 407 // Reinsert the missing node. 408 if memonly { 409 triedb.nodes[barNodeHash] = barNodeObj 410 } else { 411 diskdb.Put(barNodeHash[:], barNodeBlob) 412 } 413 // Check that iteration produces the right set of values. 414 if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { 415 t.Fatal(err) 416 } 417 } 418 419 func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int { 420 if seen == nil { 421 seen = make(map[string]bool) 422 } 423 for it.Next(true) { 424 if seen[string(it.Path())] { 425 t.Fatalf("iterator visited node path %x twice", it.Path()) 426 } 427 seen[string(it.Path())] = true 428 } 429 return len(seen) 430 }