github.com/MetalBlockchain/metalgo@v1.11.9/x/merkledb/db_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  	"bytes"
     8  	"context"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"math/rand"
    12  	"slices"
    13  	"strconv"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/prometheus/client_golang/prometheus"
    18  	"github.com/stretchr/testify/require"
    19  
    20  	"github.com/MetalBlockchain/metalgo/database"
    21  	"github.com/MetalBlockchain/metalgo/database/memdb"
    22  	"github.com/MetalBlockchain/metalgo/ids"
    23  	"github.com/MetalBlockchain/metalgo/trace"
    24  	"github.com/MetalBlockchain/metalgo/utils/hashing"
    25  	"github.com/MetalBlockchain/metalgo/utils/maybe"
    26  	"github.com/MetalBlockchain/metalgo/utils/set"
    27  	"github.com/MetalBlockchain/metalgo/utils/units"
    28  )
    29  
    30  const defaultHistoryLength = 300
    31  
    32  // newDB returns a new merkle database with the underlying type so that tests can access unexported fields
    33  func newDB(ctx context.Context, db database.Database, config Config) (*merkleDB, error) {
    34  	db, err := New(ctx, db, config)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return db.(*merkleDB), nil
    39  }
    40  
    41  func newDefaultConfig() Config {
    42  	return Config{
    43  		BranchFactor:                BranchFactor16,
    44  		Hasher:                      DefaultHasher,
    45  		RootGenConcurrency:          0,
    46  		HistoryLength:               defaultHistoryLength,
    47  		ValueNodeCacheSize:          units.MiB,
    48  		IntermediateNodeCacheSize:   units.MiB,
    49  		IntermediateWriteBufferSize: units.KiB,
    50  		IntermediateWriteBatchSize:  256 * units.KiB,
    51  		Reg:                         prometheus.NewRegistry(),
    52  		TraceLevel:                  InfoTrace,
    53  		Tracer:                      trace.Noop,
    54  	}
    55  }
    56  
    57  func Test_MerkleDB_Get_Safety(t *testing.T) {
    58  	require := require.New(t)
    59  
    60  	db, err := getBasicDB()
    61  	require.NoError(err)
    62  
    63  	keyBytes := []byte{0}
    64  	require.NoError(db.Put(keyBytes, []byte{0, 1, 2}))
    65  
    66  	val, err := db.Get(keyBytes)
    67  	require.NoError(err)
    68  
    69  	n, err := db.getNode(ToKey(keyBytes), true)
    70  	require.NoError(err)
    71  
    72  	// node's value shouldn't be affected by the edit
    73  	originalVal := slices.Clone(val)
    74  	val[0]++
    75  	require.Equal(originalVal, n.value.Value())
    76  }
    77  
    78  func Test_MerkleDB_GetValues_Safety(t *testing.T) {
    79  	require := require.New(t)
    80  
    81  	db, err := getBasicDB()
    82  	require.NoError(err)
    83  
    84  	keyBytes := []byte{0}
    85  	value := []byte{0, 1, 2}
    86  	require.NoError(db.Put(keyBytes, value))
    87  
    88  	gotValues, errs := db.GetValues(context.Background(), [][]byte{keyBytes})
    89  	require.Len(errs, 1)
    90  	require.NoError(errs[0])
    91  	require.Equal(value, gotValues[0])
    92  	gotValues[0][0]++
    93  
    94  	// editing the value array shouldn't affect the db
    95  	gotValues, errs = db.GetValues(context.Background(), [][]byte{keyBytes})
    96  	require.Len(errs, 1)
    97  	require.NoError(errs[0])
    98  	require.Equal(value, gotValues[0])
    99  }
   100  
   101  func Test_MerkleDB_DB_Interface(t *testing.T) {
   102  	for _, bf := range validBranchFactors {
   103  		for name, test := range database.Tests {
   104  			t.Run(fmt.Sprintf("%s_%d", name, bf), func(t *testing.T) {
   105  				db, err := getBasicDBWithBranchFactor(bf)
   106  				require.NoError(t, err)
   107  				test(t, db)
   108  			})
   109  		}
   110  	}
   111  }
   112  
   113  func Benchmark_MerkleDB_DBInterface(b *testing.B) {
   114  	for _, size := range database.BenchmarkSizes {
   115  		keys, values := database.SetupBenchmark(b, size[0], size[1], size[2])
   116  		for _, bf := range validBranchFactors {
   117  			for name, bench := range database.Benchmarks {
   118  				b.Run(fmt.Sprintf("merkledb_%d_%d_pairs_%d_keys_%d_values_%s", bf, size[0], size[1], size[2], name), func(b *testing.B) {
   119  					db, err := getBasicDBWithBranchFactor(bf)
   120  					require.NoError(b, err)
   121  					bench(b, db, keys, values)
   122  				})
   123  			}
   124  		}
   125  	}
   126  }
   127  
   128  func Test_MerkleDB_DB_Load_Root_From_DB(t *testing.T) {
   129  	require := require.New(t)
   130  	baseDB := memdb.New()
   131  	defer baseDB.Close()
   132  
   133  	db, err := New(
   134  		context.Background(),
   135  		baseDB,
   136  		newDefaultConfig(),
   137  	)
   138  	require.NoError(err)
   139  
   140  	// Populate initial set of key-value pairs
   141  	keyCount := 100
   142  	ops := make([]database.BatchOp, 0, keyCount)
   143  	require.NoError(err)
   144  	for i := 0; i < keyCount; i++ {
   145  		k := []byte(strconv.Itoa(i))
   146  		ops = append(ops, database.BatchOp{
   147  			Key:   k,
   148  			Value: hashing.ComputeHash256(k),
   149  		})
   150  	}
   151  	view, err := db.NewView(context.Background(), ViewChanges{BatchOps: ops})
   152  	require.NoError(err)
   153  	require.NoError(view.CommitToDB(context.Background()))
   154  
   155  	root, err := db.GetMerkleRoot(context.Background())
   156  	require.NoError(err)
   157  
   158  	require.NoError(db.Close())
   159  
   160  	// reloading the db should set the root back to the one that was saved to [baseDB]
   161  	db, err = New(
   162  		context.Background(),
   163  		baseDB,
   164  		newDefaultConfig(),
   165  	)
   166  	require.NoError(err)
   167  
   168  	reloadedRoot, err := db.GetMerkleRoot(context.Background())
   169  	require.NoError(err)
   170  	require.Equal(root, reloadedRoot)
   171  }
   172  
   173  func Test_MerkleDB_DB_Rebuild(t *testing.T) {
   174  	require := require.New(t)
   175  
   176  	initialSize := 5_000
   177  
   178  	config := newDefaultConfig()
   179  	config.ValueNodeCacheSize = uint(initialSize)
   180  	config.IntermediateNodeCacheSize = uint(initialSize)
   181  
   182  	db, err := newDB(
   183  		context.Background(),
   184  		memdb.New(),
   185  		config,
   186  	)
   187  	require.NoError(err)
   188  
   189  	// Populate initial set of keys
   190  	ops := make([]database.BatchOp, 0, initialSize)
   191  	require.NoError(err)
   192  	for i := 0; i < initialSize; i++ {
   193  		k := []byte(strconv.Itoa(i))
   194  		ops = append(ops, database.BatchOp{
   195  			Key:   k,
   196  			Value: hashing.ComputeHash256(k),
   197  		})
   198  	}
   199  	view, err := db.NewView(context.Background(), ViewChanges{BatchOps: ops})
   200  	require.NoError(err)
   201  	require.NoError(view.CommitToDB(context.Background()))
   202  
   203  	// Get root
   204  	root, err := db.GetMerkleRoot(context.Background())
   205  	require.NoError(err)
   206  
   207  	// Rebuild
   208  	require.NoError(db.rebuild(context.Background(), initialSize))
   209  
   210  	// Assert root is the same after rebuild
   211  	rebuiltRoot, err := db.GetMerkleRoot(context.Background())
   212  	require.NoError(err)
   213  	require.Equal(root, rebuiltRoot)
   214  
   215  	// add variation where root has a value
   216  	require.NoError(db.Put(nil, []byte{}))
   217  
   218  	root, err = db.GetMerkleRoot(context.Background())
   219  	require.NoError(err)
   220  
   221  	require.NoError(db.rebuild(context.Background(), initialSize))
   222  
   223  	rebuiltRoot, err = db.GetMerkleRoot(context.Background())
   224  	require.NoError(err)
   225  	require.Equal(root, rebuiltRoot)
   226  }
   227  
   228  func Test_MerkleDB_Failed_Batch_Commit(t *testing.T) {
   229  	require := require.New(t)
   230  
   231  	memDB := memdb.New()
   232  	db, err := New(
   233  		context.Background(),
   234  		memDB,
   235  		newDefaultConfig(),
   236  	)
   237  	require.NoError(err)
   238  
   239  	_ = memDB.Close()
   240  
   241  	batch := db.NewBatch()
   242  	require.NoError(batch.Put([]byte("key1"), []byte("1")))
   243  	require.NoError(batch.Put([]byte("key2"), []byte("2")))
   244  	require.NoError(batch.Put([]byte("key3"), []byte("3")))
   245  	err = batch.Write()
   246  	require.ErrorIs(err, database.ErrClosed)
   247  }
   248  
   249  func Test_MerkleDB_Value_Cache(t *testing.T) {
   250  	require := require.New(t)
   251  
   252  	memDB := memdb.New()
   253  	db, err := New(
   254  		context.Background(),
   255  		memDB,
   256  		newDefaultConfig(),
   257  	)
   258  	require.NoError(err)
   259  
   260  	batch := db.NewBatch()
   261  	key1, key2 := []byte("key1"), []byte("key2")
   262  	require.NoError(batch.Put(key1, []byte("1")))
   263  	require.NoError(batch.Put([]byte("key2"), []byte("2")))
   264  	require.NoError(batch.Write())
   265  
   266  	batch = db.NewBatch()
   267  	// force key2 to be inserted into the cache as not found
   268  	require.NoError(batch.Delete(key2))
   269  	require.NoError(batch.Write())
   270  
   271  	require.NoError(memDB.Close())
   272  
   273  	// still works because key1 is read from cache
   274  	value, err := db.Get(key1)
   275  	require.NoError(err)
   276  	require.Equal([]byte("1"), value)
   277  
   278  	// still returns missing instead of closed because key2 is read from cache
   279  	_, err = db.Get(key2)
   280  	require.ErrorIs(err, database.ErrNotFound)
   281  }
   282  
   283  func Test_MerkleDB_Invalidate_Siblings_On_Commit(t *testing.T) {
   284  	require := require.New(t)
   285  
   286  	dbTrie, err := getBasicDB()
   287  	require.NoError(err)
   288  	require.NotNil(dbTrie)
   289  
   290  	viewToCommit, err := dbTrie.NewView(
   291  		context.Background(),
   292  		ViewChanges{
   293  			BatchOps: []database.BatchOp{
   294  				{Key: []byte{0}, Value: []byte{0}},
   295  			},
   296  		},
   297  	)
   298  	require.NoError(err)
   299  
   300  	// Create siblings of viewToCommit
   301  	sibling1, err := dbTrie.NewView(context.Background(), ViewChanges{})
   302  	require.NoError(err)
   303  	sibling2, err := dbTrie.NewView(context.Background(), ViewChanges{})
   304  	require.NoError(err)
   305  
   306  	require.False(sibling1.(*view).isInvalid())
   307  	require.False(sibling2.(*view).isInvalid())
   308  
   309  	// Committing viewToCommit should invalidate siblings
   310  	require.NoError(viewToCommit.CommitToDB(context.Background()))
   311  
   312  	require.True(sibling1.(*view).isInvalid())
   313  	require.True(sibling2.(*view).isInvalid())
   314  	require.False(viewToCommit.(*view).isInvalid())
   315  }
   316  
   317  func Test_MerkleDB_CommitRangeProof_DeletesValuesInRange(t *testing.T) {
   318  	require := require.New(t)
   319  
   320  	db, err := getBasicDB()
   321  	require.NoError(err)
   322  
   323  	// value that shouldn't be deleted
   324  	require.NoError(db.Put([]byte("key6"), []byte("3")))
   325  
   326  	startRoot, err := db.GetMerkleRoot(context.Background())
   327  	require.NoError(err)
   328  
   329  	// Get an empty proof
   330  	proof, err := db.GetRangeProof(
   331  		context.Background(),
   332  		maybe.Nothing[[]byte](),
   333  		maybe.Some([]byte("key3")),
   334  		10,
   335  	)
   336  	require.NoError(err)
   337  
   338  	// confirm there are no key.values in the proof
   339  	require.Empty(proof.KeyValues)
   340  
   341  	// add values to be deleted by proof commit
   342  	batch := db.NewBatch()
   343  	require.NoError(batch.Put([]byte("key1"), []byte("1")))
   344  	require.NoError(batch.Put([]byte("key2"), []byte("2")))
   345  	require.NoError(batch.Put([]byte("key3"), []byte("3")))
   346  	require.NoError(batch.Write())
   347  
   348  	// despite having no key/values in it, committing this proof should delete key1-key3.
   349  	require.NoError(db.CommitRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Some([]byte("key3")), proof))
   350  
   351  	afterCommitRoot, err := db.GetMerkleRoot(context.Background())
   352  	require.NoError(err)
   353  
   354  	require.Equal(startRoot, afterCommitRoot)
   355  }
   356  
   357  func Test_MerkleDB_CommitRangeProof_EmptyTrie(t *testing.T) {
   358  	require := require.New(t)
   359  
   360  	// Populate [db1] with 3 key-value pairs.
   361  	db1, err := getBasicDB()
   362  	require.NoError(err)
   363  	batch := db1.NewBatch()
   364  	require.NoError(batch.Put([]byte("key1"), []byte("1")))
   365  	require.NoError(batch.Put([]byte("key2"), []byte("2")))
   366  	require.NoError(batch.Put([]byte("key3"), []byte("3")))
   367  	require.NoError(batch.Write())
   368  
   369  	// Get a proof for the range [key1, key3].
   370  	proof, err := db1.GetRangeProof(
   371  		context.Background(),
   372  		maybe.Some([]byte("key1")),
   373  		maybe.Some([]byte("key3")),
   374  		10,
   375  	)
   376  	require.NoError(err)
   377  
   378  	// Commit the proof to a fresh database.
   379  	db2, err := getBasicDB()
   380  	require.NoError(err)
   381  
   382  	require.NoError(db2.CommitRangeProof(context.Background(), maybe.Some([]byte("key1")), maybe.Some([]byte("key3")), proof))
   383  
   384  	// [db2] should have the same key-value pairs as [db1].
   385  	db2Root, err := db2.GetMerkleRoot(context.Background())
   386  	require.NoError(err)
   387  
   388  	db1Root, err := db1.GetMerkleRoot(context.Background())
   389  	require.NoError(err)
   390  
   391  	require.Equal(db1Root, db2Root)
   392  }
   393  
   394  func Test_MerkleDB_CommitRangeProof_TrieWithInitialValues(t *testing.T) {
   395  	require := require.New(t)
   396  
   397  	// Populate [db1] with 3 key-value pairs.
   398  	db1, err := getBasicDB()
   399  	require.NoError(err)
   400  	batch := db1.NewBatch()
   401  	require.NoError(batch.Put([]byte("key1"), []byte("1")))
   402  	require.NoError(batch.Put([]byte("key2"), []byte("2")))
   403  	require.NoError(batch.Put([]byte("key3"), []byte("3")))
   404  	require.NoError(batch.Write())
   405  
   406  	// Get a proof for the range [key1, key3].
   407  	proof, err := db1.GetRangeProof(
   408  		context.Background(),
   409  		maybe.Some([]byte("key1")),
   410  		maybe.Some([]byte("key3")),
   411  		10,
   412  	)
   413  	require.NoError(err)
   414  
   415  	// Populate [db2] with key-value pairs where some of the keys
   416  	// have different values than in [db1].
   417  	db2, err := getBasicDB()
   418  	require.NoError(err)
   419  	batch = db2.NewBatch()
   420  	require.NoError(batch.Put([]byte("key1"), []byte("3")))
   421  	require.NoError(batch.Put([]byte("key2"), []byte("4")))
   422  	require.NoError(batch.Put([]byte("key3"), []byte("5")))
   423  	require.NoError(batch.Put([]byte("key25"), []byte("5")))
   424  	require.NoError(batch.Write())
   425  
   426  	// Commit the proof from [db1] to [db2]
   427  	require.NoError(db2.CommitRangeProof(
   428  		context.Background(),
   429  		maybe.Some([]byte("key1")),
   430  		maybe.Some([]byte("key3")),
   431  		proof,
   432  	))
   433  
   434  	// [db2] should have the same key-value pairs as [db1].
   435  	// Note that "key25" was in the range covered by the proof,
   436  	// so it's deleted from [db2].
   437  	db2Root, err := db2.GetMerkleRoot(context.Background())
   438  	require.NoError(err)
   439  
   440  	db1Root, err := db1.GetMerkleRoot(context.Background())
   441  	require.NoError(err)
   442  
   443  	require.Equal(db1Root, db2Root)
   444  }
   445  
   446  func Test_MerkleDB_GetValues(t *testing.T) {
   447  	require := require.New(t)
   448  
   449  	db, err := getBasicDB()
   450  	require.NoError(err)
   451  
   452  	writeBasicBatch(t, db)
   453  	keys := [][]byte{{0}, {1}, {2}, {10}}
   454  	values, errors := db.GetValues(context.Background(), keys)
   455  	require.Len(values, len(keys))
   456  	require.Len(errors, len(keys))
   457  
   458  	// first 3 have values
   459  	// last was not found
   460  	require.NoError(errors[0])
   461  	require.NoError(errors[1])
   462  	require.NoError(errors[2])
   463  	require.ErrorIs(errors[3], database.ErrNotFound)
   464  
   465  	require.Equal([]byte{0}, values[0])
   466  	require.Equal([]byte{1}, values[1])
   467  	require.Equal([]byte{2}, values[2])
   468  	require.Nil(values[3])
   469  }
   470  
   471  func Test_MerkleDB_InsertNil(t *testing.T) {
   472  	require := require.New(t)
   473  
   474  	db, err := getBasicDB()
   475  	require.NoError(err)
   476  
   477  	batch := db.NewBatch()
   478  	key := []byte("key0")
   479  	require.NoError(batch.Put(key, nil))
   480  	require.NoError(batch.Write())
   481  
   482  	value, err := db.Get(key)
   483  	require.NoError(err)
   484  	require.Empty(value)
   485  
   486  	value, err = getNodeValue(db, string(key))
   487  	require.NoError(err)
   488  	require.Empty(value)
   489  }
   490  
   491  func Test_MerkleDB_HealthCheck(t *testing.T) {
   492  	require := require.New(t)
   493  
   494  	db, err := getBasicDB()
   495  	require.NoError(err)
   496  
   497  	val, err := db.HealthCheck(context.Background())
   498  	require.NoError(err)
   499  	require.Nil(val)
   500  }
   501  
   502  // Test that untracked views aren't tracked in [db.childViews].
   503  func TestDatabaseNewUntrackedView(t *testing.T) {
   504  	require := require.New(t)
   505  
   506  	db, err := getBasicDB()
   507  	require.NoError(err)
   508  
   509  	// Create a new untracked view.
   510  	view, err := newView(
   511  		db,
   512  		db,
   513  		ViewChanges{
   514  			BatchOps: []database.BatchOp{
   515  				{Key: []byte{1}, Value: []byte{1}},
   516  			},
   517  		},
   518  	)
   519  	require.NoError(err)
   520  	require.Empty(db.childViews)
   521  
   522  	// Commit the view
   523  	require.NoError(view.CommitToDB(context.Background()))
   524  
   525  	// The untracked view should not be tracked by the parent database.
   526  	require.Empty(db.childViews)
   527  }
   528  
   529  // Test that tracked views are persisted to [db.childViews].
   530  func TestDatabaseNewViewFromBatchOpsTracked(t *testing.T) {
   531  	require := require.New(t)
   532  
   533  	db, err := getBasicDB()
   534  	require.NoError(err)
   535  
   536  	// Create a new tracked view.
   537  	view, err := db.NewView(
   538  		context.Background(),
   539  		ViewChanges{
   540  			BatchOps: []database.BatchOp{
   541  				{Key: []byte{1}, Value: []byte{1}},
   542  			},
   543  		},
   544  	)
   545  	require.NoError(err)
   546  	require.Len(db.childViews, 1)
   547  
   548  	// Commit the view
   549  	require.NoError(view.CommitToDB(context.Background()))
   550  
   551  	// The view should be tracked by the parent database.
   552  	require.Contains(db.childViews, view)
   553  	require.Len(db.childViews, 1)
   554  }
   555  
   556  func TestDatabaseCommitChanges(t *testing.T) {
   557  	require := require.New(t)
   558  
   559  	db, err := getBasicDB()
   560  	require.NoError(err)
   561  	dbRoot := db.getMerkleRoot()
   562  
   563  	// Committing a nil view should be a no-op.
   564  	require.NoError(db.CommitToDB(context.Background()))
   565  	require.Equal(dbRoot, db.getMerkleRoot()) // Root didn't change
   566  
   567  	// Committing an invalid view should fail.
   568  	invalidView, err := db.NewView(context.Background(), ViewChanges{})
   569  	require.NoError(err)
   570  	invalidView.(*view).invalidate()
   571  	err = invalidView.CommitToDB(context.Background())
   572  	require.ErrorIs(err, ErrInvalid)
   573  
   574  	// Add key-value pairs to the database
   575  	key1, key2, key3 := []byte{1}, []byte{2}, []byte{3}
   576  	value1, value2, value3 := []byte{1}, []byte{2}, []byte{3}
   577  	require.NoError(db.Put(key1, value1))
   578  	require.NoError(db.Put(key2, value2))
   579  
   580  	// Make a view and insert/delete a key-value pair.
   581  	view1Intf, err := db.NewView(
   582  		context.Background(),
   583  		ViewChanges{
   584  			BatchOps: []database.BatchOp{
   585  				{Key: key3, Value: value3}, // New k-v pair
   586  				{Key: key1, Delete: true},  // Delete k-v pair
   587  			},
   588  		},
   589  	)
   590  	require.NoError(err)
   591  	require.IsType(&view{}, view1Intf)
   592  	view1 := view1Intf.(*view)
   593  	view1Root, err := view1.GetMerkleRoot(context.Background())
   594  	require.NoError(err)
   595  
   596  	// Make a second view
   597  	view2Intf, err := db.NewView(context.Background(), ViewChanges{})
   598  	require.NoError(err)
   599  	require.IsType(&view{}, view2Intf)
   600  	view2 := view2Intf.(*view)
   601  
   602  	// Make a view atop a view
   603  	view3Intf, err := view1.NewView(context.Background(), ViewChanges{})
   604  	require.NoError(err)
   605  	require.IsType(&view{}, view3Intf)
   606  	view3 := view3Intf.(*view)
   607  
   608  	// view3
   609  	//  |
   610  	// view1   view2
   611  	//     \  /
   612  	//      db
   613  
   614  	// Commit view1
   615  	require.NoError(view1.commitToDB(context.Background()))
   616  
   617  	// Make sure the key-value pairs are correct.
   618  	_, err = db.Get(key1)
   619  	require.ErrorIs(err, database.ErrNotFound)
   620  	gotValue, err := db.Get(key2)
   621  	require.NoError(err)
   622  	require.Equal(value2, gotValue)
   623  	gotValue, err = db.Get(key3)
   624  	require.NoError(err)
   625  	require.Equal(value3, gotValue)
   626  
   627  	// Make sure the root is right
   628  	require.Equal(view1Root, db.getMerkleRoot())
   629  
   630  	// Make sure view2 is invalid and view1 and view3 is valid.
   631  	require.False(view1.invalidated)
   632  	require.True(view2.invalidated)
   633  	require.False(view3.invalidated)
   634  
   635  	// Make sure view2 isn't tracked by the database.
   636  	require.NotContains(db.childViews, view2)
   637  
   638  	// Make sure view1 and view3 is tracked by the database.
   639  	require.Contains(db.childViews, view1)
   640  	require.Contains(db.childViews, view3)
   641  
   642  	// Make sure view3 is now a child of db.
   643  	require.Equal(db, view3.parentTrie)
   644  }
   645  
   646  func TestDatabaseInvalidateChildrenExcept(t *testing.T) {
   647  	require := require.New(t)
   648  
   649  	db, err := getBasicDB()
   650  	require.NoError(err)
   651  
   652  	// Create children
   653  	view1Intf, err := db.NewView(context.Background(), ViewChanges{})
   654  	require.NoError(err)
   655  	require.IsType(&view{}, view1Intf)
   656  	view1 := view1Intf.(*view)
   657  
   658  	view2Intf, err := db.NewView(context.Background(), ViewChanges{})
   659  	require.NoError(err)
   660  	require.IsType(&view{}, view2Intf)
   661  	view2 := view2Intf.(*view)
   662  
   663  	view3Intf, err := db.NewView(context.Background(), ViewChanges{})
   664  	require.NoError(err)
   665  	require.IsType(&view{}, view3Intf)
   666  	view3 := view3Intf.(*view)
   667  
   668  	db.invalidateChildrenExcept(view1)
   669  
   670  	// Make sure view1 is valid and view2 and view3 are invalid.
   671  	require.False(view1.invalidated)
   672  	require.True(view2.invalidated)
   673  	require.True(view3.invalidated)
   674  	require.Contains(db.childViews, view1)
   675  	require.Len(db.childViews, 1)
   676  
   677  	db.invalidateChildrenExcept(nil)
   678  
   679  	// Make sure all views are invalid.
   680  	require.True(view1.invalidated)
   681  	require.True(view2.invalidated)
   682  	require.True(view3.invalidated)
   683  	require.Empty(db.childViews)
   684  
   685  	// Calling with an untracked view doesn't add the untracked view
   686  	db.invalidateChildrenExcept(view1)
   687  	require.Empty(db.childViews)
   688  }
   689  
   690  func Test_MerkleDB_Random_Insert_Ordering(t *testing.T) {
   691  	require := require.New(t)
   692  
   693  	var (
   694  		numRuns             = 3
   695  		numShuffles         = 3
   696  		numKeyValues        = 1_000
   697  		prefixProbability   = .1
   698  		nilValueProbability = 0.05
   699  		keys                [][]byte
   700  		keysSet             set.Set[string]
   701  	)
   702  
   703  	// Returns a random key.
   704  	// With probability approximately [prefixProbability], the returned key
   705  	// will be a prefix of a previously returned key.
   706  	genKey := func(r *rand.Rand) []byte {
   707  		for {
   708  			var key []byte
   709  			shouldPrefix := r.Float64() < prefixProbability
   710  			if len(keys) > 2 && shouldPrefix {
   711  				// Return a key that is a prefix of a previously returned key.
   712  				prefix := keys[r.Intn(len(keys))]
   713  				key = make([]byte, r.Intn(50)+len(prefix))
   714  				copy(key, prefix)
   715  				_, _ = r.Read(key[len(prefix):])
   716  			} else {
   717  				key = make([]byte, r.Intn(50))
   718  				_, _ = r.Read(key)
   719  			}
   720  
   721  			// If the key has already been returned, try again.
   722  			// This test would flake if we allowed duplicate keys
   723  			// because then the order of insertion matters.
   724  			if !keysSet.Contains(string(key)) {
   725  				keysSet.Add(string(key))
   726  				keys = append(keys, key)
   727  				return key
   728  			}
   729  		}
   730  	}
   731  
   732  	for i := 0; i < numRuns; i++ {
   733  		now := time.Now().UnixNano()
   734  		t.Logf("seed for iter %d: %d", i, now)
   735  		r := rand.New(rand.NewSource(now)) // #nosec G404
   736  
   737  		// Insert key-value pairs into a database.
   738  		ops := make([]database.BatchOp, 0, numKeyValues)
   739  		keys = [][]byte{}
   740  		for x := 0; x < numKeyValues; x++ {
   741  			key := genKey(r)
   742  			value := make([]byte, r.Intn(51))
   743  			if r.Float64() < nilValueProbability {
   744  				value = nil
   745  			} else {
   746  				_, _ = r.Read(value)
   747  			}
   748  			ops = append(ops, database.BatchOp{
   749  				Key:   key,
   750  				Value: value,
   751  			})
   752  		}
   753  
   754  		db, err := getBasicDB()
   755  		require.NoError(err)
   756  
   757  		view1, err := db.NewView(context.Background(), ViewChanges{BatchOps: ops})
   758  		require.NoError(err)
   759  
   760  		// Get the root of the trie after applying [ops].
   761  		view1Root, err := view1.GetMerkleRoot(context.Background())
   762  		require.NoError(err)
   763  
   764  		// Assert that the same operations applied in a different order
   765  		// result in the same root. Note this is only true because
   766  		// all keys inserted are unique.
   767  		for shuffleIndex := 0; shuffleIndex < numShuffles; shuffleIndex++ {
   768  			r.Shuffle(numKeyValues, func(i, j int) {
   769  				ops[i], ops[j] = ops[j], ops[i]
   770  			})
   771  
   772  			view2, err := db.NewView(context.Background(), ViewChanges{BatchOps: ops})
   773  			require.NoError(err)
   774  
   775  			view2Root, err := view2.GetMerkleRoot(context.Background())
   776  			require.NoError(err)
   777  
   778  			require.Equal(view1Root, view2Root)
   779  		}
   780  	}
   781  }
   782  
   783  func TestMerkleDBClear(t *testing.T) {
   784  	require := require.New(t)
   785  
   786  	// Make a database and insert some key-value pairs.
   787  	db, err := getBasicDB()
   788  	require.NoError(err)
   789  
   790  	emptyRootID := db.getMerkleRoot()
   791  
   792  	now := time.Now().UnixNano()
   793  	t.Logf("seed: %d", now)
   794  	r := rand.New(rand.NewSource(now)) // #nosec G404
   795  
   796  	insertRandomKeyValues(
   797  		require,
   798  		r,
   799  		[]database.Database{db},
   800  		1_000,
   801  		0.25,
   802  	)
   803  
   804  	// Clear the database.
   805  	require.NoError(db.Clear())
   806  
   807  	// Assert that the database is empty.
   808  	iter := db.NewIterator()
   809  	defer iter.Release()
   810  	require.False(iter.Next())
   811  	require.Equal(ids.Empty, db.getMerkleRoot())
   812  	require.True(db.root.IsNothing())
   813  
   814  	// Assert caches are empty.
   815  	require.Zero(db.valueNodeDB.nodeCache.Len())
   816  	require.Zero(db.intermediateNodeDB.writeBuffer.currentSize)
   817  
   818  	// Assert history has only the clearing change.
   819  	require.Len(db.history.lastChanges, 1)
   820  	change, ok := db.history.lastChanges[emptyRootID]
   821  	require.True(ok)
   822  	require.Empty(change.nodes)
   823  	require.Empty(change.values)
   824  }
   825  
   826  func FuzzMerkleDBEmptyRandomizedActions(f *testing.F) {
   827  	f.Fuzz(
   828  		func(
   829  			t *testing.T,
   830  			randSeed int64,
   831  			size uint,
   832  		) {
   833  			if size == 0 {
   834  				t.SkipNow()
   835  			}
   836  			require := require.New(t)
   837  			r := rand.New(rand.NewSource(randSeed)) // #nosec G404
   838  			for _, ts := range validTokenSizes {
   839  				runRandDBTest(
   840  					require,
   841  					r,
   842  					generateRandTest(
   843  						require,
   844  						r,
   845  						size,
   846  						0.01, /*checkHashProbability*/
   847  					),
   848  					ts,
   849  				)
   850  			}
   851  		})
   852  }
   853  
   854  func FuzzMerkleDBInitialValuesRandomizedActions(f *testing.F) {
   855  	f.Fuzz(func(
   856  		t *testing.T,
   857  		initialValues uint,
   858  		numSteps uint,
   859  		randSeed int64,
   860  	) {
   861  		if numSteps == 0 {
   862  			t.SkipNow()
   863  		}
   864  		require := require.New(t)
   865  		r := rand.New(rand.NewSource(randSeed)) // #nosec G404
   866  		for _, ts := range validTokenSizes {
   867  			runRandDBTest(
   868  				require,
   869  				r,
   870  				generateInitialValues(
   871  					require,
   872  					r,
   873  					initialValues,
   874  					numSteps,
   875  					0.001, /*checkHashProbability*/
   876  				),
   877  				ts,
   878  			)
   879  		}
   880  	})
   881  }
   882  
   883  // randTest performs random trie operations.
   884  // Instances of this test are created by Generate.
   885  type randTest []randTestStep
   886  
   887  type randTestStep struct {
   888  	op    int
   889  	key   []byte // for opUpdate, opDelete, opGet
   890  	value []byte // for opUpdate
   891  }
   892  
   893  const (
   894  	opUpdate = iota
   895  	opDelete
   896  	opGet
   897  	opWriteBatch
   898  	opGenerateRangeProof
   899  	opGenerateChangeProof
   900  	opCheckhash
   901  	opMax // boundary value, not an actual op
   902  )
   903  
   904  func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest, tokenSize int) {
   905  	db, err := getBasicDBWithBranchFactor(tokenSizeToBranchFactor[tokenSize])
   906  	require.NoError(err)
   907  
   908  	const (
   909  		maxProofLen  = 100
   910  		maxPastRoots = defaultHistoryLength
   911  	)
   912  
   913  	var (
   914  		values               = make(map[Key][]byte) // tracks content of the trie
   915  		currentBatch         = db.NewBatch()
   916  		uncommittedKeyValues = make(map[Key][]byte)
   917  		uncommittedDeletes   = set.Set[Key]{}
   918  		pastRoots            = []ids.ID{}
   919  	)
   920  
   921  	startRoot, err := db.GetMerkleRoot(context.Background())
   922  	require.NoError(err)
   923  
   924  	for i, step := range rt {
   925  		require.LessOrEqual(i, len(rt))
   926  		switch step.op {
   927  		case opUpdate:
   928  			require.NoError(currentBatch.Put(step.key, step.value))
   929  
   930  			uncommittedKeyValues[ToKey(step.key)] = step.value
   931  			uncommittedDeletes.Remove(ToKey(step.key))
   932  		case opDelete:
   933  			require.NoError(currentBatch.Delete(step.key))
   934  
   935  			uncommittedDeletes.Add(ToKey(step.key))
   936  			delete(uncommittedKeyValues, ToKey(step.key))
   937  		case opGenerateRangeProof:
   938  			root, err := db.GetMerkleRoot(context.Background())
   939  			require.NoError(err)
   940  
   941  			if len(pastRoots) > 0 {
   942  				root = pastRoots[r.Intn(len(pastRoots))]
   943  			}
   944  
   945  			start := maybe.Nothing[[]byte]()
   946  			if len(step.key) > 0 {
   947  				start = maybe.Some(step.key)
   948  			}
   949  			end := maybe.Nothing[[]byte]()
   950  			if len(step.value) > 0 {
   951  				end = maybe.Some(step.value)
   952  			}
   953  
   954  			rangeProof, err := db.GetRangeProofAtRoot(context.Background(), root, start, end, maxProofLen)
   955  			if root == ids.Empty {
   956  				require.ErrorIs(err, ErrEmptyProof)
   957  				continue
   958  			}
   959  			require.NoError(err)
   960  			require.LessOrEqual(len(rangeProof.KeyValues), maxProofLen)
   961  
   962  			require.NoError(rangeProof.Verify(
   963  				context.Background(),
   964  				start,
   965  				end,
   966  				root,
   967  				tokenSize,
   968  				db.hasher,
   969  			))
   970  		case opGenerateChangeProof:
   971  			root, err := db.GetMerkleRoot(context.Background())
   972  			require.NoError(err)
   973  
   974  			if len(pastRoots) > 1 {
   975  				root = pastRoots[r.Intn(len(pastRoots))]
   976  			}
   977  
   978  			start := maybe.Nothing[[]byte]()
   979  			if len(step.key) > 0 {
   980  				start = maybe.Some(step.key)
   981  			}
   982  
   983  			end := maybe.Nothing[[]byte]()
   984  			if len(step.value) > 0 {
   985  				end = maybe.Some(step.value)
   986  			}
   987  
   988  			changeProof, err := db.GetChangeProof(context.Background(), startRoot, root, start, end, maxProofLen)
   989  			if startRoot == root {
   990  				require.ErrorIs(err, errSameRoot)
   991  				continue
   992  			}
   993  			if root == ids.Empty {
   994  				require.ErrorIs(err, ErrEmptyProof)
   995  				continue
   996  			}
   997  			require.NoError(err)
   998  			require.LessOrEqual(len(changeProof.KeyChanges), maxProofLen)
   999  
  1000  			changeProofDB, err := getBasicDBWithBranchFactor(tokenSizeToBranchFactor[tokenSize])
  1001  			require.NoError(err)
  1002  
  1003  			require.NoError(changeProofDB.VerifyChangeProof(
  1004  				context.Background(),
  1005  				changeProof,
  1006  				start,
  1007  				end,
  1008  				root,
  1009  			))
  1010  		case opWriteBatch:
  1011  			oldRoot, err := db.GetMerkleRoot(context.Background())
  1012  			require.NoError(err)
  1013  
  1014  			require.NoError(currentBatch.Write())
  1015  			currentBatch.Reset()
  1016  
  1017  			if len(uncommittedKeyValues) == 0 && len(uncommittedDeletes) == 0 {
  1018  				continue
  1019  			}
  1020  
  1021  			for key, value := range uncommittedKeyValues {
  1022  				values[key] = value
  1023  			}
  1024  			clear(uncommittedKeyValues)
  1025  
  1026  			for key := range uncommittedDeletes {
  1027  				delete(values, key)
  1028  			}
  1029  			uncommittedDeletes.Clear()
  1030  
  1031  			newRoot, err := db.GetMerkleRoot(context.Background())
  1032  			require.NoError(err)
  1033  
  1034  			if oldRoot != newRoot {
  1035  				pastRoots = append(pastRoots, newRoot)
  1036  				if len(pastRoots) > maxPastRoots {
  1037  					pastRoots = pastRoots[len(pastRoots)-maxPastRoots:]
  1038  				}
  1039  			}
  1040  
  1041  		case opGet:
  1042  			v, err := db.Get(step.key)
  1043  			if err != nil {
  1044  				require.ErrorIs(err, database.ErrNotFound)
  1045  			}
  1046  
  1047  			want := values[ToKey(step.key)]
  1048  			require.True(bytes.Equal(want, v)) // Use bytes.Equal so nil treated equal to []byte{}
  1049  
  1050  			trieValue, err := getNodeValue(db, string(step.key))
  1051  			if err != nil {
  1052  				require.ErrorIs(err, database.ErrNotFound)
  1053  			}
  1054  
  1055  			require.True(bytes.Equal(want, trieValue)) // Use bytes.Equal so nil treated equal to []byte{}
  1056  		case opCheckhash:
  1057  			// Create a view with the same key-values as [db]
  1058  			newDB, err := getBasicDBWithBranchFactor(tokenSizeToBranchFactor[tokenSize])
  1059  			require.NoError(err)
  1060  
  1061  			ops := make([]database.BatchOp, 0, len(values))
  1062  			for key, value := range values {
  1063  				ops = append(ops, database.BatchOp{
  1064  					Key:   key.Bytes(),
  1065  					Value: value,
  1066  				})
  1067  			}
  1068  
  1069  			view, err := newDB.NewView(context.Background(), ViewChanges{BatchOps: ops})
  1070  			require.NoError(err)
  1071  
  1072  			// Check that the root of the view is the same as the root of [db]
  1073  			newRoot, err := view.GetMerkleRoot(context.Background())
  1074  			require.NoError(err)
  1075  
  1076  			dbRoot, err := db.GetMerkleRoot(context.Background())
  1077  			require.NoError(err)
  1078  			require.Equal(dbRoot, newRoot)
  1079  		default:
  1080  			require.FailNow("unknown op")
  1081  		}
  1082  	}
  1083  }
  1084  
  1085  func generateRandTestWithKeys(
  1086  	require *require.Assertions,
  1087  	r *rand.Rand,
  1088  	allKeys [][]byte,
  1089  	size uint,
  1090  	checkHashProbability float64,
  1091  ) randTest {
  1092  	const nilEndProbability = 0.1
  1093  
  1094  	genKey := func() []byte {
  1095  		if len(allKeys) < 2 || r.Intn(100) < 10 {
  1096  			// new key
  1097  			key := make([]byte, r.Intn(50))
  1098  			_, err := r.Read(key)
  1099  			require.NoError(err)
  1100  			allKeys = append(allKeys, key)
  1101  			return key
  1102  		}
  1103  		if len(allKeys) > 2 && r.Intn(100) < 10 {
  1104  			// new prefixed key
  1105  			prefix := allKeys[r.Intn(len(allKeys))]
  1106  			key := make([]byte, r.Intn(50)+len(prefix))
  1107  			copy(key, prefix)
  1108  			_, err := r.Read(key[len(prefix):])
  1109  			require.NoError(err)
  1110  			allKeys = append(allKeys, key)
  1111  			return key
  1112  		}
  1113  		// use existing key
  1114  		return allKeys[r.Intn(len(allKeys))]
  1115  	}
  1116  
  1117  	genEnd := func(key []byte) []byte {
  1118  		// got is defined because if a rand method is used
  1119  		// in an if statement, the nosec directive doesn't work.
  1120  		got := r.Float64() // #nosec G404
  1121  		if got < nilEndProbability {
  1122  			return nil
  1123  		}
  1124  
  1125  		endKey := make([]byte, len(key))
  1126  		copy(endKey, key)
  1127  		for i := 0; i < len(endKey); i += 2 {
  1128  			n := r.Intn(len(endKey))
  1129  			if endKey[n] < 250 {
  1130  				endKey[n] += byte(r.Intn(int(255 - endKey[n])))
  1131  			}
  1132  		}
  1133  		return endKey
  1134  	}
  1135  
  1136  	var steps randTest
  1137  	for i := uint(0); i < size-1; {
  1138  		step := randTestStep{op: r.Intn(opMax)}
  1139  		switch step.op {
  1140  		case opUpdate:
  1141  			step.key = genKey()
  1142  			step.value = make([]byte, r.Intn(50))
  1143  			if len(step.value) == 51 {
  1144  				step.value = nil
  1145  			} else {
  1146  				_, err := r.Read(step.value)
  1147  				require.NoError(err)
  1148  			}
  1149  		case opGet, opDelete:
  1150  			step.key = genKey()
  1151  		case opGenerateRangeProof, opGenerateChangeProof:
  1152  			step.key = genKey()
  1153  			step.value = genEnd(step.key)
  1154  		case opCheckhash:
  1155  			// this gets really expensive so control how often it happens
  1156  			if r.Float64() > checkHashProbability {
  1157  				continue
  1158  			}
  1159  		}
  1160  		steps = append(steps, step)
  1161  		i++
  1162  	}
  1163  	// always end with a full hash of the trie
  1164  	steps = append(steps, randTestStep{op: opCheckhash})
  1165  	return steps
  1166  }
  1167  
  1168  func generateInitialValues(
  1169  	require *require.Assertions,
  1170  	r *rand.Rand,
  1171  	numInitialKeyValues uint,
  1172  	size uint,
  1173  	percentChanceToFullHash float64,
  1174  ) randTest {
  1175  	const (
  1176  		prefixProbability   = 0.1
  1177  		nilValueProbability = 0.05
  1178  	)
  1179  
  1180  	var allKeys [][]byte
  1181  	genKey := func() []byte {
  1182  		// new prefixed key
  1183  		if len(allKeys) > 2 && r.Float64() < prefixProbability {
  1184  			prefix := allKeys[r.Intn(len(allKeys))]
  1185  			key := make([]byte, r.Intn(50)+len(prefix))
  1186  			copy(key, prefix)
  1187  			_, _ = r.Read(key[len(prefix):])
  1188  			allKeys = append(allKeys, key)
  1189  			return key
  1190  		}
  1191  
  1192  		// new key
  1193  		key := make([]byte, r.Intn(50))
  1194  		_, _ = r.Read(key)
  1195  		allKeys = append(allKeys, key)
  1196  		return key
  1197  	}
  1198  
  1199  	var steps randTest
  1200  	for i := uint(0); i < numInitialKeyValues; i++ {
  1201  		step := randTestStep{
  1202  			op:    opUpdate,
  1203  			key:   genKey(),
  1204  			value: make([]byte, r.Intn(50)),
  1205  		}
  1206  		// got is defined because if a rand method is used
  1207  		// in an if statement, the nosec directive doesn't work.
  1208  		got := r.Float64() // #nosec G404
  1209  		if got < nilValueProbability {
  1210  			step.value = nil
  1211  		} else {
  1212  			_, _ = r.Read(step.value)
  1213  		}
  1214  		steps = append(steps, step)
  1215  	}
  1216  	steps = append(steps, randTestStep{op: opWriteBatch})
  1217  	steps = append(steps, generateRandTestWithKeys(require, r, allKeys, size, percentChanceToFullHash)...)
  1218  	return steps
  1219  }
  1220  
  1221  func generateRandTest(require *require.Assertions, r *rand.Rand, size uint, percentChanceToFullHash float64) randTest {
  1222  	return generateRandTestWithKeys(require, r, [][]byte{}, size, percentChanceToFullHash)
  1223  }
  1224  
  1225  // Inserts [n] random key/value pairs into each database.
  1226  // Deletes [deletePortion] of the key/value pairs after insertion.
  1227  func insertRandomKeyValues(
  1228  	require *require.Assertions,
  1229  	rand *rand.Rand,
  1230  	dbs []database.Database,
  1231  	numKeyValues uint,
  1232  	deletePortion float64,
  1233  ) {
  1234  	maxKeyLen := units.KiB
  1235  	maxValLen := 4 * units.KiB
  1236  
  1237  	require.GreaterOrEqual(deletePortion, float64(0))
  1238  	require.LessOrEqual(deletePortion, float64(1))
  1239  	for i := uint(0); i < numKeyValues; i++ {
  1240  		keyLen := rand.Intn(maxKeyLen)
  1241  		key := make([]byte, keyLen)
  1242  		_, _ = rand.Read(key)
  1243  
  1244  		valueLen := rand.Intn(maxValLen)
  1245  		value := make([]byte, valueLen)
  1246  		_, _ = rand.Read(value)
  1247  		for _, db := range dbs {
  1248  			require.NoError(db.Put(key, value))
  1249  		}
  1250  
  1251  		if rand.Float64() < deletePortion {
  1252  			for _, db := range dbs {
  1253  				require.NoError(db.Delete(key))
  1254  			}
  1255  		}
  1256  	}
  1257  }
  1258  
  1259  func TestGetRangeProofAtRootEmptyRootID(t *testing.T) {
  1260  	require := require.New(t)
  1261  
  1262  	db, err := getBasicDB()
  1263  	require.NoError(err)
  1264  
  1265  	_, err = db.GetRangeProofAtRoot(
  1266  		context.Background(),
  1267  		ids.Empty,
  1268  		maybe.Nothing[[]byte](),
  1269  		maybe.Nothing[[]byte](),
  1270  		10,
  1271  	)
  1272  	require.ErrorIs(err, ErrEmptyProof)
  1273  }
  1274  
  1275  func TestGetChangeProofEmptyRootID(t *testing.T) {
  1276  	require := require.New(t)
  1277  
  1278  	db, err := getBasicDB()
  1279  	require.NoError(err)
  1280  
  1281  	require.NoError(db.Put([]byte("key"), []byte("value")))
  1282  
  1283  	rootID := db.getMerkleRoot()
  1284  
  1285  	_, err = db.GetChangeProof(
  1286  		context.Background(),
  1287  		rootID,
  1288  		ids.Empty,
  1289  		maybe.Nothing[[]byte](),
  1290  		maybe.Nothing[[]byte](),
  1291  		10,
  1292  	)
  1293  	require.ErrorIs(err, ErrEmptyProof)
  1294  }
  1295  
  1296  func TestCrashRecovery(t *testing.T) {
  1297  	require := require.New(t)
  1298  
  1299  	baseDB := memdb.New()
  1300  	merkleDB, err := newDatabase(
  1301  		context.Background(),
  1302  		baseDB,
  1303  		newDefaultConfig(),
  1304  		&mockMetrics{},
  1305  	)
  1306  	require.NoError(err)
  1307  
  1308  	merkleDBBatch := merkleDB.NewBatch()
  1309  	require.NoError(merkleDBBatch.Put([]byte("is this"), []byte("hope")))
  1310  	require.NoError(merkleDBBatch.Put([]byte("expected?"), []byte("so")))
  1311  	require.NoError(merkleDBBatch.Write())
  1312  
  1313  	expectedRoot, err := merkleDB.GetMerkleRoot(context.Background())
  1314  	require.NoError(err)
  1315  
  1316  	// Do not `.Close()` the database to simulate a process crash.
  1317  
  1318  	newMerkleDB, err := newDatabase(
  1319  		context.Background(),
  1320  		baseDB,
  1321  		newDefaultConfig(),
  1322  		&mockMetrics{},
  1323  	)
  1324  	require.NoError(err)
  1325  
  1326  	value, err := newMerkleDB.Get([]byte("is this"))
  1327  	require.NoError(err)
  1328  	require.Equal([]byte("hope"), value)
  1329  
  1330  	value, err = newMerkleDB.Get([]byte("expected?"))
  1331  	require.NoError(err)
  1332  	require.Equal([]byte("so"), value)
  1333  
  1334  	rootAfterRecovery, err := newMerkleDB.GetMerkleRoot(context.Background())
  1335  	require.NoError(err)
  1336  	require.Equal(expectedRoot, rootAfterRecovery)
  1337  }
  1338  
  1339  func BenchmarkCommitView(b *testing.B) {
  1340  	db, err := getBasicDB()
  1341  	require.NoError(b, err)
  1342  
  1343  	ops := make([]database.BatchOp, 1_000)
  1344  	for i := range ops {
  1345  		k := binary.AppendUvarint(nil, uint64(i))
  1346  		ops[i] = database.BatchOp{
  1347  			Key:   k,
  1348  			Value: hashing.ComputeHash256(k),
  1349  		}
  1350  	}
  1351  
  1352  	ctx := context.Background()
  1353  	viewIntf, err := db.NewView(ctx, ViewChanges{BatchOps: ops})
  1354  	require.NoError(b, err)
  1355  
  1356  	view := viewIntf.(*view)
  1357  	require.NoError(b, view.applyValueChanges(ctx))
  1358  
  1359  	b.Run("apply and commit changes", func(b *testing.B) {
  1360  		require := require.New(b)
  1361  
  1362  		for i := 0; i < b.N; i++ {
  1363  			db.baseDB = memdb.New() // Keep each iteration independent
  1364  
  1365  			valueNodeBatch := db.baseDB.NewBatch()
  1366  			require.NoError(db.applyChanges(ctx, valueNodeBatch, view.changes))
  1367  			require.NoError(db.commitValueChanges(ctx, valueNodeBatch))
  1368  		}
  1369  	})
  1370  }
  1371  
  1372  func BenchmarkIteration(b *testing.B) {
  1373  	db, err := getBasicDB()
  1374  	require.NoError(b, err)
  1375  
  1376  	ops := make([]database.BatchOp, 1_000)
  1377  	for i := range ops {
  1378  		k := binary.AppendUvarint(nil, uint64(i))
  1379  		ops[i] = database.BatchOp{
  1380  			Key:   k,
  1381  			Value: hashing.ComputeHash256(k),
  1382  		}
  1383  	}
  1384  
  1385  	ctx := context.Background()
  1386  	view, err := db.NewView(ctx, ViewChanges{BatchOps: ops})
  1387  	require.NoError(b, err)
  1388  
  1389  	require.NoError(b, view.CommitToDB(ctx))
  1390  
  1391  	b.Run("create iterator", func(b *testing.B) {
  1392  		for i := 0; i < b.N; i++ {
  1393  			it := db.NewIterator()
  1394  			it.Release()
  1395  		}
  1396  	})
  1397  
  1398  	b.Run("iterate", func(b *testing.B) {
  1399  		for i := 0; i < b.N; i++ {
  1400  			it := db.NewIterator()
  1401  			for it.Next() {
  1402  			}
  1403  			it.Release()
  1404  		}
  1405  	})
  1406  }