github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/trie/iterator_test.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package trie 18 19 import ( 20 "bytes" 21 "fmt" 22 "testing" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/ethdb" 26 ) 27 28 func TestIterator(t *testing.T) { 29 trie := newEmpty() 30 vals := []struct{ k, v string }{ 31 {"do", "verb"}, 32 {"ether", "wookiedoo"}, 33 {"horse", "stallion"}, 34 {"shaman", "horse"}, 35 {"doge", "coin"}, 36 {"dog", "puppy"}, 37 {"somethingveryoddindeedthis is", "myothernodedata"}, 38 } 39 all := make(map[string]string) 40 for _, val := range vals { 41 all[val.k] = val.v 42 trie.Update([]byte(val.k), []byte(val.v)) 43 } 44 trie.Commit() 45 46 found := make(map[string]string) 47 it := NewIterator(trie.NodeIterator(nil)) 48 for it.Next() { 49 found[string(it.Key)] = string(it.Value) 50 } 51 52 for k, v := range all { 53 if found[k] != v { 54 t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v) 55 } 56 } 57 } 58 59 type kv struct { 60 k, v []byte 61 t bool 62 } 63 64 func TestIteratorLargeData(t *testing.T) { 65 trie := newEmpty() 66 vals := make(map[string]*kv) 67 68 for i := byte(0); i < 255; i++ { 69 value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} 70 value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} 71 trie.Update(value.k, value.v) 72 trie.Update(value2.k, value2.v) 73 vals[string(value.k)] = value 74 vals[string(value2.k)] = value2 75 } 76 77 it := NewIterator(trie.NodeIterator(nil)) 78 for it.Next() { 79 vals[string(it.Key)].t = true 80 } 81 82 var untouched []*kv 83 for _, value := range vals { 84 if !value.t { 85 untouched = append(untouched, value) 86 } 87 } 88 89 if len(untouched) > 0 { 90 t.Errorf("Missed %d nodes", len(untouched)) 91 for _, value := range untouched { 92 t.Error(value) 93 } 94 } 95 } 96 97 // Tests that the node iterator indeed walks over the entire database contents. 98 func TestNodeIteratorCoverage(t *testing.T) { 99 // Create some arbitrary test trie to iterate 100 db, trie, _ := makeTestTrie() 101 102 // Gather all the node hashes found by the iterator 103 hashes := make(map[common.Hash]struct{}) 104 for it := trie.NodeIterator(nil); it.Next(true); { 105 if it.Hash() != (common.Hash{}) { 106 hashes[it.Hash()] = struct{}{} 107 } 108 } 109 // Cross check the hashes and the database itself 110 for hash := range hashes { 111 if _, err := db.Get(hash.Bytes()); err != nil { 112 t.Errorf("failed to retrieve reported node %x: %v", hash, err) 113 } 114 } 115 for _, key := range db.(*ethdb.MemDatabase).Keys() { 116 if _, ok := hashes[common.BytesToHash(key)]; !ok { 117 t.Errorf("state entry not reported %x", key) 118 } 119 } 120 } 121 122 type kvs struct{ k, v string } 123 124 var testdata1 = []kvs{ 125 {"barb", "ba"}, 126 {"bard", "bc"}, 127 {"bars", "bb"}, 128 {"bar", "b"}, 129 {"fab", "z"}, 130 {"food", "ab"}, 131 {"foos", "aa"}, 132 {"foo", "a"}, 133 } 134 135 var testdata2 = []kvs{ 136 {"aardvark", "c"}, 137 {"bar", "b"}, 138 {"barb", "bd"}, 139 {"bars", "be"}, 140 {"fab", "z"}, 141 {"foo", "a"}, 142 {"foos", "aa"}, 143 {"food", "ab"}, 144 {"jars", "d"}, 145 } 146 147 func TestIteratorSeek(t *testing.T) { 148 trie := newEmpty() 149 for _, val := range testdata1 { 150 trie.Update([]byte(val.k), []byte(val.v)) 151 } 152 153 // Seek to the middle. 154 it := NewIterator(trie.NodeIterator([]byte("fab"))) 155 if err := checkIteratorOrder(testdata1[4:], it); err != nil { 156 t.Fatal(err) 157 } 158 159 // Seek to a non-existent key. 160 it = NewIterator(trie.NodeIterator([]byte("barc"))) 161 if err := checkIteratorOrder(testdata1[1:], it); err != nil { 162 t.Fatal(err) 163 } 164 165 // Seek beyond the end. 166 it = NewIterator(trie.NodeIterator([]byte("z"))) 167 if err := checkIteratorOrder(nil, it); err != nil { 168 t.Fatal(err) 169 } 170 } 171 172 func checkIteratorOrder(want []kvs, it *Iterator) error { 173 for it.Next() { 174 if len(want) == 0 { 175 return fmt.Errorf("didn't expect any more values, got key %q", it.Key) 176 } 177 if !bytes.Equal(it.Key, []byte(want[0].k)) { 178 return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k) 179 } 180 want = want[1:] 181 } 182 if len(want) > 0 { 183 return fmt.Errorf("iterator ended early, want key %q", want[0]) 184 } 185 return nil 186 } 187 188 func TestDifferenceIterator(t *testing.T) { 189 triea := newEmpty() 190 for _, val := range testdata1 { 191 triea.Update([]byte(val.k), []byte(val.v)) 192 } 193 triea.Commit() 194 195 trieb := newEmpty() 196 for _, val := range testdata2 { 197 trieb.Update([]byte(val.k), []byte(val.v)) 198 } 199 trieb.Commit() 200 201 found := make(map[string]string) 202 di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil)) 203 it := NewIterator(di) 204 for it.Next() { 205 found[string(it.Key)] = string(it.Value) 206 } 207 208 all := []struct{ k, v string }{ 209 {"aardvark", "c"}, 210 {"barb", "bd"}, 211 {"bars", "be"}, 212 {"jars", "d"}, 213 } 214 for _, item := range all { 215 if found[item.k] != item.v { 216 t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v) 217 } 218 } 219 if len(found) != len(all) { 220 t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all)) 221 } 222 } 223 224 func TestUnionIterator(t *testing.T) { 225 triea := newEmpty() 226 for _, val := range testdata1 { 227 triea.Update([]byte(val.k), []byte(val.v)) 228 } 229 triea.Commit() 230 231 trieb := newEmpty() 232 for _, val := range testdata2 { 233 trieb.Update([]byte(val.k), []byte(val.v)) 234 } 235 trieb.Commit() 236 237 di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) 238 it := NewIterator(di) 239 240 all := []struct{ k, v string }{ 241 {"aardvark", "c"}, 242 {"barb", "bd"}, 243 {"barb", "ba"}, 244 {"bard", "bc"}, 245 {"bars", "bb"}, 246 {"bars", "be"}, 247 {"bar", "b"}, 248 {"fab", "z"}, 249 {"food", "ab"}, 250 {"foos", "aa"}, 251 {"foo", "a"}, 252 {"jars", "d"}, 253 } 254 255 for i, kv := range all { 256 if !it.Next() { 257 t.Errorf("Iterator ends prematurely at element %d", i) 258 } 259 if kv.k != string(it.Key) { 260 t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k) 261 } 262 if kv.v != string(it.Value) { 263 t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v) 264 } 265 } 266 if it.Next() { 267 t.Errorf("Iterator returned extra values.") 268 } 269 }