github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/mpt/trie_test.go (about) 1 package mpt 2 3 import ( 4 "testing" 5 6 "github.com/nspcc-dev/neo-go/internal/random" 7 "github.com/nspcc-dev/neo-go/pkg/core/storage" 8 "github.com/stretchr/testify/require" 9 ) 10 11 func newTestStore() *storage.MemCachedStore { 12 return storage.NewMemCachedStore(storage.NewMemoryStore()) 13 } 14 15 func newTestTrie(t *testing.T) *Trie { 16 b := NewBranchNode() 17 18 l1 := NewLeafNode([]byte{0xAB, 0xCD}) 19 b.Children[0] = NewExtensionNode([]byte{0x01}, l1) 20 21 l3 := NewLeafNode([]byte{}) 22 b.Children[1] = NewExtensionNode([]byte{0x03}, l3) 23 24 l2 := NewLeafNode([]byte{0x22, 0x22}) 25 b.Children[9] = NewExtensionNode([]byte{0x09}, l2) 26 27 v := NewLeafNode([]byte("hello")) 28 h := NewHashNode(v.Hash()) 29 b.Children[10] = NewExtensionNode([]byte{0x0e}, h) 30 31 e := NewExtensionNode(toNibbles([]byte{0xAC}), b) 32 tr := NewTrie(e, ModeAll, newTestStore()) 33 34 tr.putToStore(e) 35 tr.putToStore(b) 36 tr.putToStore(l1) 37 tr.putToStore(l2) 38 tr.putToStore(l3) 39 tr.putToStore(v) 40 tr.putToStore(b.Children[0]) 41 tr.putToStore(b.Children[1]) 42 tr.putToStore(b.Children[9]) 43 tr.putToStore(b.Children[10]) 44 45 return tr 46 } 47 48 func testTrieRefcount(t *testing.T, key1, key2 []byte) { 49 tr := NewTrie(nil, ModeLatest, storage.NewMemCachedStore(storage.NewMemoryStore())) 50 require.NoError(t, tr.Put(key1, []byte{1})) 51 tr.Flush(0) 52 require.NoError(t, tr.Put(key2, []byte{1})) 53 tr.Flush(0) 54 tr.testHas(t, key1, []byte{1}) 55 tr.testHas(t, key2, []byte{1}) 56 57 // remove first, keep second 58 require.NoError(t, tr.Delete(key1)) 59 tr.Flush(0) 60 tr.testHas(t, key1, nil) 61 tr.testHas(t, key2, []byte{1}) 62 63 // no-op 64 require.NoError(t, tr.Put(key1, []byte{1})) 65 require.NoError(t, tr.Delete(key1)) 66 tr.Flush(0) 67 tr.testHas(t, key1, nil) 68 tr.testHas(t, key2, []byte{1}) 69 70 // delete non-existent, refcount should not be updated 71 require.NoError(t, tr.Delete(key1)) 72 tr.Flush(0) 73 tr.testHas(t, key1, nil) 74 tr.testHas(t, key2, []byte{1}) 75 } 76 77 func TestTrie_Refcount(t *testing.T) { 78 t.Run("Leaf", func(t *testing.T) { 79 testTrieRefcount(t, []byte{0x11}, []byte{0x12}) 80 }) 81 t.Run("Extension", func(t *testing.T) { 82 testTrieRefcount(t, []byte{0x10, 11}, []byte{0x11, 12}) 83 }) 84 } 85 86 func TestTrie_PutIntoBranchNode(t *testing.T) { 87 check := func(t *testing.T, value []byte) { 88 b := NewBranchNode() 89 l := NewLeafNode([]byte{0x8}) 90 b.Children[0x7] = NewHashNode(l.Hash()) 91 b.Children[0x8] = NewHashNode(random.Uint256()) 92 tr := NewTrie(b, ModeAll, newTestStore()) 93 94 // empty hash node child 95 require.NoError(t, tr.Put([]byte{0x66}, value)) 96 tr.testHas(t, []byte{0x66}, value) 97 require.True(t, isValid(tr.root)) 98 99 // missing hash 100 require.Error(t, tr.Put([]byte{0x70}, value)) 101 require.True(t, isValid(tr.root)) 102 103 // hash is in store 104 tr.putToStore(l) 105 require.NoError(t, tr.Put([]byte{0x70}, value)) 106 require.True(t, isValid(tr.root)) 107 } 108 109 t.Run("non-empty value", func(t *testing.T) { 110 check(t, []byte{0x42}) 111 }) 112 t.Run("empty value", func(t *testing.T) { 113 check(t, []byte{}) 114 }) 115 } 116 117 func TestTrie_PutIntoExtensionNode(t *testing.T) { 118 check := func(t *testing.T, value []byte) { 119 l := NewLeafNode([]byte{0x11}) 120 key := []byte{0x12} 121 e := NewExtensionNode(toNibbles(key), NewHashNode(l.Hash())) 122 tr := NewTrie(e, ModeAll, newTestStore()) 123 124 // missing hash 125 require.Error(t, tr.Put(key, value)) 126 127 tr.putToStore(l) 128 require.NoError(t, tr.Put(key, value)) 129 tr.testHas(t, key, value) 130 require.True(t, isValid(tr.root)) 131 } 132 133 t.Run("non-empty value", func(t *testing.T) { 134 check(t, []byte{0x42}) 135 }) 136 t.Run("empty value", func(t *testing.T) { 137 check(t, []byte{}) 138 }) 139 } 140 141 func TestTrie_PutIntoHashNode(t *testing.T) { 142 check := func(t *testing.T, value []byte) { 143 b := NewBranchNode() 144 l := NewLeafNode(random.Bytes(5)) 145 e := NewExtensionNode([]byte{0x02}, l) 146 b.Children[1] = NewHashNode(e.Hash()) 147 b.Children[9] = NewHashNode(random.Uint256()) 148 tr := NewTrie(b, ModeAll, newTestStore()) 149 150 tr.putToStore(e) 151 152 t.Run("MissingLeafHash", func(t *testing.T) { 153 _, err := tr.Get([]byte{0x12}) 154 require.Error(t, err) 155 }) 156 157 tr.putToStore(l) 158 159 require.NoError(t, tr.Put([]byte{0x12, 0x34}, value)) 160 tr.testHas(t, []byte{0x12, 0x34}, value) 161 tr.testHas(t, []byte{0x12}, l.value) 162 require.True(t, isValid(tr.root)) 163 } 164 165 t.Run("non-empty value", func(t *testing.T) { 166 val := random.Bytes(3) 167 check(t, val) 168 }) 169 t.Run("empty value", func(t *testing.T) { 170 check(t, []byte{}) 171 }) 172 } 173 174 func TestTrie_Put(t *testing.T) { 175 trExp := newTestTrie(t) 176 177 trAct := NewTrie(nil, ModeAll, newTestStore()) 178 require.NoError(t, trAct.Put([]byte{0xAC, 0x01}, []byte{0xAB, 0xCD})) 179 require.NoError(t, trAct.Put([]byte{0xAC, 0x13}, []byte{})) 180 require.NoError(t, trAct.Put([]byte{0xAC, 0x99}, []byte{0x22, 0x22})) 181 require.NoError(t, trAct.Put([]byte{0xAC, 0xAE}, []byte("hello"))) 182 183 // Note: the exact tries differ because of ("acae":"hello") node is stored as Hash node in test trie. 184 require.Equal(t, trExp.root.Hash(), trAct.root.Hash()) 185 require.True(t, isValid(trAct.root)) 186 } 187 188 func TestTrie_PutInvalid(t *testing.T) { 189 tr := NewTrie(nil, ModeAll, newTestStore()) 190 key, value := []byte("key"), []byte("value") 191 192 // empty key 193 require.Error(t, tr.Put(nil, value)) 194 195 // big key 196 require.Error(t, tr.Put(make([]byte, maxPathLength+1), value)) 197 198 // big value 199 require.Error(t, tr.Put(key, make([]byte, MaxValueLength+1))) 200 201 // this is ok though 202 require.NoError(t, tr.Put(key, value)) 203 tr.testHas(t, key, value) 204 } 205 206 func TestTrie_BigPut(t *testing.T) { 207 tr := NewTrie(nil, ModeAll, newTestStore()) 208 items := []struct{ k, v string }{ 209 {"item with long key", "value1"}, 210 {"item with matching prefix", "value2"}, 211 {"another prefix", "value3"}, 212 {"another prefix 2", "value4"}, 213 {"another ", "value5"}, 214 } 215 216 for i := range items { 217 require.NoError(t, tr.Put([]byte(items[i].k), []byte(items[i].v))) 218 } 219 220 for i := range items { 221 tr.testHas(t, []byte(items[i].k), []byte(items[i].v)) 222 } 223 224 t.Run("Rewrite", func(t *testing.T) { 225 k, v := []byte(items[0].k), []byte{0x01, 0x23} 226 require.NoError(t, tr.Put(k, v)) 227 tr.testHas(t, k, v) 228 }) 229 230 t.Run("Rewrite to empty", func(t *testing.T) { 231 k, v := []byte(items[0].k), []byte{} 232 require.NoError(t, tr.Put(k, v)) 233 tr.testHas(t, k, v) 234 }) 235 236 t.Run("Remove", func(t *testing.T) { 237 k := []byte(items[1].k) 238 require.NoError(t, tr.Delete(k)) 239 tr.testHas(t, k, nil) 240 }) 241 } 242 243 func (tr *Trie) putToStore(n Node) { 244 if n.Type() == HashT { 245 panic("can't put hash node in trie") 246 } 247 if tr.mode.RC() { 248 tr.refcount[n.Hash()] = &cachedNode{ 249 bytes: n.Bytes(), 250 refcount: 1, 251 } 252 tr.updateRefCount(n.Hash(), makeStorageKey(n.Hash()), 0) 253 } else { 254 tr.Store.Put(makeStorageKey(n.Hash()), n.Bytes()) 255 } 256 } 257 258 func (tr *Trie) testHas(t *testing.T, key, value []byte) { 259 v, err := tr.Get(key) 260 if value == nil { 261 require.Error(t, err) 262 return 263 } 264 require.NoError(t, err) 265 require.Equal(t, value, v) 266 } 267 268 // isValid checks for 3 invariants: 269 // - BranchNode contains > 1 children 270 // - ExtensionNode do not contain another extension node 271 // - ExtensionNode do not have nil key 272 // It is used only during testing to catch possible bugs. 273 func isValid(curr Node) bool { 274 switch n := curr.(type) { 275 case *BranchNode: 276 var count int 277 for i := range n.Children { 278 if !isValid(n.Children[i]) { 279 return false 280 } 281 if !isEmpty(n.Children[i]) { 282 count++ 283 } 284 } 285 return count > 1 286 case *ExtensionNode: 287 _, ok := n.next.(*ExtensionNode) 288 return len(n.key) != 0 && !ok 289 default: 290 return true 291 } 292 } 293 294 func TestTrie_Get(t *testing.T) { 295 t.Run("HashNode", func(t *testing.T) { 296 tr := newTestTrie(t) 297 tr.testHas(t, []byte{0xAC, 0xAE}, []byte("hello")) 298 }) 299 t.Run("UnfoldRoot", func(t *testing.T) { 300 tr := newTestTrie(t) 301 single := NewTrie(NewHashNode(tr.root.Hash()), ModeAll, tr.Store) 302 single.testHas(t, []byte{0xAC}, nil) 303 single.testHas(t, []byte{0xAC, 0x01}, []byte{0xAB, 0xCD}) 304 single.testHas(t, []byte{0xAC, 0x99}, []byte{0x22, 0x22}) 305 single.testHas(t, []byte{0xAC, 0xAE}, []byte("hello")) 306 }) 307 } 308 309 func TestTrie_Flush(t *testing.T) { 310 pairs := map[string][]byte{ 311 "x": []byte("value0"), 312 "key1": []byte("value1"), 313 "key2": []byte("value2"), 314 } 315 316 tr := NewTrie(nil, ModeAll, newTestStore()) 317 for k, v := range pairs { 318 require.NoError(t, tr.Put([]byte(k), v)) 319 } 320 321 tr.Flush(0) 322 tr = NewTrie(NewHashNode(tr.StateRoot()), ModeAll, tr.Store) 323 for k, v := range pairs { 324 actual, err := tr.Get([]byte(k)) 325 require.NoError(t, err) 326 require.Equal(t, v, actual) 327 } 328 } 329 330 func TestTrie_Delete(t *testing.T) { 331 t.Run("No GC", func(t *testing.T) { 332 testTrieDelete(t, false) 333 }) 334 t.Run("With GC", func(t *testing.T) { 335 testTrieDelete(t, true) 336 }) 337 } 338 339 func testTrieDelete(t *testing.T, enableGC bool) { 340 var mode TrieMode 341 if enableGC { 342 mode = ModeLatest 343 } 344 t.Run("Hash", func(t *testing.T) { 345 t.Run("FromStore", func(t *testing.T) { 346 l := NewLeafNode([]byte{0x12}) 347 tr := NewTrie(NewHashNode(l.Hash()), mode, newTestStore()) 348 t.Run("NotInStore", func(t *testing.T) { 349 require.Error(t, tr.Delete([]byte{})) 350 }) 351 352 tr.putToStore(l) 353 tr.testHas(t, []byte{}, []byte{0x12}) 354 require.NoError(t, tr.Delete([]byte{})) 355 tr.testHas(t, []byte{}, nil) 356 }) 357 358 t.Run("Empty", func(t *testing.T) { 359 tr := NewTrie(nil, mode, newTestStore()) 360 require.NoError(t, tr.Delete([]byte{})) 361 }) 362 }) 363 364 t.Run("Leaf", func(t *testing.T) { 365 check := func(t *testing.T, value []byte) { 366 l := NewLeafNode(value) 367 tr := NewTrie(l, mode, newTestStore()) 368 t.Run("NonExistentKey", func(t *testing.T) { 369 require.NoError(t, tr.Delete([]byte{0x12})) 370 tr.testHas(t, []byte{}, value) 371 }) 372 require.NoError(t, tr.Delete([]byte{})) 373 tr.testHas(t, []byte{}, nil) 374 } 375 t.Run("non-empty value", func(t *testing.T) { 376 check(t, []byte{0x12, 0x34}) 377 }) 378 t.Run("empty value", func(t *testing.T) { 379 check(t, []byte{}) 380 }) 381 }) 382 383 t.Run("Extension", func(t *testing.T) { 384 t.Run("SingleKey", func(t *testing.T) { 385 check := func(t *testing.T, value []byte) { 386 l := NewLeafNode(value) 387 e := NewExtensionNode([]byte{0x0A, 0x0B}, l) 388 tr := NewTrie(e, mode, newTestStore()) 389 390 t.Run("NonExistentKey", func(t *testing.T) { 391 require.NoError(t, tr.Delete([]byte{})) 392 tr.testHas(t, []byte{0xAB}, value) 393 }) 394 395 require.NoError(t, tr.Delete([]byte{0xAB})) 396 require.IsType(t, EmptyNode{}, tr.root) 397 } 398 t.Run("non-empty value", func(t *testing.T) { 399 check(t, []byte{0x12, 0x34}) 400 }) 401 t.Run("empty value", func(t *testing.T) { 402 check(t, []byte{}) 403 }) 404 }) 405 406 t.Run("MultipleKeys", func(t *testing.T) { 407 check := func(t *testing.T, value []byte) { 408 b := NewBranchNode() 409 b.Children[0] = NewExtensionNode([]byte{0x01}, NewLeafNode(value)) 410 b.Children[6] = NewExtensionNode([]byte{0x07}, NewLeafNode([]byte{0x56, 0x78})) 411 e := NewExtensionNode([]byte{0x01, 0x02}, b) 412 tr := NewTrie(e, mode, newTestStore()) 413 414 h := e.Hash() 415 require.NoError(t, tr.Delete([]byte{0x12, 0x01})) 416 tr.testHas(t, []byte{0x12, 0x01}, nil) 417 tr.testHas(t, []byte{0x12, 0x67}, []byte{0x56, 0x78}) 418 419 require.NotEqual(t, h, tr.root.Hash()) 420 require.Equal(t, toNibbles([]byte{0x12, 0x67}), e.key) 421 require.IsType(t, (*LeafNode)(nil), e.next) 422 } 423 t.Run("non-empty value", func(t *testing.T) { 424 check(t, []byte{0x12, 0x34}) 425 }) 426 t.Run("empty value", func(t *testing.T) { 427 check(t, []byte{}) 428 }) 429 }) 430 }) 431 432 t.Run("Branch", func(t *testing.T) { 433 t.Run("3 Children", func(t *testing.T) { 434 check := func(t *testing.T, value []byte) { 435 b := NewBranchNode() 436 b.Children[lastChild] = NewLeafNode([]byte{0x12}) 437 b.Children[0] = NewExtensionNode([]byte{0x01}, NewLeafNode([]byte{0x34})) 438 b.Children[1] = NewExtensionNode([]byte{0x06}, NewLeafNode(value)) 439 tr := NewTrie(b, mode, newTestStore()) 440 require.NoError(t, tr.Delete([]byte{0x16})) 441 tr.testHas(t, []byte{}, []byte{0x12}) 442 tr.testHas(t, []byte{0x01}, []byte{0x34}) 443 tr.testHas(t, []byte{0x16}, nil) 444 } 445 t.Run("non-empty value", func(t *testing.T) { 446 check(t, []byte{0x56}) 447 }) 448 t.Run("empty value", func(t *testing.T) { 449 check(t, []byte{}) 450 }) 451 }) 452 t.Run("2 Children", func(t *testing.T) { 453 t.Run("DeleteLast", func(t *testing.T) { 454 t.Run("MergeExtension", func(t *testing.T) { 455 check := func(t *testing.T, value []byte) { 456 b := NewBranchNode() 457 b.Children[lastChild] = NewLeafNode(value) 458 l := NewLeafNode([]byte{0x34}) 459 e := NewExtensionNode([]byte{0x06}, l) 460 b.Children[5] = NewHashNode(e.Hash()) 461 tr := NewTrie(b, mode, newTestStore()) 462 tr.putToStore(l) 463 tr.putToStore(e) 464 require.NoError(t, tr.Delete([]byte{})) 465 tr.testHas(t, []byte{}, nil) 466 tr.testHas(t, []byte{0x56}, []byte{0x34}) 467 require.IsType(t, (*ExtensionNode)(nil), tr.root) 468 } 469 t.Run("non-empty value", func(t *testing.T) { 470 check(t, []byte{0x12}) 471 }) 472 t.Run("empty value", func(t *testing.T) { 473 check(t, []byte{}) 474 }) 475 476 t.Run("WithHash, branch node replaced", func(t *testing.T) { 477 check := func(t *testing.T, value []byte) { 478 ch := NewLeafNode([]byte{5, 6}) 479 h := ch.Hash() 480 481 b := NewBranchNode() 482 b.Children[3] = NewExtensionNode([]byte{4}, NewLeafNode(value)) 483 b.Children[lastChild] = NewHashNode(h) 484 485 tr := NewTrie(NewExtensionNode([]byte{1, 2}, b), mode, newTestStore()) 486 tr.putToStore(ch) 487 488 require.NoError(t, tr.Delete([]byte{0x12, 0x34})) 489 tr.testHas(t, []byte{0x12, 0x34}, nil) 490 tr.testHas(t, []byte{0x12}, []byte{5, 6}) 491 require.IsType(t, (*ExtensionNode)(nil), tr.root) 492 require.Equal(t, h, tr.root.(*ExtensionNode).next.Hash()) 493 } 494 t.Run("non-empty value", func(t *testing.T) { 495 check(t, []byte{1, 2, 3}) 496 }) 497 t.Run("empty value", func(t *testing.T) { 498 check(t, []byte{}) 499 }) 500 }) 501 }) 502 503 t.Run("LeaveLeaf", func(t *testing.T) { 504 check := func(t *testing.T, value []byte) { 505 c := NewBranchNode() 506 c.Children[5] = NewLeafNode([]byte{0x05}) 507 c.Children[6] = NewLeafNode([]byte{0x06}) 508 509 b := NewBranchNode() 510 b.Children[lastChild] = NewLeafNode(value) 511 b.Children[5] = c 512 tr := NewTrie(b, mode, newTestStore()) 513 514 require.NoError(t, tr.Delete([]byte{})) 515 tr.testHas(t, []byte{}, nil) 516 tr.testHas(t, []byte{0x55}, []byte{0x05}) 517 tr.testHas(t, []byte{0x56}, []byte{0x06}) 518 require.IsType(t, (*ExtensionNode)(nil), tr.root) 519 } 520 t.Run("non-empty value", func(t *testing.T) { 521 check(t, []byte{0x12}) 522 }) 523 t.Run("empty value", func(t *testing.T) { 524 check(t, []byte{}) 525 }) 526 }) 527 }) 528 529 t.Run("DeleteMiddle", func(t *testing.T) { 530 check := func(t *testing.T, value []byte) { 531 b := NewBranchNode() 532 b.Children[lastChild] = NewLeafNode([]byte{0x12}) 533 l := NewLeafNode(value) 534 e := NewExtensionNode([]byte{0x06}, l) 535 b.Children[5] = NewHashNode(e.Hash()) 536 tr := NewTrie(b, mode, newTestStore()) 537 tr.putToStore(l) 538 tr.putToStore(e) 539 require.NoError(t, tr.Delete([]byte{0x56})) 540 tr.testHas(t, []byte{}, []byte{0x12}) 541 tr.testHas(t, []byte{0x56}, nil) 542 require.IsType(t, (*LeafNode)(nil), tr.root) 543 } 544 t.Run("non-empty value", func(t *testing.T) { 545 check(t, []byte{0x34}) 546 }) 547 t.Run("empty value", func(t *testing.T) { 548 check(t, []byte{}) 549 }) 550 }) 551 }) 552 }) 553 } 554 555 func TestTrie_PanicInvalidRoot(t *testing.T) { 556 tr := &Trie{Store: newTestStore()} 557 require.Panics(t, func() { _ = tr.Put([]byte{1}, []byte{2}) }) 558 require.Panics(t, func() { _, _ = tr.Get([]byte{1}) }) 559 require.Panics(t, func() { _ = tr.Delete([]byte{1}) }) 560 } 561 562 func TestTrie_Collapse(t *testing.T) { 563 t.Run("PanicNegative", func(t *testing.T) { 564 tr := newTestTrie(t) 565 require.Panics(t, func() { tr.Collapse(-1) }) 566 }) 567 t.Run("Depth=0", func(t *testing.T) { 568 tr := newTestTrie(t) 569 h := tr.root.Hash() 570 571 _, ok := tr.root.(*HashNode) 572 require.False(t, ok) 573 574 tr.Collapse(0) 575 _, ok = tr.root.(*HashNode) 576 require.True(t, ok) 577 require.Equal(t, h, tr.root.Hash()) 578 }) 579 t.Run("Branch,Depth=1", func(t *testing.T) { 580 b := NewBranchNode() 581 e := NewExtensionNode([]byte{0x01}, NewLeafNode([]byte("value1"))) 582 he := e.Hash() 583 b.Children[0] = e 584 hb := b.Hash() 585 586 tr := NewTrie(b, ModeAll, newTestStore()) 587 tr.Collapse(1) 588 589 newb, ok := tr.root.(*BranchNode) 590 require.True(t, ok) 591 require.Equal(t, hb, newb.Hash()) 592 require.IsType(t, (*HashNode)(nil), b.Children[0]) 593 require.Equal(t, he, b.Children[0].Hash()) 594 }) 595 t.Run("Extension,Depth=1", func(t *testing.T) { 596 l := NewLeafNode([]byte("value")) 597 hl := l.Hash() 598 e := NewExtensionNode([]byte{0x01}, l) 599 h := e.Hash() 600 tr := NewTrie(e, ModeAll, newTestStore()) 601 tr.Collapse(1) 602 603 newe, ok := tr.root.(*ExtensionNode) 604 require.True(t, ok) 605 require.Equal(t, h, newe.Hash()) 606 require.IsType(t, (*HashNode)(nil), newe.next) 607 require.Equal(t, hl, newe.next.Hash()) 608 }) 609 t.Run("Leaf", func(t *testing.T) { 610 l := NewLeafNode([]byte("value")) 611 tr := NewTrie(l, ModeAll, newTestStore()) 612 tr.Collapse(10) 613 require.Equal(t, NewLeafNode([]byte("value")), tr.root) 614 }) 615 t.Run("Empty Leaf", func(t *testing.T) { 616 l := NewLeafNode([]byte{}) 617 tr := NewTrie(l, ModeAll, newTestStore()) 618 tr.Collapse(10) 619 require.Equal(t, NewLeafNode([]byte{}), tr.root) 620 }) 621 t.Run("Hash", func(t *testing.T) { 622 t.Run("EmptyNode", func(t *testing.T) { 623 tr := NewTrie(EmptyNode{}, ModeAll, newTestStore()) 624 require.NotPanics(t, func() { tr.Collapse(1) }) 625 _, ok := tr.root.(EmptyNode) 626 require.True(t, ok) 627 }) 628 629 h := random.Uint256() 630 hn := NewHashNode(h) 631 tr := NewTrie(hn, ModeAll, newTestStore()) 632 tr.Collapse(10) 633 634 newRoot, ok := tr.root.(*HashNode) 635 require.True(t, ok) 636 require.Equal(t, NewHashNode(h), newRoot) 637 }) 638 } 639 640 func TestTrie_Seek(t *testing.T) { 641 tr := newTestTrie(t) 642 t.Run("extension", func(t *testing.T) { 643 check := func(t *testing.T, prefix []byte) { 644 _, res, prefix, err := tr.getWithPath(tr.root, prefix, false) 645 require.NoError(t, err) 646 require.Equal(t, []byte{0x0A, 0x0C}, prefix) 647 require.Equal(t, BranchT, res.Type()) // extension's next is branch 648 } 649 t.Run("seek prefix points to extension", func(t *testing.T) { 650 check(t, []byte{}) 651 }) 652 t.Run("seek prefix is a part of extension key", func(t *testing.T) { 653 check(t, []byte{0x0A}) 654 }) 655 t.Run("seek prefix match extension key", func(t *testing.T) { 656 check(t, []byte{0x0A, 0x0C}) // path to extension's next 657 }) 658 }) 659 t.Run("branch", func(t *testing.T) { 660 t.Run("seek prefix points to branch", func(t *testing.T) { 661 _, res, prefix, err := tr.getWithPath(tr.root, []byte{0x0A, 0x0C}, false) 662 require.NoError(t, err) 663 require.Equal(t, []byte{0x0A, 0x0C}, prefix) 664 require.Equal(t, BranchT, res.Type()) 665 }) 666 t.Run("seek prefix points to empty branch child", func(t *testing.T) { 667 _, _, _, err := tr.getWithPath(tr.root, []byte{0x0A, 0x0C, 0x02}, false) 668 require.Error(t, err) 669 }) 670 t.Run("seek prefix points to non-empty branch child", func(t *testing.T) { 671 _, res, prefix, err := tr.getWithPath(tr.root, []byte{0x0A, 0x0C, 0x01}, false) 672 require.NoError(t, err) 673 require.Equal(t, []byte{0x0A, 0x0C, 0x01, 0x03}, prefix) 674 require.Equal(t, LeafT, res.Type()) 675 }) 676 }) 677 t.Run("leaf", func(t *testing.T) { 678 t.Run("seek prefix points to leaf", func(t *testing.T) { 679 _, res, prefix, err := tr.getWithPath(tr.root, []byte{0x0A, 0x0C, 0x01, 0x03}, false) 680 require.NoError(t, err) 681 require.Equal(t, []byte{0x0A, 0x0C, 0x01, 0x03}, prefix) 682 require.Equal(t, LeafT, res.Type()) 683 }) 684 }) 685 t.Run("hash", func(t *testing.T) { 686 t.Run("seek prefix points to hash", func(t *testing.T) { 687 _, res, prefix, err := tr.getWithPath(tr.root, []byte{0x0A, 0x0C, 0x0A, 0x0E}, false) 688 require.NoError(t, err) 689 require.Equal(t, []byte{0x0A, 0x0C, 0x0A, 0x0E}, prefix) 690 require.Equal(t, LeafT, res.Type()) 691 }) 692 }) 693 }