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  }