github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/storage/badger/operation/common_test.go (about)

     1  package operation
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/dgraph-io/badger/v2"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"github.com/vmihailenco/msgpack/v4"
    13  
    14  	"github.com/onflow/flow-go/model/flow"
    15  	"github.com/onflow/flow-go/storage"
    16  	"github.com/onflow/flow-go/utils/unittest"
    17  )
    18  
    19  type Entity struct {
    20  	ID uint64
    21  }
    22  
    23  type UnencodeableEntity Entity
    24  
    25  var errCantEncode = fmt.Errorf("encoding not supported")
    26  var errCantDecode = fmt.Errorf("decoding not supported")
    27  
    28  func (a UnencodeableEntity) MarshalJSON() ([]byte, error) {
    29  	return nil, errCantEncode
    30  }
    31  
    32  func (a *UnencodeableEntity) UnmarshalJSON(b []byte) error {
    33  	return errCantDecode
    34  }
    35  
    36  func (a UnencodeableEntity) MarshalMsgpack() ([]byte, error) {
    37  	return nil, errCantEncode
    38  }
    39  
    40  func (a UnencodeableEntity) UnmarshalMsgpack(b []byte) error {
    41  	return errCantDecode
    42  }
    43  
    44  func TestInsertValid(t *testing.T) {
    45  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
    46  		e := Entity{ID: 1337}
    47  		key := []byte{0x01, 0x02, 0x03}
    48  		val, _ := msgpack.Marshal(e)
    49  
    50  		err := db.Update(insert(key, e))
    51  		require.NoError(t, err)
    52  
    53  		var act []byte
    54  		_ = db.View(func(tx *badger.Txn) error {
    55  			item, err := tx.Get(key)
    56  			require.NoError(t, err)
    57  			act, err = item.ValueCopy(nil)
    58  			require.NoError(t, err)
    59  			return nil
    60  		})
    61  
    62  		assert.Equal(t, val, act)
    63  	})
    64  }
    65  
    66  func TestInsertDuplicate(t *testing.T) {
    67  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
    68  		e := Entity{ID: 1337}
    69  		key := []byte{0x01, 0x02, 0x03}
    70  		val, _ := msgpack.Marshal(e)
    71  
    72  		// persist first time
    73  		err := db.Update(insert(key, e))
    74  		require.NoError(t, err)
    75  
    76  		e2 := Entity{ID: 1338}
    77  
    78  		// persist again
    79  		err = db.Update(insert(key, e2))
    80  		require.Error(t, err)
    81  		require.ErrorIs(t, err, storage.ErrAlreadyExists)
    82  
    83  		// ensure old value did not update
    84  		var act []byte
    85  		_ = db.View(func(tx *badger.Txn) error {
    86  			item, err := tx.Get(key)
    87  			require.NoError(t, err)
    88  			act, err = item.ValueCopy(nil)
    89  			require.NoError(t, err)
    90  			return nil
    91  		})
    92  
    93  		assert.Equal(t, val, act)
    94  	})
    95  }
    96  
    97  func TestInsertEncodingError(t *testing.T) {
    98  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
    99  		e := Entity{ID: 1337}
   100  		key := []byte{0x01, 0x02, 0x03}
   101  
   102  		err := db.Update(insert(key, UnencodeableEntity(e)))
   103  		require.Error(t, err, errCantEncode)
   104  		require.NotErrorIs(t, err, storage.ErrNotFound)
   105  	})
   106  }
   107  
   108  func TestUpdateValid(t *testing.T) {
   109  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   110  		e := Entity{ID: 1337}
   111  		key := []byte{0x01, 0x02, 0x03}
   112  		val, _ := msgpack.Marshal(e)
   113  
   114  		_ = db.Update(func(tx *badger.Txn) error {
   115  			err := tx.Set(key, []byte{})
   116  			require.NoError(t, err)
   117  			return nil
   118  		})
   119  
   120  		err := db.Update(update(key, e))
   121  		require.NoError(t, err)
   122  
   123  		var act []byte
   124  		_ = db.View(func(tx *badger.Txn) error {
   125  			item, err := tx.Get(key)
   126  			require.NoError(t, err)
   127  			act, err = item.ValueCopy(nil)
   128  			require.NoError(t, err)
   129  			return nil
   130  		})
   131  
   132  		assert.Equal(t, val, act)
   133  	})
   134  }
   135  
   136  func TestUpdateMissing(t *testing.T) {
   137  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   138  		e := Entity{ID: 1337}
   139  		key := []byte{0x01, 0x02, 0x03}
   140  
   141  		err := db.Update(update(key, e))
   142  		require.ErrorIs(t, err, storage.ErrNotFound)
   143  
   144  		// ensure nothing was written
   145  		_ = db.View(func(tx *badger.Txn) error {
   146  			_, err := tx.Get(key)
   147  			require.Equal(t, badger.ErrKeyNotFound, err)
   148  			return nil
   149  		})
   150  	})
   151  }
   152  
   153  func TestUpdateEncodingError(t *testing.T) {
   154  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   155  		e := Entity{ID: 1337}
   156  		key := []byte{0x01, 0x02, 0x03}
   157  		val, _ := msgpack.Marshal(e)
   158  
   159  		_ = db.Update(func(tx *badger.Txn) error {
   160  			err := tx.Set(key, val)
   161  			require.NoError(t, err)
   162  			return nil
   163  		})
   164  
   165  		err := db.Update(update(key, UnencodeableEntity(e)))
   166  		require.Error(t, err)
   167  		require.NotErrorIs(t, err, storage.ErrNotFound)
   168  
   169  		// ensure value did not change
   170  		var act []byte
   171  		_ = db.View(func(tx *badger.Txn) error {
   172  			item, err := tx.Get(key)
   173  			require.NoError(t, err)
   174  			act, err = item.ValueCopy(nil)
   175  			require.NoError(t, err)
   176  			return nil
   177  		})
   178  
   179  		assert.Equal(t, val, act)
   180  	})
   181  }
   182  
   183  func TestUpsertEntry(t *testing.T) {
   184  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   185  		e := Entity{ID: 1337}
   186  		key := []byte{0x01, 0x02, 0x03}
   187  		val, _ := msgpack.Marshal(e)
   188  
   189  		// first upsert an non-existed entry
   190  		err := db.Update(insert(key, e))
   191  		require.NoError(t, err)
   192  
   193  		var act []byte
   194  		_ = db.View(func(tx *badger.Txn) error {
   195  			item, err := tx.Get(key)
   196  			require.NoError(t, err)
   197  			act, err = item.ValueCopy(nil)
   198  			require.NoError(t, err)
   199  			return nil
   200  		})
   201  
   202  		assert.Equal(t, val, act)
   203  
   204  		// next upsert the value with the same key
   205  		newEntity := Entity{ID: 1338}
   206  		newVal, _ := msgpack.Marshal(newEntity)
   207  		err = db.Update(upsert(key, newEntity))
   208  		require.NoError(t, err)
   209  
   210  		_ = db.View(func(tx *badger.Txn) error {
   211  			item, err := tx.Get(key)
   212  			require.NoError(t, err)
   213  			act, err = item.ValueCopy(nil)
   214  			require.NoError(t, err)
   215  			return nil
   216  		})
   217  
   218  		assert.Equal(t, newVal, act)
   219  	})
   220  }
   221  
   222  func TestRetrieveValid(t *testing.T) {
   223  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   224  		e := Entity{ID: 1337}
   225  		key := []byte{0x01, 0x02, 0x03}
   226  		val, _ := msgpack.Marshal(e)
   227  
   228  		_ = db.Update(func(tx *badger.Txn) error {
   229  			err := tx.Set(key, val)
   230  			require.NoError(t, err)
   231  			return nil
   232  		})
   233  
   234  		var act Entity
   235  		err := db.View(retrieve(key, &act))
   236  		require.NoError(t, err)
   237  
   238  		assert.Equal(t, e, act)
   239  	})
   240  }
   241  
   242  func TestRetrieveMissing(t *testing.T) {
   243  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   244  		key := []byte{0x01, 0x02, 0x03}
   245  
   246  		var act Entity
   247  		err := db.View(retrieve(key, &act))
   248  		require.ErrorIs(t, err, storage.ErrNotFound)
   249  	})
   250  }
   251  
   252  func TestRetrieveUnencodeable(t *testing.T) {
   253  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   254  		e := Entity{ID: 1337}
   255  		key := []byte{0x01, 0x02, 0x03}
   256  		val, _ := msgpack.Marshal(e)
   257  
   258  		_ = db.Update(func(tx *badger.Txn) error {
   259  			err := tx.Set(key, val)
   260  			require.NoError(t, err)
   261  			return nil
   262  		})
   263  
   264  		var act *UnencodeableEntity
   265  		err := db.View(retrieve(key, &act))
   266  		require.Error(t, err)
   267  		require.NotErrorIs(t, err, storage.ErrNotFound)
   268  	})
   269  }
   270  
   271  // TestExists verifies that `exists` returns correct results in different scenarios.
   272  func TestExists(t *testing.T) {
   273  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   274  		t.Run("non-existent key", func(t *testing.T) {
   275  			key := unittest.RandomBytes(32)
   276  			var _exists bool
   277  			err := db.View(exists(key, &_exists))
   278  			require.NoError(t, err)
   279  			assert.False(t, _exists)
   280  		})
   281  
   282  		t.Run("existent key", func(t *testing.T) {
   283  			key := unittest.RandomBytes(32)
   284  			err := db.Update(insert(key, unittest.RandomBytes(256)))
   285  			require.NoError(t, err)
   286  
   287  			var _exists bool
   288  			err = db.View(exists(key, &_exists))
   289  			require.NoError(t, err)
   290  			assert.True(t, _exists)
   291  		})
   292  
   293  		t.Run("removed key", func(t *testing.T) {
   294  			key := unittest.RandomBytes(32)
   295  			// insert, then remove the key
   296  			err := db.Update(insert(key, unittest.RandomBytes(256)))
   297  			require.NoError(t, err)
   298  			err = db.Update(remove(key))
   299  			require.NoError(t, err)
   300  
   301  			var _exists bool
   302  			err = db.View(exists(key, &_exists))
   303  			require.NoError(t, err)
   304  			assert.False(t, _exists)
   305  		})
   306  	})
   307  }
   308  
   309  func TestLookup(t *testing.T) {
   310  	expected := []flow.Identifier{
   311  		{0x01},
   312  		{0x02},
   313  		{0x03},
   314  		{0x04},
   315  	}
   316  	actual := []flow.Identifier{}
   317  
   318  	iterationFunc := lookup(&actual)
   319  
   320  	for _, e := range expected {
   321  		checkFunc, createFunc, handleFunc := iterationFunc()
   322  		assert.True(t, checkFunc([]byte{0x00}))
   323  		target := createFunc()
   324  		assert.IsType(t, &flow.Identifier{}, target)
   325  
   326  		// set the value to target. Need to use reflection here since target is not strongly typed
   327  		reflect.ValueOf(target).Elem().Set(reflect.ValueOf(e))
   328  
   329  		assert.NoError(t, handleFunc())
   330  	}
   331  
   332  	assert.Equal(t, expected, actual)
   333  }
   334  
   335  func TestIterate(t *testing.T) {
   336  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   337  		keys := [][]byte{{0x00}, {0x12}, {0xf0}, {0xff}}
   338  		vals := []bool{false, false, true, true}
   339  		expected := []bool{false, true}
   340  
   341  		_ = db.Update(func(tx *badger.Txn) error {
   342  			for i, key := range keys {
   343  				enc, err := msgpack.Marshal(vals[i])
   344  				require.NoError(t, err)
   345  				err = tx.Set(key, enc)
   346  				require.NoError(t, err)
   347  			}
   348  			return nil
   349  		})
   350  
   351  		actual := make([]bool, 0, len(keys))
   352  		iterationFunc := func() (checkFunc, createFunc, handleFunc) {
   353  			check := func(key []byte) bool {
   354  				return !bytes.Equal(key, []byte{0x12})
   355  			}
   356  			var val bool
   357  			create := func() interface{} {
   358  				return &val
   359  			}
   360  			handle := func() error {
   361  				actual = append(actual, val)
   362  				return nil
   363  			}
   364  			return check, create, handle
   365  		}
   366  
   367  		err := db.View(iterate(keys[0], keys[2], iterationFunc))
   368  		require.Nil(t, err)
   369  
   370  		assert.Equal(t, expected, actual)
   371  	})
   372  }
   373  
   374  func TestTraverse(t *testing.T) {
   375  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   376  		keys := [][]byte{{0x42, 0x00}, {0xff}, {0x42, 0x56}, {0x00}, {0x42, 0xff}}
   377  		vals := []bool{false, false, true, false, true}
   378  		expected := []bool{false, true}
   379  
   380  		_ = db.Update(func(tx *badger.Txn) error {
   381  			for i, key := range keys {
   382  				enc, err := msgpack.Marshal(vals[i])
   383  				require.NoError(t, err)
   384  				err = tx.Set(key, enc)
   385  				require.NoError(t, err)
   386  			}
   387  			return nil
   388  		})
   389  
   390  		actual := make([]bool, 0, len(keys))
   391  		iterationFunc := func() (checkFunc, createFunc, handleFunc) {
   392  			check := func(key []byte) bool {
   393  				return !bytes.Equal(key, []byte{0x42, 0x56})
   394  			}
   395  			var val bool
   396  			create := func() interface{} {
   397  				return &val
   398  			}
   399  			handle := func() error {
   400  				actual = append(actual, val)
   401  				return nil
   402  			}
   403  			return check, create, handle
   404  		}
   405  
   406  		err := db.View(traverse([]byte{0x42}, iterationFunc))
   407  		require.Nil(t, err)
   408  
   409  		assert.Equal(t, expected, actual)
   410  	})
   411  }
   412  
   413  func TestRemove(t *testing.T) {
   414  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   415  		e := Entity{ID: 1337}
   416  		key := []byte{0x01, 0x02, 0x03}
   417  		val, _ := msgpack.Marshal(e)
   418  
   419  		_ = db.Update(func(tx *badger.Txn) error {
   420  			err := tx.Set(key, val)
   421  			require.NoError(t, err)
   422  			return nil
   423  		})
   424  
   425  		t.Run("should be able to remove", func(t *testing.T) {
   426  			_ = db.Update(func(txn *badger.Txn) error {
   427  				err := remove(key)(txn)
   428  				assert.NoError(t, err)
   429  
   430  				_, err = txn.Get(key)
   431  				assert.ErrorIs(t, err, badger.ErrKeyNotFound)
   432  
   433  				return nil
   434  			})
   435  		})
   436  
   437  		t.Run("should error when removing non-existing value", func(t *testing.T) {
   438  			nonexistantKey := append(key, 0x01)
   439  			_ = db.Update(func(txn *badger.Txn) error {
   440  				err := remove(nonexistantKey)(txn)
   441  				assert.ErrorIs(t, err, storage.ErrNotFound)
   442  				assert.Error(t, err)
   443  				return nil
   444  			})
   445  		})
   446  	})
   447  }
   448  
   449  func TestRemoveByPrefix(t *testing.T) {
   450  	t.Run("should no-op when removing non-existing value", func(t *testing.T) {
   451  		unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   452  			e := Entity{ID: 1337}
   453  			key := []byte{0x01, 0x02, 0x03}
   454  			val, _ := msgpack.Marshal(e)
   455  
   456  			_ = db.Update(func(tx *badger.Txn) error {
   457  				err := tx.Set(key, val)
   458  				assert.NoError(t, err)
   459  				return nil
   460  			})
   461  
   462  			nonexistantKey := append(key, 0x01)
   463  			err := db.Update(removeByPrefix(nonexistantKey))
   464  			assert.NoError(t, err)
   465  
   466  			var act Entity
   467  			err = db.View(retrieve(key, &act))
   468  			require.NoError(t, err)
   469  
   470  			assert.Equal(t, e, act)
   471  		})
   472  	})
   473  
   474  	t.Run("should be able to remove", func(t *testing.T) {
   475  		unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   476  			e := Entity{ID: 1337}
   477  			key := []byte{0x01, 0x02, 0x03}
   478  			val, _ := msgpack.Marshal(e)
   479  
   480  			_ = db.Update(func(tx *badger.Txn) error {
   481  				err := tx.Set(key, val)
   482  				assert.NoError(t, err)
   483  				return nil
   484  			})
   485  
   486  			_ = db.Update(func(txn *badger.Txn) error {
   487  				prefix := []byte{0x01, 0x02}
   488  				err := removeByPrefix(prefix)(txn)
   489  				assert.NoError(t, err)
   490  
   491  				_, err = txn.Get(key)
   492  				assert.Error(t, err)
   493  				assert.IsType(t, badger.ErrKeyNotFound, err)
   494  
   495  				return nil
   496  			})
   497  		})
   498  	})
   499  
   500  	t.Run("should be able to remove by key", func(t *testing.T) {
   501  		unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   502  			e := Entity{ID: 1337}
   503  			key := []byte{0x01, 0x02, 0x03}
   504  			val, _ := msgpack.Marshal(e)
   505  
   506  			_ = db.Update(func(tx *badger.Txn) error {
   507  				err := tx.Set(key, val)
   508  				assert.NoError(t, err)
   509  				return nil
   510  			})
   511  
   512  			_ = db.Update(func(txn *badger.Txn) error {
   513  				err := removeByPrefix(key)(txn)
   514  				assert.NoError(t, err)
   515  
   516  				_, err = txn.Get(key)
   517  				assert.Error(t, err)
   518  				assert.IsType(t, badger.ErrKeyNotFound, err)
   519  
   520  				return nil
   521  			})
   522  		})
   523  	})
   524  }
   525  
   526  func TestIterateBoundaries(t *testing.T) {
   527  
   528  	// create range of keys covering all boundaries around our start/end values
   529  	start := []byte{0x10}
   530  	end := []byte{0x20}
   531  	keys := [][]byte{
   532  		// before start -> not included in range
   533  		{0x09, 0xff},
   534  		// shares prefix with start -> included in range
   535  		{0x10, 0x00},
   536  		{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   537  		{0x10, 0xff},
   538  		{0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   539  		// prefix between start and end -> included in range
   540  		{0x11, 0x00},
   541  		{0x19, 0xff},
   542  		// shares prefix with end -> included in range
   543  		{0x20, 0x00},
   544  		{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   545  		{0x20, 0xff},
   546  		{0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   547  		// after end -> not included in range
   548  		{0x21, 0x00},
   549  	}
   550  
   551  	// set the maximum current DB key range
   552  	for _, key := range keys {
   553  		if uint32(len(key)) > max {
   554  			max = uint32(len(key))
   555  		}
   556  	}
   557  
   558  	// keys within the expected range
   559  	keysInRange := keys[1:11]
   560  
   561  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   562  
   563  		// insert the keys into the database
   564  		_ = db.Update(func(tx *badger.Txn) error {
   565  			for _, key := range keys {
   566  				err := tx.Set(key, []byte{0x00})
   567  				if err != nil {
   568  					return err
   569  				}
   570  			}
   571  			return nil
   572  		})
   573  
   574  		// define iteration function that simply appends all traversed keys
   575  		var found [][]byte
   576  		iteration := func() (checkFunc, createFunc, handleFunc) {
   577  			check := func(key []byte) bool {
   578  				found = append(found, key)
   579  				return false
   580  			}
   581  			create := func() interface{} {
   582  				return nil
   583  			}
   584  			handle := func() error {
   585  				return fmt.Errorf("shouldn't handle anything")
   586  			}
   587  			return check, create, handle
   588  		}
   589  
   590  		// iterate forward and check boundaries are included correctly
   591  		found = nil
   592  		err := db.View(iterate(start, end, iteration))
   593  		for i, f := range found {
   594  			t.Logf("forward %d: %x", i, f)
   595  		}
   596  		require.NoError(t, err, "should iterate forward without error")
   597  		assert.ElementsMatch(t, keysInRange, found, "forward iteration should go over correct keys")
   598  
   599  		// iterate backward and check boundaries are included correctly
   600  		found = nil
   601  		err = db.View(iterate(end, start, iteration))
   602  		for i, f := range found {
   603  			t.Logf("backward %d: %x", i, f)
   604  		}
   605  		require.NoError(t, err, "should iterate backward without error")
   606  		assert.ElementsMatch(t, keysInRange, found, "backward iteration should go over correct keys")
   607  	})
   608  }
   609  
   610  func TestFindHighestAtOrBelow(t *testing.T) {
   611  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   612  		prefix := []byte("test_prefix")
   613  
   614  		type Entity struct {
   615  			Value uint64
   616  		}
   617  
   618  		entity1 := Entity{Value: 41}
   619  		entity2 := Entity{Value: 42}
   620  		entity3 := Entity{Value: 43}
   621  
   622  		err := db.Update(func(tx *badger.Txn) error {
   623  			key := append(prefix, b(uint64(15))...)
   624  			val, err := msgpack.Marshal(entity3)
   625  			if err != nil {
   626  				return err
   627  			}
   628  			err = tx.Set(key, val)
   629  			if err != nil {
   630  				return err
   631  			}
   632  
   633  			key = append(prefix, b(uint64(5))...)
   634  			val, err = msgpack.Marshal(entity1)
   635  			if err != nil {
   636  				return err
   637  			}
   638  			err = tx.Set(key, val)
   639  			if err != nil {
   640  				return err
   641  			}
   642  
   643  			key = append(prefix, b(uint64(10))...)
   644  			val, err = msgpack.Marshal(entity2)
   645  			if err != nil {
   646  				return err
   647  			}
   648  			err = tx.Set(key, val)
   649  			if err != nil {
   650  				return err
   651  			}
   652  			return nil
   653  		})
   654  		require.NoError(t, err)
   655  
   656  		var entity Entity
   657  
   658  		t.Run("target height exists", func(t *testing.T) {
   659  			err = findHighestAtOrBelow(
   660  				prefix,
   661  				10,
   662  				&entity)(db.NewTransaction(false))
   663  			require.NoError(t, err)
   664  			require.Equal(t, uint64(42), entity.Value)
   665  		})
   666  
   667  		t.Run("target height above", func(t *testing.T) {
   668  			err = findHighestAtOrBelow(
   669  				prefix,
   670  				11,
   671  				&entity)(db.NewTransaction(false))
   672  			require.NoError(t, err)
   673  			require.Equal(t, uint64(42), entity.Value)
   674  		})
   675  
   676  		t.Run("target height above highest", func(t *testing.T) {
   677  			err = findHighestAtOrBelow(
   678  				prefix,
   679  				20,
   680  				&entity)(db.NewTransaction(false))
   681  			require.NoError(t, err)
   682  			require.Equal(t, uint64(43), entity.Value)
   683  		})
   684  
   685  		t.Run("target height below lowest", func(t *testing.T) {
   686  			err = findHighestAtOrBelow(
   687  				prefix,
   688  				4,
   689  				&entity)(db.NewTransaction(false))
   690  			require.ErrorIs(t, err, storage.ErrNotFound)
   691  		})
   692  
   693  		t.Run("empty prefix", func(t *testing.T) {
   694  			err = findHighestAtOrBelow(
   695  				[]byte{},
   696  				5,
   697  				&entity)(db.NewTransaction(false))
   698  			require.Error(t, err)
   699  			require.Contains(t, err.Error(), "prefix must not be empty")
   700  		})
   701  	})
   702  }