github.com/onflow/flow-go@v0.33.17/storage/badger/operation/common_test.go (about)

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