github.com/MetalBlockchain/metalgo@v1.11.9/x/merkledb/trie_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package merkledb
     5  
     6  import (
     7  	"context"
     8  	"math/rand"
     9  	"strconv"
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/MetalBlockchain/metalgo/database"
    16  	"github.com/MetalBlockchain/metalgo/database/memdb"
    17  	"github.com/MetalBlockchain/metalgo/ids"
    18  	"github.com/MetalBlockchain/metalgo/utils/hashing"
    19  )
    20  
    21  func getNodeValue(t Trie, key string) ([]byte, error) {
    22  	path := ToKey([]byte(key))
    23  	if asView, ok := t.(*view); ok {
    24  		if err := asView.applyValueChanges(context.Background()); err != nil {
    25  			return nil, err
    26  		}
    27  	}
    28  
    29  	var result *node
    30  
    31  	err := visitPathToKey(t, path, func(n *node) error {
    32  		result = n
    33  		return nil
    34  	})
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	if result == nil || result.key != path {
    39  		return nil, database.ErrNotFound
    40  	}
    41  
    42  	return result.value.Value(), nil
    43  }
    44  
    45  func Test_GetValue_Safety(t *testing.T) {
    46  	require := require.New(t)
    47  
    48  	db, err := getBasicDB()
    49  	require.NoError(err)
    50  
    51  	view, err := db.NewView(
    52  		context.Background(),
    53  		ViewChanges{
    54  			BatchOps: []database.BatchOp{
    55  				{Key: []byte{0}, Value: []byte{0}},
    56  			},
    57  		},
    58  	)
    59  	require.NoError(err)
    60  
    61  	trieVal, err := view.GetValue(context.Background(), []byte{0})
    62  	require.NoError(err)
    63  	require.Equal([]byte{0}, trieVal)
    64  	trieVal[0] = 1
    65  
    66  	// should still be []byte{0} after edit
    67  	trieVal, err = view.GetValue(context.Background(), []byte{0})
    68  	require.NoError(err)
    69  	require.Equal([]byte{0}, trieVal)
    70  }
    71  
    72  func Test_GetValues_Safety(t *testing.T) {
    73  	require := require.New(t)
    74  
    75  	db, err := getBasicDB()
    76  	require.NoError(err)
    77  
    78  	view, err := db.NewView(
    79  		context.Background(),
    80  		ViewChanges{
    81  			BatchOps: []database.BatchOp{
    82  				{Key: []byte{0}, Value: []byte{0}},
    83  			},
    84  		},
    85  	)
    86  	require.NoError(err)
    87  
    88  	trieVals, errs := view.GetValues(context.Background(), [][]byte{{0}})
    89  	require.Len(errs, 1)
    90  	require.NoError(errs[0])
    91  	require.Equal([]byte{0}, trieVals[0])
    92  	trieVals[0][0] = 1
    93  	require.Equal([]byte{1}, trieVals[0])
    94  
    95  	// should still be []byte{0} after edit
    96  	trieVals, errs = view.GetValues(context.Background(), [][]byte{{0}})
    97  	require.Len(errs, 1)
    98  	require.NoError(errs[0])
    99  	require.Equal([]byte{0}, trieVals[0])
   100  }
   101  
   102  func TestVisitPathToKey(t *testing.T) {
   103  	require := require.New(t)
   104  
   105  	db, err := getBasicDB()
   106  	require.NoError(err)
   107  
   108  	trieIntf, err := db.NewView(context.Background(), ViewChanges{})
   109  	require.NoError(err)
   110  	require.IsType(&view{}, trieIntf)
   111  	trie := trieIntf.(*view)
   112  
   113  	var nodePath []*node
   114  	require.NoError(visitPathToKey(trie, ToKey(nil), func(n *node) error {
   115  		nodePath = append(nodePath, n)
   116  		return nil
   117  	}))
   118  
   119  	require.Empty(nodePath)
   120  
   121  	// Insert a key
   122  	key1 := []byte{0}
   123  	trieIntf, err = trie.NewView(
   124  		context.Background(),
   125  		ViewChanges{
   126  			BatchOps: []database.BatchOp{
   127  				{Key: key1, Value: []byte("value")},
   128  			},
   129  		},
   130  	)
   131  	require.NoError(err)
   132  	require.IsType(&view{}, trieIntf)
   133  	trie = trieIntf.(*view)
   134  	require.NoError(trie.applyValueChanges(context.Background()))
   135  
   136  	nodePath = make([]*node, 0, 1)
   137  	require.NoError(visitPathToKey(trie, ToKey(key1), func(n *node) error {
   138  		nodePath = append(nodePath, n)
   139  		return nil
   140  	}))
   141  
   142  	// 1 value
   143  	require.Len(nodePath, 1)
   144  	require.Equal(ToKey(key1), nodePath[0].key)
   145  
   146  	// Insert another key which is a child of the first
   147  	key2 := []byte{0, 1}
   148  	trieIntf, err = trie.NewView(
   149  		context.Background(),
   150  		ViewChanges{
   151  			BatchOps: []database.BatchOp{
   152  				{Key: key2, Value: []byte("value")},
   153  			},
   154  		},
   155  	)
   156  	require.NoError(err)
   157  	require.IsType(&view{}, trieIntf)
   158  	trie = trieIntf.(*view)
   159  	require.NoError(trie.applyValueChanges(context.Background()))
   160  
   161  	nodePath = make([]*node, 0, 2)
   162  	require.NoError(visitPathToKey(trie, ToKey(key2), func(n *node) error {
   163  		nodePath = append(nodePath, n)
   164  		return nil
   165  	}))
   166  	require.Len(nodePath, 2)
   167  	require.Equal(trie.root.Value(), nodePath[0])
   168  	require.Equal(ToKey(key1), nodePath[0].key)
   169  	require.Equal(ToKey(key2), nodePath[1].key)
   170  
   171  	// Trie is:
   172  	// [0]
   173  	//  |
   174  	// [0,1]
   175  	// Insert a key which shares no prefix with the others
   176  	key3 := []byte{255}
   177  	trieIntf, err = trie.NewView(
   178  		context.Background(),
   179  		ViewChanges{
   180  			BatchOps: []database.BatchOp{
   181  				{Key: key3, Value: []byte("value")},
   182  			},
   183  		},
   184  	)
   185  	require.NoError(err)
   186  	require.IsType(&view{}, trieIntf)
   187  	trie = trieIntf.(*view)
   188  	require.NoError(trie.applyValueChanges(context.Background()))
   189  
   190  	// Trie is:
   191  	//    []
   192  	//   /  \
   193  	// [0]  [255]
   194  	//  |
   195  	// [0,1]
   196  	nodePath = make([]*node, 0, 2)
   197  	require.NoError(visitPathToKey(trie, ToKey(key3), func(n *node) error {
   198  		nodePath = append(nodePath, n)
   199  		return nil
   200  	}))
   201  
   202  	require.Len(nodePath, 2)
   203  	require.Equal(trie.root.Value(), nodePath[0])
   204  	require.Zero(trie.root.Value().key.length)
   205  	require.Equal(ToKey(key3), nodePath[1].key)
   206  
   207  	// Other key path not affected
   208  	nodePath = make([]*node, 0, 3)
   209  	require.NoError(visitPathToKey(trie, ToKey(key2), func(n *node) error {
   210  		nodePath = append(nodePath, n)
   211  		return nil
   212  	}))
   213  	require.Len(nodePath, 3)
   214  	require.Equal(trie.root.Value(), nodePath[0])
   215  	require.Equal(ToKey(key1), nodePath[1].key)
   216  	require.Equal(ToKey(key2), nodePath[2].key)
   217  
   218  	// Gets closest node when key doesn't exist
   219  	key4 := []byte{0, 1, 2}
   220  	nodePath = make([]*node, 0, 3)
   221  	require.NoError(visitPathToKey(trie, ToKey(key4), func(n *node) error {
   222  		nodePath = append(nodePath, n)
   223  		return nil
   224  	}))
   225  
   226  	require.Len(nodePath, 3)
   227  	require.Equal(trie.root.Value(), nodePath[0])
   228  	require.Equal(ToKey(key1), nodePath[1].key)
   229  	require.Equal(ToKey(key2), nodePath[2].key)
   230  
   231  	// Gets just root when key doesn't exist and no key shares a prefix
   232  	key5 := []byte{128}
   233  	nodePath = make([]*node, 0, 1)
   234  	require.NoError(visitPathToKey(trie, ToKey(key5), func(n *node) error {
   235  		nodePath = append(nodePath, n)
   236  		return nil
   237  	}))
   238  	require.Len(nodePath, 1)
   239  	require.Equal(trie.root.Value(), nodePath[0])
   240  }
   241  
   242  func Test_Trie_ViewOnCommitedView(t *testing.T) {
   243  	require := require.New(t)
   244  
   245  	dbTrie, err := getBasicDB()
   246  	require.NoError(err)
   247  	require.NotNil(dbTrie)
   248  
   249  	committedTrie, err := dbTrie.NewView(
   250  		context.Background(),
   251  		ViewChanges{
   252  			BatchOps: []database.BatchOp{
   253  				{Key: []byte{0}, Value: []byte{0}},
   254  			},
   255  		},
   256  	)
   257  	require.NoError(err)
   258  
   259  	require.NoError(committedTrie.CommitToDB(context.Background()))
   260  
   261  	view, err := committedTrie.NewView(
   262  		context.Background(),
   263  		ViewChanges{
   264  			BatchOps: []database.BatchOp{
   265  				{Key: []byte{1}, Value: []byte{1}},
   266  			},
   267  		},
   268  	)
   269  	require.NoError(err)
   270  	require.NoError(view.CommitToDB(context.Background()))
   271  
   272  	val0, err := dbTrie.GetValue(context.Background(), []byte{0})
   273  	require.NoError(err)
   274  	require.Equal([]byte{0}, val0)
   275  	val1, err := dbTrie.GetValue(context.Background(), []byte{1})
   276  	require.NoError(err)
   277  	require.Equal([]byte{1}, val1)
   278  }
   279  
   280  func Test_Trie_WriteToDB(t *testing.T) {
   281  	require := require.New(t)
   282  
   283  	dbTrie, err := getBasicDB()
   284  	require.NoError(err)
   285  	require.NotNil(dbTrie)
   286  
   287  	trieIntf1, err := dbTrie.NewView(context.Background(), ViewChanges{})
   288  	require.NoError(err)
   289  	trie1 := trieIntf1.(*view)
   290  
   291  	// value hasn't been inserted so shouldn't exist
   292  	value, err := trie1.GetValue(context.Background(), []byte("key"))
   293  	require.ErrorIs(err, database.ErrNotFound)
   294  	require.Nil(value)
   295  
   296  	trieIntf2, err := trie1.NewView(
   297  		context.Background(),
   298  		ViewChanges{
   299  			BatchOps: []database.BatchOp{
   300  				{Key: []byte("key"), Value: []byte("value")},
   301  			},
   302  		},
   303  	)
   304  	require.NoError(err)
   305  	trie2 := trieIntf2.(*view)
   306  
   307  	value, err = getNodeValue(trie2, "key")
   308  	require.NoError(err)
   309  	require.Equal([]byte("value"), value)
   310  
   311  	require.NoError(trie1.CommitToDB(context.Background()))
   312  	require.NoError(trie2.CommitToDB(context.Background()))
   313  
   314  	key := []byte("key")
   315  	prefixedKey := make([]byte, len(key)+valueNodePrefixLen)
   316  	copy(prefixedKey, valueNodePrefix)
   317  	copy(prefixedKey[valueNodePrefixLen:], key)
   318  	rawBytes, err := dbTrie.baseDB.Get(prefixedKey)
   319  	require.NoError(err)
   320  
   321  	node, err := parseNode(dbTrie.hasher, ToKey(key), rawBytes)
   322  	require.NoError(err)
   323  	require.Equal([]byte("value"), node.value.Value())
   324  }
   325  
   326  func Test_Trie_InsertAndRetrieve(t *testing.T) {
   327  	require := require.New(t)
   328  
   329  	dbTrie, err := getBasicDB()
   330  	require.NoError(err)
   331  	require.NotNil(dbTrie)
   332  
   333  	// value hasn't been inserted so shouldn't exist
   334  	value, err := dbTrie.Get([]byte("key"))
   335  	require.ErrorIs(err, database.ErrNotFound)
   336  	require.Nil(value)
   337  
   338  	require.NoError(dbTrie.Put([]byte("key"), []byte("value")))
   339  
   340  	value, err = getNodeValue(dbTrie, "key")
   341  	require.NoError(err)
   342  	require.Equal([]byte("value"), value)
   343  }
   344  
   345  func Test_Trie_Overwrite(t *testing.T) {
   346  	require := require.New(t)
   347  
   348  	dbTrie, err := getBasicDB()
   349  	require.NoError(err)
   350  	require.NotNil(dbTrie)
   351  	trie, err := dbTrie.NewView(
   352  		context.Background(),
   353  		ViewChanges{
   354  			BatchOps: []database.BatchOp{
   355  				{Key: []byte("key"), Value: []byte("value0")},
   356  				{Key: []byte("key"), Value: []byte("value1")},
   357  			},
   358  		},
   359  	)
   360  	require.NoError(err)
   361  	value, err := getNodeValue(trie, "key")
   362  	require.NoError(err)
   363  	require.Equal([]byte("value1"), value)
   364  
   365  	trie, err = dbTrie.NewView(
   366  		context.Background(),
   367  		ViewChanges{
   368  			BatchOps: []database.BatchOp{
   369  				{Key: []byte("key"), Value: []byte("value2")},
   370  			},
   371  		},
   372  	)
   373  	require.NoError(err)
   374  	value, err = getNodeValue(trie, "key")
   375  	require.NoError(err)
   376  	require.Equal([]byte("value2"), value)
   377  }
   378  
   379  func Test_Trie_Delete(t *testing.T) {
   380  	require := require.New(t)
   381  
   382  	dbTrie, err := getBasicDB()
   383  	require.NoError(err)
   384  	require.NotNil(dbTrie)
   385  
   386  	trie, err := dbTrie.NewView(
   387  		context.Background(),
   388  		ViewChanges{
   389  			BatchOps: []database.BatchOp{
   390  				{Key: []byte("key"), Value: []byte("value0")},
   391  			},
   392  		},
   393  	)
   394  	require.NoError(err)
   395  
   396  	value, err := getNodeValue(trie, "key")
   397  	require.NoError(err)
   398  	require.Equal([]byte("value0"), value)
   399  
   400  	trie, err = dbTrie.NewView(
   401  		context.Background(),
   402  		ViewChanges{
   403  			BatchOps: []database.BatchOp{
   404  				{Key: []byte("key"), Delete: true},
   405  			},
   406  		},
   407  	)
   408  	require.NoError(err)
   409  
   410  	value, err = getNodeValue(trie, "key")
   411  	require.ErrorIs(err, database.ErrNotFound)
   412  	require.Nil(value)
   413  }
   414  
   415  func Test_Trie_DeleteMissingKey(t *testing.T) {
   416  	require := require.New(t)
   417  
   418  	trie, err := getBasicDB()
   419  	require.NoError(err)
   420  	require.NotNil(trie)
   421  
   422  	require.NoError(trie.DeleteContext(context.Background(), []byte("key")))
   423  }
   424  
   425  func Test_Trie_ExpandOnKeyPath(t *testing.T) {
   426  	require := require.New(t)
   427  
   428  	dbTrie, err := getBasicDB()
   429  	require.NoError(err)
   430  	require.NotNil(dbTrie)
   431  	trieIntf, err := dbTrie.NewView(
   432  		context.Background(),
   433  		ViewChanges{
   434  			BatchOps: []database.BatchOp{
   435  				{Key: []byte("key"), Value: []byte("value0")},
   436  			},
   437  		},
   438  	)
   439  	require.NoError(err)
   440  	trie := trieIntf.(*view)
   441  
   442  	value, err := getNodeValue(trie, "key")
   443  	require.NoError(err)
   444  	require.Equal([]byte("value0"), value)
   445  
   446  	trieIntf, err = trie.NewView(
   447  		context.Background(),
   448  		ViewChanges{
   449  			BatchOps: []database.BatchOp{
   450  				{Key: []byte("key1"), Value: []byte("value1")},
   451  			},
   452  		},
   453  	)
   454  	require.NoError(err)
   455  	trie = trieIntf.(*view)
   456  
   457  	value, err = getNodeValue(trie, "key")
   458  	require.NoError(err)
   459  	require.Equal([]byte("value0"), value)
   460  
   461  	value, err = getNodeValue(trie, "key1")
   462  	require.NoError(err)
   463  	require.Equal([]byte("value1"), value)
   464  
   465  	trieIntf, err = trie.NewView(
   466  		context.Background(),
   467  		ViewChanges{
   468  			BatchOps: []database.BatchOp{
   469  				{Key: []byte("key12"), Value: []byte("value12")},
   470  			},
   471  		},
   472  	)
   473  	require.NoError(err)
   474  	trie = trieIntf.(*view)
   475  
   476  	value, err = getNodeValue(trie, "key")
   477  	require.NoError(err)
   478  	require.Equal([]byte("value0"), value)
   479  
   480  	value, err = getNodeValue(trie, "key1")
   481  	require.NoError(err)
   482  	require.Equal([]byte("value1"), value)
   483  
   484  	value, err = getNodeValue(trie, "key12")
   485  	require.NoError(err)
   486  	require.Equal([]byte("value12"), value)
   487  }
   488  
   489  func Test_Trie_CompressedKeys(t *testing.T) {
   490  	require := require.New(t)
   491  
   492  	dbTrie, err := getBasicDB()
   493  	require.NoError(err)
   494  	require.NotNil(dbTrie)
   495  	trieIntf, err := dbTrie.NewView(
   496  		context.Background(),
   497  		ViewChanges{
   498  			BatchOps: []database.BatchOp{
   499  				{Key: []byte("key12"), Value: []byte("value12")},
   500  			},
   501  		},
   502  	)
   503  	require.NoError(err)
   504  	trie := trieIntf.(*view)
   505  
   506  	value, err := getNodeValue(trie, "key12")
   507  	require.NoError(err)
   508  	require.Equal([]byte("value12"), value)
   509  
   510  	trieIntf, err = trie.NewView(
   511  		context.Background(),
   512  		ViewChanges{
   513  			BatchOps: []database.BatchOp{
   514  				{Key: []byte("key1"), Value: []byte("value1")},
   515  			},
   516  		},
   517  	)
   518  	require.NoError(err)
   519  	trie = trieIntf.(*view)
   520  
   521  	value, err = getNodeValue(trie, "key12")
   522  	require.NoError(err)
   523  	require.Equal([]byte("value12"), value)
   524  
   525  	value, err = getNodeValue(trie, "key1")
   526  	require.NoError(err)
   527  	require.Equal([]byte("value1"), value)
   528  
   529  	trieIntf, err = trie.NewView(
   530  		context.Background(),
   531  		ViewChanges{
   532  			BatchOps: []database.BatchOp{
   533  				{Key: []byte("key"), Value: []byte("value")},
   534  			},
   535  		},
   536  	)
   537  	require.NoError(err)
   538  	trie = trieIntf.(*view)
   539  
   540  	value, err = getNodeValue(trie, "key12")
   541  	require.NoError(err)
   542  	require.Equal([]byte("value12"), value)
   543  
   544  	value, err = getNodeValue(trie, "key1")
   545  	require.NoError(err)
   546  	require.Equal([]byte("value1"), value)
   547  
   548  	value, err = getNodeValue(trie, "key")
   549  	require.NoError(err)
   550  	require.Equal([]byte("value"), value)
   551  }
   552  
   553  func Test_Trie_SplitBranch(t *testing.T) {
   554  	require := require.New(t)
   555  
   556  	dbTrie, err := getBasicDB()
   557  	require.NoError(err)
   558  	require.NotNil(dbTrie)
   559  
   560  	// force a new node to generate with common prefix "key1" and have these two nodes as children
   561  	trie, err := dbTrie.NewView(
   562  		context.Background(),
   563  		ViewChanges{
   564  			BatchOps: []database.BatchOp{
   565  				{Key: []byte("key12"), Value: []byte("value12")},
   566  				{Key: []byte("key134"), Value: []byte("value134")},
   567  			},
   568  		},
   569  	)
   570  	require.NoError(err)
   571  
   572  	value, err := getNodeValue(trie, "key12")
   573  	require.NoError(err)
   574  	require.Equal([]byte("value12"), value)
   575  
   576  	value, err = getNodeValue(trie, "key134")
   577  	require.NoError(err)
   578  	require.Equal([]byte("value134"), value)
   579  }
   580  
   581  func Test_Trie_HashCountOnBranch(t *testing.T) {
   582  	require := require.New(t)
   583  
   584  	dbTrie, err := getBasicDB()
   585  	require.NoError(err)
   586  	require.NotNil(dbTrie)
   587  
   588  	key1, key2, keyPrefix := []byte("12"), []byte("1F"), []byte("1")
   589  
   590  	view1, err := dbTrie.NewView(
   591  		context.Background(),
   592  		ViewChanges{
   593  			BatchOps: []database.BatchOp{
   594  				{Key: key1, Value: []byte("")},
   595  			},
   596  		})
   597  	require.NoError(err)
   598  
   599  	// trie is:
   600  	// [1]
   601  
   602  	// create new node with common prefix whose children
   603  	// are key1, key2
   604  	view2, err := view1.NewView(
   605  		context.Background(),
   606  		ViewChanges{
   607  			BatchOps: []database.BatchOp{
   608  				{Key: key2, Value: []byte("")},
   609  			},
   610  		})
   611  	require.NoError(err)
   612  
   613  	// trie is:
   614  	//    [1]
   615  	//    /  \
   616  	// [12]  [1F]
   617  
   618  	// clear the hash count to ignore setup
   619  	dbTrie.metrics.(*mockMetrics).hashCount = 0
   620  
   621  	// calculate the root
   622  	_, err = view2.GetMerkleRoot(context.Background())
   623  	require.NoError(err)
   624  
   625  	// Make sure the root is an intermediate node with the expected common prefix.
   626  	// Note it's only created on call to GetMerkleRoot, not in NewView.
   627  	prefixNode, err := view2.getEditableNode(ToKey(keyPrefix), false)
   628  	require.NoError(err)
   629  	root := view2.getRoot().Value()
   630  	require.Equal(root, prefixNode)
   631  	require.Len(root.children, 2)
   632  
   633  	// Had to hash each of the new nodes ("12" and "1F") and the new root
   634  	require.Equal(int64(3), dbTrie.metrics.(*mockMetrics).hashCount)
   635  }
   636  
   637  func Test_Trie_HashCountOnDelete(t *testing.T) {
   638  	require := require.New(t)
   639  
   640  	dbTrie, err := getBasicDB()
   641  	require.NoError(err)
   642  
   643  	trie, err := dbTrie.NewView(
   644  		context.Background(),
   645  		ViewChanges{
   646  			BatchOps: []database.BatchOp{
   647  				{Key: []byte("k"), Value: []byte("value0")},
   648  				{Key: []byte("ke"), Value: []byte("value1")},
   649  				{Key: []byte("key"), Value: []byte("value2")},
   650  				{Key: []byte("key1"), Value: []byte("value3")},
   651  				{Key: []byte("key2"), Value: []byte("value4")},
   652  			},
   653  		},
   654  	)
   655  	require.NoError(err)
   656  	require.NotNil(trie)
   657  
   658  	require.NoError(trie.CommitToDB(context.Background()))
   659  	oldCount := dbTrie.metrics.(*mockMetrics).hashCount
   660  
   661  	// delete the middle values
   662  	view, err := trie.NewView(
   663  		context.Background(),
   664  		ViewChanges{
   665  			BatchOps: []database.BatchOp{
   666  				{Key: []byte("k"), Delete: true},
   667  				{Key: []byte("ke"), Delete: true},
   668  				{Key: []byte("key"), Delete: true},
   669  			},
   670  		},
   671  	)
   672  	require.NoError(err)
   673  	require.NoError(view.CommitToDB(context.Background()))
   674  
   675  	// trie is:
   676  	//      [key0] (first 28 bits)
   677  	//      /  \
   678  	// [key1]  [key2]
   679  	root := view.getRoot().Value()
   680  	expectedRootKey := ToKey([]byte("key0")).Take(28)
   681  	require.Equal(expectedRootKey, root.key)
   682  	require.Len(root.children, 2)
   683  
   684  	// Had to hash the new root but not [key1] or [key2] nodes
   685  	require.Equal(oldCount+1, dbTrie.metrics.(*mockMetrics).hashCount)
   686  }
   687  
   688  func Test_Trie_NoExistingResidual(t *testing.T) {
   689  	require := require.New(t)
   690  
   691  	dbTrie, err := getBasicDB()
   692  	require.NoError(err)
   693  	require.NotNil(dbTrie)
   694  
   695  	trie, err := dbTrie.NewView(
   696  		context.Background(),
   697  		ViewChanges{
   698  			BatchOps: []database.BatchOp{
   699  				{Key: []byte("k"), Value: []byte("1")},
   700  				{Key: []byte("ke"), Value: []byte("2")},
   701  				{Key: []byte("key1"), Value: []byte("3")},
   702  				{Key: []byte("key123"), Value: []byte("4")},
   703  			},
   704  		},
   705  	)
   706  	require.NoError(err)
   707  	require.NotNil(trie)
   708  
   709  	value, err := getNodeValue(trie, "k")
   710  	require.NoError(err)
   711  	require.Equal([]byte("1"), value)
   712  
   713  	value, err = getNodeValue(trie, "ke")
   714  	require.NoError(err)
   715  	require.Equal([]byte("2"), value)
   716  
   717  	value, err = getNodeValue(trie, "key1")
   718  	require.NoError(err)
   719  	require.Equal([]byte("3"), value)
   720  
   721  	value, err = getNodeValue(trie, "key123")
   722  	require.NoError(err)
   723  	require.Equal([]byte("4"), value)
   724  }
   725  
   726  func Test_Trie_BatchApply(t *testing.T) {
   727  	require := require.New(t)
   728  
   729  	dbTrie, err := getBasicDB()
   730  	require.NoError(err)
   731  	require.NotNil(dbTrie)
   732  
   733  	trie, err := dbTrie.NewView(
   734  		context.Background(),
   735  		ViewChanges{
   736  			BatchOps: []database.BatchOp{
   737  				{Key: []byte("key1"), Value: []byte("value1")},
   738  				{Key: []byte("key12"), Value: []byte("value12")},
   739  				{Key: []byte("key134"), Value: []byte("value134")},
   740  				{Key: []byte("key1"), Delete: true},
   741  			},
   742  		},
   743  	)
   744  	require.NoError(err)
   745  	require.NotNil(trie)
   746  
   747  	value, err := getNodeValue(trie, "key12")
   748  	require.NoError(err)
   749  	require.Equal([]byte("value12"), value)
   750  
   751  	value, err = getNodeValue(trie, "key134")
   752  	require.NoError(err)
   753  	require.Equal([]byte("value134"), value)
   754  
   755  	_, err = getNodeValue(trie, "key1")
   756  	require.ErrorIs(err, database.ErrNotFound)
   757  }
   758  
   759  func Test_Trie_ChainDeletion(t *testing.T) {
   760  	require := require.New(t)
   761  
   762  	trie, err := getBasicDB()
   763  	require.NoError(err)
   764  	require.NotNil(trie)
   765  	newTrie, err := trie.NewView(
   766  		context.Background(),
   767  		ViewChanges{
   768  			BatchOps: []database.BatchOp{
   769  				{Key: []byte("k"), Value: []byte("value0")},
   770  				{Key: []byte("ke"), Value: []byte("value1")},
   771  				{Key: []byte("key"), Value: []byte("value2")},
   772  				{Key: []byte("key1"), Value: []byte("value3")},
   773  			},
   774  		},
   775  	)
   776  	require.NoError(err)
   777  
   778  	require.NoError(newTrie.(*view).applyValueChanges(context.Background()))
   779  	maybeRoot := newTrie.getRoot()
   780  	require.NoError(err)
   781  	require.True(maybeRoot.HasValue())
   782  	require.Equal([]byte("value0"), maybeRoot.Value().value.Value())
   783  	require.Len(maybeRoot.Value().children, 1)
   784  
   785  	newTrie, err = newTrie.NewView(
   786  		context.Background(),
   787  		ViewChanges{
   788  			BatchOps: []database.BatchOp{
   789  				{Key: []byte("k"), Delete: true},
   790  				{Key: []byte("ke"), Delete: true},
   791  				{Key: []byte("key"), Delete: true},
   792  				{Key: []byte("key1"), Delete: true},
   793  			},
   794  		},
   795  	)
   796  	require.NoError(err)
   797  	require.NoError(newTrie.(*view).applyValueChanges(context.Background()))
   798  
   799  	// trie should be empty
   800  	root := newTrie.getRoot()
   801  	require.False(root.HasValue())
   802  }
   803  
   804  func Test_Trie_Invalidate_Siblings_On_Commit(t *testing.T) {
   805  	require := require.New(t)
   806  
   807  	dbTrie, err := getBasicDB()
   808  	require.NoError(err)
   809  	require.NotNil(dbTrie)
   810  
   811  	view1, err := dbTrie.NewView(context.Background(), ViewChanges{})
   812  	require.NoError(err)
   813  
   814  	view2, err := view1.NewView(
   815  		context.Background(),
   816  		ViewChanges{
   817  			BatchOps: []database.BatchOp{
   818  				{Key: []byte{0}, Value: []byte{0}},
   819  			},
   820  		},
   821  	)
   822  	require.NoError(err)
   823  
   824  	// Siblings of view2
   825  	sibling1, err := view1.NewView(context.Background(), ViewChanges{})
   826  	require.NoError(err)
   827  	sibling2, err := view1.NewView(context.Background(), ViewChanges{})
   828  	require.NoError(err)
   829  
   830  	require.False(sibling1.(*view).isInvalid())
   831  	require.False(sibling2.(*view).isInvalid())
   832  
   833  	require.NoError(view1.CommitToDB(context.Background()))
   834  	require.NoError(view2.CommitToDB(context.Background()))
   835  
   836  	require.True(sibling1.(*view).isInvalid())
   837  	require.True(sibling2.(*view).isInvalid())
   838  	require.False(view2.(*view).isInvalid())
   839  }
   840  
   841  func Test_Trie_NodeCollapse(t *testing.T) {
   842  	require := require.New(t)
   843  
   844  	dbTrie, err := getBasicDB()
   845  	require.NoError(err)
   846  	require.NotNil(dbTrie)
   847  
   848  	kvs := []database.BatchOp{
   849  		{Key: []byte("k"), Value: []byte("value0")},
   850  		{Key: []byte("ke"), Value: []byte("value1")},
   851  		{Key: []byte("key"), Value: []byte("value2")},
   852  		{Key: []byte("key1"), Value: []byte("value3")},
   853  		{Key: []byte("key2"), Value: []byte("value4")},
   854  	}
   855  
   856  	trie, err := dbTrie.NewView(
   857  		context.Background(),
   858  		ViewChanges{
   859  			BatchOps: kvs,
   860  		},
   861  	)
   862  	require.NoError(err)
   863  
   864  	require.NoError(trie.(*view).applyValueChanges(context.Background()))
   865  
   866  	for _, kv := range kvs {
   867  		node, err := trie.getEditableNode(ToKey(kv.Key), true)
   868  		require.NoError(err)
   869  
   870  		require.Equal(kv.Value, node.value.Value())
   871  	}
   872  
   873  	// delete some values
   874  	deletedKVs, remainingKVs := kvs[:3], kvs[3:]
   875  	deleteOps := make([]database.BatchOp, len(deletedKVs))
   876  	for i, kv := range deletedKVs {
   877  		deleteOps[i] = database.BatchOp{
   878  			Key:    kv.Key,
   879  			Delete: true,
   880  		}
   881  	}
   882  
   883  	trie, err = trie.NewView(
   884  		context.Background(),
   885  		ViewChanges{
   886  			BatchOps: deleteOps,
   887  		},
   888  	)
   889  	require.NoError(err)
   890  
   891  	require.NoError(trie.(*view).applyValueChanges(context.Background()))
   892  
   893  	for _, kv := range deletedKVs {
   894  		_, err := trie.getEditableNode(ToKey(kv.Key), true)
   895  		require.ErrorIs(err, database.ErrNotFound)
   896  	}
   897  
   898  	// make sure the other values are still there
   899  	for _, kv := range remainingKVs {
   900  		node, err := trie.getEditableNode(ToKey(kv.Key), true)
   901  		require.NoError(err)
   902  
   903  		require.Equal(kv.Value, node.value.Value())
   904  	}
   905  }
   906  
   907  func Test_Trie_MultipleStates(t *testing.T) {
   908  	randCount := int64(0)
   909  	for _, commitApproach := range []string{"never", "before", "after"} {
   910  		t.Run(commitApproach, func(t *testing.T) {
   911  			require := require.New(t)
   912  
   913  			r := rand.New(rand.NewSource(randCount)) // #nosec G404
   914  			randCount++
   915  			rdb := memdb.New()
   916  			defer rdb.Close()
   917  			db, err := New(
   918  				context.Background(),
   919  				rdb,
   920  				newDefaultConfig(),
   921  			)
   922  			require.NoError(err)
   923  			defer db.Close()
   924  
   925  			initialSet := 1000
   926  			// Populate initial set of keys
   927  			ops := make([]database.BatchOp, 0, initialSet)
   928  			require.NoError(err)
   929  			kv := [][]byte{}
   930  			for i := 0; i < initialSet; i++ {
   931  				k := []byte(strconv.Itoa(i))
   932  				kv = append(kv, k)
   933  				ops = append(ops, database.BatchOp{Key: k, Value: hashing.ComputeHash256(k)})
   934  			}
   935  			root, err := db.NewView(
   936  				context.Background(),
   937  				ViewChanges{
   938  					BatchOps: ops,
   939  				},
   940  			)
   941  			require.NoError(err)
   942  
   943  			// Get initial root
   944  			_, err = root.GetMerkleRoot(context.Background())
   945  			require.NoError(err)
   946  
   947  			if commitApproach == "before" {
   948  				require.NoError(root.CommitToDB(context.Background()))
   949  			}
   950  
   951  			// Populate additional states
   952  			concurrentStates := []Trie{}
   953  			for i := 0; i < 5; i++ {
   954  				newState, err := root.NewView(context.Background(), ViewChanges{})
   955  				require.NoError(err)
   956  				concurrentStates = append(concurrentStates, newState)
   957  			}
   958  
   959  			if commitApproach == "after" {
   960  				require.NoError(root.CommitToDB(context.Background()))
   961  			}
   962  
   963  			// Process ops
   964  			newStart := initialSet
   965  			concurrentOps := make([][]database.BatchOp, len(concurrentStates))
   966  			for i := 0; i < 100; i++ {
   967  				if r.Intn(100) < 20 {
   968  					// New Key
   969  					for index := range concurrentStates {
   970  						k := []byte(strconv.Itoa(newStart))
   971  						concurrentOps[index] = append(concurrentOps[index], database.BatchOp{Key: k, Value: hashing.ComputeHash256(k)})
   972  					}
   973  					newStart++
   974  				} else {
   975  					// Fetch and update old
   976  					selectedKey := kv[r.Intn(len(kv))]
   977  					var pastV []byte
   978  					for index, state := range concurrentStates {
   979  						v, err := state.GetValue(context.Background(), selectedKey)
   980  						require.NoError(err)
   981  						if pastV == nil {
   982  							pastV = v
   983  						} else {
   984  							require.Equal(pastV, v)
   985  						}
   986  						concurrentOps[index] = append(concurrentOps[index], database.BatchOp{Key: selectedKey, Value: hashing.ComputeHash256(v)})
   987  					}
   988  				}
   989  			}
   990  			for index, state := range concurrentStates {
   991  				concurrentStates[index], err = state.NewView(
   992  					context.Background(),
   993  					ViewChanges{
   994  						BatchOps: concurrentOps[index],
   995  					},
   996  				)
   997  				require.NoError(err)
   998  			}
   999  
  1000  			// Generate roots
  1001  			var pastRoot ids.ID
  1002  			for _, state := range concurrentStates {
  1003  				mroot, err := state.GetMerkleRoot(context.Background())
  1004  				require.NoError(err)
  1005  				if pastRoot == ids.Empty {
  1006  					pastRoot = mroot
  1007  				} else {
  1008  					require.Equal(pastRoot, mroot)
  1009  				}
  1010  			}
  1011  		})
  1012  	}
  1013  }
  1014  
  1015  func TestNewViewOnCommittedView(t *testing.T) {
  1016  	require := require.New(t)
  1017  
  1018  	db, err := getBasicDB()
  1019  	require.NoError(err)
  1020  
  1021  	// Create a view
  1022  	view1Intf, err := db.NewView(context.Background(), ViewChanges{BatchOps: []database.BatchOp{{Key: []byte{1}, Value: []byte{1}}}})
  1023  	require.NoError(err)
  1024  	require.IsType(&view{}, view1Intf)
  1025  	view1 := view1Intf.(*view)
  1026  
  1027  	// view1
  1028  	//   |
  1029  	//  db
  1030  
  1031  	require.Len(db.childViews, 1)
  1032  	require.Contains(db.childViews, view1)
  1033  	require.Equal(db, view1.parentTrie)
  1034  
  1035  	// Commit the view
  1036  	require.NoError(view1.CommitToDB(context.Background()))
  1037  
  1038  	// view1 (committed)
  1039  	//   |
  1040  	//  db
  1041  
  1042  	require.Len(db.childViews, 1)
  1043  	require.Contains(db.childViews, view1)
  1044  	require.Equal(db, view1.parentTrie)
  1045  
  1046  	// Create a new view on the committed view
  1047  	view2Intf, err := view1.NewView(context.Background(), ViewChanges{})
  1048  	require.NoError(err)
  1049  	require.IsType(&view{}, view2Intf)
  1050  	view2 := view2Intf.(*view)
  1051  
  1052  	// view2
  1053  	//   |
  1054  	// view1 (committed)
  1055  	//   |
  1056  	//  db
  1057  
  1058  	require.Equal(db, view2.parentTrie)
  1059  	require.Contains(db.childViews, view1)
  1060  	require.Contains(db.childViews, view2)
  1061  	require.Len(db.childViews, 2)
  1062  
  1063  	// Make sure the new view has the right value
  1064  	got, err := view2.GetValue(context.Background(), []byte{1})
  1065  	require.NoError(err)
  1066  	require.Equal([]byte{1}, got)
  1067  
  1068  	// Make another view
  1069  	view3Intf, err := view2.NewView(context.Background(), ViewChanges{})
  1070  	require.NoError(err)
  1071  	require.IsType(&view{}, view3Intf)
  1072  	view3 := view3Intf.(*view)
  1073  
  1074  	// view3
  1075  	//   |
  1076  	// view2
  1077  	//   |
  1078  	// view1 (committed)
  1079  	//   |
  1080  	//  db
  1081  
  1082  	require.Equal(view2, view3.parentTrie)
  1083  	require.Contains(view2.childViews, view3)
  1084  	require.Len(view2.childViews, 1)
  1085  	require.Contains(db.childViews, view1)
  1086  	require.Contains(db.childViews, view2)
  1087  	require.Len(db.childViews, 2)
  1088  
  1089  	// Commit view2
  1090  	require.NoError(view2.CommitToDB(context.Background()))
  1091  
  1092  	// view3
  1093  	//   |
  1094  	// view2 (committed)
  1095  	//   |
  1096  	// view1 (committed)
  1097  	//   |
  1098  	//  db
  1099  
  1100  	// Note that view2 being committed invalidates view1
  1101  	require.True(view1.invalidated)
  1102  	require.Contains(db.childViews, view2)
  1103  	require.Contains(db.childViews, view3)
  1104  	require.Len(db.childViews, 2)
  1105  	require.Equal(db, view3.parentTrie)
  1106  
  1107  	// Commit view3
  1108  	require.NoError(view3.CommitToDB(context.Background()))
  1109  
  1110  	// view3 being committed invalidates view2
  1111  	require.True(view2.invalidated)
  1112  	require.Contains(db.childViews, view3)
  1113  	require.Len(db.childViews, 1)
  1114  	require.Equal(db, view3.parentTrie)
  1115  }
  1116  
  1117  func Test_View_NewView(t *testing.T) {
  1118  	require := require.New(t)
  1119  
  1120  	db, err := getBasicDB()
  1121  	require.NoError(err)
  1122  
  1123  	// Create a view
  1124  	view1Intf, err := db.NewView(context.Background(), ViewChanges{})
  1125  	require.NoError(err)
  1126  	require.IsType(&view{}, view1Intf)
  1127  	view1 := view1Intf.(*view)
  1128  
  1129  	// Create a view atop view1
  1130  	view2Intf, err := view1.NewView(context.Background(), ViewChanges{})
  1131  	require.NoError(err)
  1132  	require.IsType(&view{}, view2Intf)
  1133  	view2 := view2Intf.(*view)
  1134  
  1135  	// view2
  1136  	//   |
  1137  	// view1
  1138  	//   |
  1139  	//  db
  1140  
  1141  	// Assert view2's parent is view1
  1142  	require.Equal(view1, view2.parentTrie)
  1143  	require.Contains(view1.childViews, view2)
  1144  	require.Len(view1.childViews, 1)
  1145  
  1146  	// Commit view1
  1147  	require.NoError(view1.CommitToDB(context.Background()))
  1148  
  1149  	// Make another view atop view1
  1150  	view3Intf, err := view1.NewView(context.Background(), ViewChanges{})
  1151  	require.NoError(err)
  1152  	require.IsType(&view{}, view3Intf)
  1153  	view3 := view3Intf.(*view)
  1154  
  1155  	// view3
  1156  	//   |
  1157  	// view2
  1158  	//   |
  1159  	// view1
  1160  	//   |
  1161  	//  db
  1162  
  1163  	// Assert view3's parent is db
  1164  	require.Equal(db, view3.parentTrie)
  1165  	require.Contains(db.childViews, view3)
  1166  	require.NotContains(view1.childViews, view3)
  1167  
  1168  	// Assert that NewPreallocatedView on an invalid view fails
  1169  	invalidView := &view{invalidated: true}
  1170  	_, err = invalidView.NewView(context.Background(), ViewChanges{})
  1171  	require.ErrorIs(err, ErrInvalid)
  1172  }
  1173  
  1174  func TestViewInvalidate(t *testing.T) {
  1175  	require := require.New(t)
  1176  
  1177  	db, err := getBasicDB()
  1178  	require.NoError(err)
  1179  
  1180  	// Create a view
  1181  	view1Intf, err := db.NewView(context.Background(), ViewChanges{})
  1182  	require.NoError(err)
  1183  	require.IsType(&view{}, view1Intf)
  1184  	view1 := view1Intf.(*view)
  1185  
  1186  	// Create 2 views atop view1
  1187  	view2Intf, err := view1.NewView(context.Background(), ViewChanges{})
  1188  	require.NoError(err)
  1189  	require.IsType(&view{}, view2Intf)
  1190  	view2 := view2Intf.(*view)
  1191  
  1192  	view3Intf, err := view1.NewView(context.Background(), ViewChanges{})
  1193  	require.NoError(err)
  1194  	require.IsType(&view{}, view3Intf)
  1195  	view3 := view3Intf.(*view)
  1196  
  1197  	// view2  view3
  1198  	//   |    /
  1199  	//   view1
  1200  	//     |
  1201  	//     db
  1202  
  1203  	// Invalidate view1
  1204  	view1.invalidate()
  1205  
  1206  	require.Empty(view1.childViews)
  1207  	require.True(view1.invalidated)
  1208  	require.True(view2.invalidated)
  1209  	require.True(view3.invalidated)
  1210  }
  1211  
  1212  func Test_Trie_ConcurrentNewViewAndCommit(t *testing.T) {
  1213  	require := require.New(t)
  1214  
  1215  	trie, err := getBasicDB()
  1216  	require.NoError(err)
  1217  	require.NotNil(trie)
  1218  
  1219  	newTrie, err := trie.NewView(
  1220  		context.Background(),
  1221  		ViewChanges{
  1222  			BatchOps: []database.BatchOp{
  1223  				{Key: []byte("key"), Value: []byte("value0")},
  1224  			},
  1225  		},
  1226  	)
  1227  	require.NoError(err)
  1228  
  1229  	var wg sync.WaitGroup
  1230  	defer wg.Wait()
  1231  
  1232  	wg.Add(1)
  1233  	go func() {
  1234  		defer wg.Done()
  1235  		require.NoError(newTrie.CommitToDB(context.Background()))
  1236  	}()
  1237  
  1238  	view, err := newTrie.NewView(context.Background(), ViewChanges{})
  1239  	require.NoError(err)
  1240  	require.NotNil(view)
  1241  }
  1242  
  1243  // Returns the path of the only child of this node.
  1244  // Assumes this node has exactly one child.
  1245  func getSingleChildKey(n *node, tokenSize int) Key {
  1246  	for index, entry := range n.children {
  1247  		return n.key.Extend(ToToken(index, tokenSize), entry.compressedKey)
  1248  	}
  1249  	return Key{}
  1250  }
  1251  
  1252  func TestTrieCommitToDB(t *testing.T) {
  1253  	r := require.New(t)
  1254  
  1255  	type test struct {
  1256  		name        string
  1257  		trieFunc    func() View
  1258  		expectedErr error
  1259  	}
  1260  
  1261  	// Make a database
  1262  	db, err := getBasicDB()
  1263  	r.NoError(err)
  1264  
  1265  	tests := []test{
  1266  		{
  1267  			name: "invalid",
  1268  			trieFunc: func() View {
  1269  				nView, err := db.NewView(context.Background(), ViewChanges{})
  1270  				r.NoError(err)
  1271  
  1272  				// Invalidate the view
  1273  				nView.(*view).invalidate()
  1274  
  1275  				return nView
  1276  			},
  1277  			expectedErr: ErrInvalid,
  1278  		},
  1279  		{
  1280  			name: "committed",
  1281  			trieFunc: func() View {
  1282  				view, err := db.NewView(context.Background(), ViewChanges{})
  1283  				r.NoError(err)
  1284  
  1285  				// Commit the view
  1286  				r.NoError(view.CommitToDB(context.Background()))
  1287  
  1288  				return view
  1289  			},
  1290  			expectedErr: ErrCommitted,
  1291  		},
  1292  		{
  1293  			name: "parent not database",
  1294  			trieFunc: func() View {
  1295  				nView, err := db.NewView(context.Background(), ViewChanges{})
  1296  				r.NoError(err)
  1297  
  1298  				// Change the parent
  1299  				nView.(*view).parentTrie = &view{}
  1300  
  1301  				return nView
  1302  			},
  1303  			expectedErr: ErrParentNotDatabase,
  1304  		},
  1305  	}
  1306  
  1307  	for _, tt := range tests {
  1308  		require := require.New(t)
  1309  
  1310  		trie := tt.trieFunc()
  1311  		err := trie.CommitToDB(context.Background())
  1312  		require.ErrorIs(err, tt.expectedErr)
  1313  	}
  1314  
  1315  	// Put 2 key-value pairs
  1316  	key1, value1 := []byte("key1"), []byte("value1")
  1317  	key2, value2 := []byte("key2"), []byte("value2")
  1318  	r.NoError(db.Put(key1, value1))
  1319  	r.NoError(db.Put(key2, value2))
  1320  
  1321  	// Make a view
  1322  	key3, value3 := []byte("key3"), []byte("value3")
  1323  	// Delete a key-value pair, modify a key-value pair,
  1324  	// and insert a new key-value pair
  1325  	view, err := db.NewView(
  1326  		context.Background(),
  1327  		ViewChanges{
  1328  			BatchOps: []database.BatchOp{
  1329  				{Key: key1, Delete: true},
  1330  				{Key: key2, Value: value3},
  1331  				{Key: key3, Value: value3},
  1332  			},
  1333  		},
  1334  	)
  1335  	r.NoError(err)
  1336  
  1337  	// Commit the view
  1338  	r.NoError(view.CommitToDB(context.Background()))
  1339  
  1340  	// Make sure the database has the right values
  1341  	_, err = db.Get(key1)
  1342  	r.ErrorIs(err, database.ErrNotFound)
  1343  
  1344  	got, err := db.Get(key2)
  1345  	r.NoError(err)
  1346  	r.Equal(value3, got)
  1347  
  1348  	got, err = db.Get(key3)
  1349  	r.NoError(err)
  1350  	r.Equal(value3, got)
  1351  }