github.com/ledgerwatch/erigon-lib@v1.0.0/kv/mdbx/kv_abstract_test.go (about)

     1  /*
     2     Copyright 2021 Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package mdbx_test
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net"
    23  	"runtime"
    24  	"testing"
    25  
    26  	"github.com/ledgerwatch/erigon-lib/gointerfaces"
    27  	"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
    28  	"github.com/ledgerwatch/erigon-lib/kv"
    29  	"github.com/ledgerwatch/erigon-lib/kv/mdbx"
    30  	"github.com/ledgerwatch/erigon-lib/kv/memdb"
    31  	"github.com/ledgerwatch/erigon-lib/kv/remotedb"
    32  	"github.com/ledgerwatch/erigon-lib/kv/remotedbserver"
    33  	"github.com/ledgerwatch/log/v3"
    34  	"github.com/stretchr/testify/assert"
    35  	"github.com/stretchr/testify/require"
    36  	"google.golang.org/grpc"
    37  	"google.golang.org/grpc/test/bufconn"
    38  )
    39  
    40  func TestSequence(t *testing.T) {
    41  	if runtime.GOOS == "windows" {
    42  		t.Skip("fix me on win please")
    43  	}
    44  
    45  	writeDBs, _ := setupDatabases(t, log.New(), func(defaultBuckets kv.TableCfg) kv.TableCfg {
    46  		return defaultBuckets
    47  	})
    48  	ctx := context.Background()
    49  
    50  	for _, db := range writeDBs {
    51  		db := db
    52  		tx, err := db.BeginRw(ctx)
    53  		require.NoError(t, err)
    54  		defer tx.Rollback()
    55  
    56  		i, err := tx.ReadSequence(kv.ChaindataTables[0])
    57  		require.NoError(t, err)
    58  		require.Equal(t, uint64(0), i)
    59  		i, err = tx.IncrementSequence(kv.ChaindataTables[0], 1)
    60  		require.NoError(t, err)
    61  		require.Equal(t, uint64(0), i)
    62  		i, err = tx.IncrementSequence(kv.ChaindataTables[0], 6)
    63  		require.NoError(t, err)
    64  		require.Equal(t, uint64(1), i)
    65  		i, err = tx.IncrementSequence(kv.ChaindataTables[0], 1)
    66  		require.NoError(t, err)
    67  		require.Equal(t, uint64(7), i)
    68  
    69  		i, err = tx.ReadSequence(kv.ChaindataTables[1])
    70  		require.NoError(t, err)
    71  		require.Equal(t, uint64(0), i)
    72  		i, err = tx.IncrementSequence(kv.ChaindataTables[1], 1)
    73  		require.NoError(t, err)
    74  		require.Equal(t, uint64(0), i)
    75  		i, err = tx.IncrementSequence(kv.ChaindataTables[1], 6)
    76  		require.NoError(t, err)
    77  		require.Equal(t, uint64(1), i)
    78  		i, err = tx.IncrementSequence(kv.ChaindataTables[1], 1)
    79  		require.NoError(t, err)
    80  		require.Equal(t, uint64(7), i)
    81  		tx.Rollback()
    82  	}
    83  }
    84  
    85  func TestManagedTx(t *testing.T) {
    86  	if runtime.GOOS == "windows" {
    87  		t.Skip("fix me on win please")
    88  	}
    89  
    90  	logger := log.New()
    91  	defaultConfig := kv.ChaindataTablesCfg
    92  	defer func() {
    93  		kv.ChaindataTablesCfg = defaultConfig
    94  	}()
    95  
    96  	bucketID := 0
    97  	bucket1 := kv.ChaindataTables[bucketID]
    98  	bucket2 := kv.ChaindataTables[bucketID+1]
    99  	writeDBs, readDBs := setupDatabases(t, logger, func(defaultBuckets kv.TableCfg) kv.TableCfg {
   100  		return map[string]kv.TableCfgItem{
   101  			bucket1: {
   102  				Flags:                     kv.DupSort,
   103  				AutoDupSortKeysConversion: true,
   104  				DupToLen:                  4,
   105  				DupFromLen:                6,
   106  			},
   107  			bucket2: {
   108  				Flags: 0,
   109  			},
   110  		}
   111  	})
   112  
   113  	ctx := context.Background()
   114  
   115  	for _, db := range writeDBs {
   116  		db := db
   117  		tx, err := db.BeginRw(ctx)
   118  		require.NoError(t, err)
   119  		defer tx.Rollback()
   120  
   121  		c, err := tx.RwCursor(bucket1)
   122  		require.NoError(t, err)
   123  		c1, err := tx.RwCursor(bucket2)
   124  		require.NoError(t, err)
   125  		require.NoError(t, c.Append([]byte{0}, []byte{1}))
   126  		require.NoError(t, c1.Append([]byte{0}, []byte{1}))
   127  		require.NoError(t, c.Append([]byte{0, 0, 0, 0, 0, 1}, []byte{1})) // prefixes of len=FromLen for DupSort test (other keys must be <ToLen)
   128  		require.NoError(t, c1.Append([]byte{0, 0, 0, 0, 0, 1}, []byte{1}))
   129  		require.NoError(t, c.Append([]byte{0, 0, 0, 0, 0, 2}, []byte{1}))
   130  		require.NoError(t, c1.Append([]byte{0, 0, 0, 0, 0, 2}, []byte{1}))
   131  		require.NoError(t, c.Append([]byte{0, 0, 1}, []byte{1}))
   132  		require.NoError(t, c1.Append([]byte{0, 0, 1}, []byte{1}))
   133  		for i := uint8(1); i < 10; i++ {
   134  			require.NoError(t, c.Append([]byte{i}, []byte{1}))
   135  			require.NoError(t, c1.Append([]byte{i}, []byte{1}))
   136  		}
   137  		require.NoError(t, c.Put([]byte{0, 0, 0, 0, 0, 1}, []byte{2}))
   138  		require.NoError(t, c1.Put([]byte{0, 0, 0, 0, 0, 1}, []byte{2}))
   139  		err = tx.Commit()
   140  		require.NoError(t, err)
   141  	}
   142  
   143  	for _, db := range readDBs {
   144  		db := db
   145  		msg := fmt.Sprintf("%T", db)
   146  		switch db.(type) {
   147  		case *remotedb.DB:
   148  		default:
   149  			continue
   150  		}
   151  
   152  		t.Run("filter "+msg, func(t *testing.T) {
   153  			//testPrefixFilter(t, db, bucket1)
   154  		})
   155  		t.Run("multiple cursors "+msg, func(t *testing.T) {
   156  			testMultiCursor(t, db, bucket1, bucket2)
   157  		})
   158  	}
   159  }
   160  
   161  func TestRemoteKvVersion(t *testing.T) {
   162  	if runtime.GOOS == "windows" {
   163  		t.Skip("fix me on win please")
   164  	}
   165  	ctx := context.Background()
   166  	logger := log.New()
   167  	writeDB := mdbx.NewMDBX(logger).InMem("").MustOpen()
   168  	defer writeDB.Close()
   169  	conn := bufconn.Listen(1024 * 1024)
   170  	grpcServer := grpc.NewServer()
   171  	go func() {
   172  		remote.RegisterKVServer(grpcServer, remotedbserver.NewKvServer(ctx, writeDB, nil, nil, logger))
   173  		if err := grpcServer.Serve(conn); err != nil {
   174  			log.Error("private RPC server fail", "err", err)
   175  		}
   176  	}()
   177  	v := gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion)
   178  	// Different Major versions
   179  	v1 := v
   180  	v1.Major++
   181  
   182  	cc, err := grpc.Dial("", grpc.WithInsecure(), grpc.WithContextDialer(func(ctx context.Context, url string) (net.Conn, error) { return conn.Dial() }))
   183  	assert.NoError(t, err)
   184  	a, err := remotedb.NewRemote(v1, logger, remote.NewKVClient(cc)).Open()
   185  	if err != nil {
   186  		t.Fatalf("%v", err)
   187  	}
   188  	require.False(t, a.EnsureVersionCompatibility())
   189  	// Different Minor versions
   190  	v2 := v
   191  	v2.Minor++
   192  	a, err = remotedb.NewRemote(v2, logger, remote.NewKVClient(cc)).Open()
   193  	if err != nil {
   194  		t.Fatalf("%v", err)
   195  	}
   196  	require.False(t, a.EnsureVersionCompatibility())
   197  	// Different Patch versions
   198  	v3 := v
   199  	v3.Patch++
   200  	a, err = remotedb.NewRemote(v3, logger, remote.NewKVClient(cc)).Open()
   201  	require.NoError(t, err)
   202  	require.True(t, a.EnsureVersionCompatibility())
   203  }
   204  
   205  func TestRemoteKvRange(t *testing.T) {
   206  	if runtime.GOOS == "windows" {
   207  		t.Skip("fix me on win please")
   208  	}
   209  	logger := log.New()
   210  	ctx, writeDB := context.Background(), memdb.NewTestDB(t)
   211  	grpcServer, conn := grpc.NewServer(), bufconn.Listen(1024*1024)
   212  	go func() {
   213  		kvServer := remotedbserver.NewKvServer(ctx, writeDB, nil, nil, logger)
   214  		remote.RegisterKVServer(grpcServer, kvServer)
   215  		if err := grpcServer.Serve(conn); err != nil {
   216  			log.Error("private RPC server fail", "err", err)
   217  		}
   218  	}()
   219  
   220  	cc, err := grpc.Dial("", grpc.WithInsecure(), grpc.WithContextDialer(func(ctx context.Context, url string) (net.Conn, error) { return conn.Dial() }))
   221  	require.NoError(t, err)
   222  	db, err := remotedb.NewRemote(gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion), logger, remote.NewKVClient(cc)).Open()
   223  	require.NoError(t, err)
   224  	require.True(t, db.EnsureVersionCompatibility())
   225  
   226  	require := require.New(t)
   227  	require.NoError(writeDB.Update(ctx, func(tx kv.RwTx) error {
   228  		wc, err := tx.RwCursorDupSort(kv.PlainState)
   229  		require.NoError(err)
   230  		require.NoError(wc.Append([]byte{1}, []byte{1}))
   231  		require.NoError(wc.Append([]byte{1}, []byte{2}))
   232  		require.NoError(wc.Append([]byte{2}, []byte{1}))
   233  		require.NoError(wc.Append([]byte{3}, []byte{1}))
   234  		return nil
   235  	}))
   236  
   237  	require.NoError(db.View(ctx, func(tx kv.Tx) error {
   238  		c, err := tx.Cursor(kv.PlainState)
   239  		require.NoError(err)
   240  
   241  		k, v, err := c.First()
   242  		require.NoError(err)
   243  		require.Equal([]byte{1}, k)
   244  		require.Equal([]byte{1}, v)
   245  
   246  		// it must be possible to Stream and manipulate cursors in same time
   247  		cnt := 0
   248  		require.NoError(tx.ForEach(kv.PlainState, nil, func(_, _ []byte) error {
   249  			if cnt == 0 {
   250  				k, v, err = c.Next()
   251  				require.NoError(err)
   252  				require.Equal([]byte{1}, k)
   253  				require.Equal([]byte{2}, v)
   254  			}
   255  			cnt++
   256  			return nil
   257  		}))
   258  		require.Equal(4, cnt)
   259  
   260  		// remote Tx must provide Snapshots-Isolation-Level: new updates are not visible for old readers
   261  		require.NoError(writeDB.Update(ctx, func(tx kv.RwTx) error {
   262  			require.NoError(tx.Put(kv.PlainState, []byte{4}, []byte{1}))
   263  			return nil
   264  		}))
   265  
   266  		k, v, err = c.Last()
   267  		require.NoError(err)
   268  		require.Equal([]byte{3}, k)
   269  		require.Equal([]byte{1}, v)
   270  		return nil
   271  	}))
   272  
   273  	err = db.View(ctx, func(tx kv.Tx) error {
   274  		cntRange := func(from, to []byte) (i int) {
   275  			it, err := tx.Range(kv.PlainState, from, to)
   276  			require.NoError(err)
   277  			for it.HasNext() {
   278  				_, _, err = it.Next()
   279  				require.NoError(err)
   280  				i++
   281  			}
   282  			return i
   283  		}
   284  
   285  		require.Equal(2, cntRange([]byte{2}, []byte{4}))
   286  		require.Equal(4, cntRange(nil, []byte{4}))
   287  		require.Equal(3, cntRange([]byte{2}, nil))
   288  		require.Equal(5, cntRange(nil, nil))
   289  		return nil
   290  	})
   291  	require.NoError(err)
   292  
   293  	// Limit
   294  	err = db.View(ctx, func(tx kv.Tx) error {
   295  		cntRange := func(from, to []byte) (i int) {
   296  			it, err := tx.RangeAscend(kv.PlainState, from, to, 2)
   297  			require.NoError(err)
   298  			for it.HasNext() {
   299  				_, _, err := it.Next()
   300  				require.NoError(err)
   301  				i++
   302  			}
   303  			return i
   304  		}
   305  
   306  		require.Equal(2, cntRange([]byte{2}, []byte{4}))
   307  		require.Equal(2, cntRange(nil, []byte{4}))
   308  		require.Equal(2, cntRange([]byte{2}, nil))
   309  		require.Equal(2, cntRange(nil, nil))
   310  		return nil
   311  	})
   312  	require.NoError(err)
   313  
   314  	err = db.View(ctx, func(tx kv.Tx) error {
   315  		cntRange := func(from, to []byte) (i int) {
   316  			it, err := tx.RangeDescend(kv.PlainState, from, to, 2)
   317  			require.NoError(err)
   318  			for it.HasNext() {
   319  				_, _, err := it.Next()
   320  				require.NoError(err)
   321  				i++
   322  			}
   323  			return i
   324  		}
   325  
   326  		require.Equal(2, cntRange([]byte{4}, []byte{2}))
   327  		require.Equal(0, cntRange(nil, []byte{4}))
   328  		require.Equal(2, cntRange([]byte{2}, nil))
   329  		require.Equal(2, cntRange(nil, nil))
   330  		return nil
   331  	})
   332  	require.NoError(err)
   333  }
   334  
   335  func setupDatabases(t *testing.T, logger log.Logger, f mdbx.TableCfgFunc) (writeDBs []kv.RwDB, readDBs []kv.RwDB) {
   336  	t.Helper()
   337  	ctx := context.Background()
   338  	writeDBs = []kv.RwDB{
   339  		mdbx.NewMDBX(logger).InMem("").WithTableCfg(f).MustOpen(),
   340  		mdbx.NewMDBX(logger).InMem("").WithTableCfg(f).MustOpen(), // for remote db
   341  	}
   342  
   343  	conn := bufconn.Listen(1024 * 1024)
   344  
   345  	grpcServer := grpc.NewServer()
   346  	f2 := func() {
   347  		remote.RegisterKVServer(grpcServer, remotedbserver.NewKvServer(ctx, writeDBs[1], nil, nil, logger))
   348  		if err := grpcServer.Serve(conn); err != nil {
   349  			logger.Error("private RPC server fail", "err", err)
   350  		}
   351  	}
   352  	go f2()
   353  	v := gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion)
   354  	cc, err := grpc.Dial("", grpc.WithInsecure(), grpc.WithContextDialer(func(ctx context.Context, url string) (net.Conn, error) { return conn.Dial() }))
   355  	assert.NoError(t, err)
   356  	rdb, err := remotedb.NewRemote(v, logger, remote.NewKVClient(cc)).Open()
   357  	assert.NoError(t, err)
   358  	readDBs = []kv.RwDB{
   359  		writeDBs[0],
   360  		writeDBs[1],
   361  		rdb,
   362  	}
   363  
   364  	t.Cleanup(func() {
   365  		grpcServer.Stop()
   366  
   367  		if err := conn.Close(); err != nil {
   368  			panic(err)
   369  		}
   370  
   371  		for _, db := range readDBs {
   372  			db.Close()
   373  		}
   374  
   375  		for _, db := range writeDBs {
   376  			db.Close()
   377  		}
   378  
   379  	})
   380  	return writeDBs, readDBs
   381  }
   382  
   383  func testMultiCursor(t *testing.T, db kv.RwDB, bucket1, bucket2 string) {
   384  	t.Helper()
   385  	assert, ctx := assert.New(t), context.Background()
   386  
   387  	if err := db.View(ctx, func(tx kv.Tx) error {
   388  		c1, err := tx.Cursor(bucket1)
   389  		if err != nil {
   390  			return err
   391  		}
   392  		c2, err := tx.Cursor(bucket2)
   393  		if err != nil {
   394  			return err
   395  		}
   396  
   397  		k1, v1, err := c1.First()
   398  		assert.NoError(err)
   399  		k2, v2, err := c2.First()
   400  		assert.NoError(err)
   401  		assert.Equal(k1, k2)
   402  		assert.Equal(v1, v2)
   403  
   404  		k1, v1, err = c1.Next()
   405  		assert.NoError(err)
   406  		k2, v2, err = c2.Next()
   407  		assert.NoError(err)
   408  		assert.Equal(k1, k2)
   409  		assert.Equal(v1, v2)
   410  
   411  		k1, v1, err = c1.Seek([]byte{0})
   412  		assert.NoError(err)
   413  		k2, v2, err = c2.Seek([]byte{0})
   414  		assert.NoError(err)
   415  		assert.Equal(k1, k2)
   416  		assert.Equal(v1, v2)
   417  
   418  		k1, v1, err = c1.Seek([]byte{0, 0})
   419  		assert.NoError(err)
   420  		k2, v2, err = c2.Seek([]byte{0, 0})
   421  		assert.NoError(err)
   422  		assert.Equal(k1, k2)
   423  		assert.Equal(v1, v2)
   424  
   425  		k1, v1, err = c1.Seek([]byte{0, 0, 0, 0})
   426  		assert.NoError(err)
   427  		k2, v2, err = c2.Seek([]byte{0, 0, 0, 0})
   428  		assert.NoError(err)
   429  		assert.Equal(k1, k2)
   430  		assert.Equal(v1, v2)
   431  
   432  		k1, v1, err = c1.Next()
   433  		assert.NoError(err)
   434  		k2, v2, err = c2.Next()
   435  		assert.NoError(err)
   436  		assert.Equal(k1, k2)
   437  		assert.Equal(v1, v2)
   438  
   439  		k1, v1, err = c1.Seek([]byte{0})
   440  		assert.NoError(err)
   441  		k2, v2, err = c2.Seek([]byte{0})
   442  		assert.NoError(err)
   443  		assert.Equal(k1, k2)
   444  		assert.Equal(v1, v2)
   445  
   446  		k1, v1, err = c1.Seek([]byte{0, 0})
   447  		assert.NoError(err)
   448  		k2, v2, err = c2.Seek([]byte{0, 0})
   449  		assert.NoError(err)
   450  		assert.Equal(k1, k2)
   451  		assert.Equal(v1, v2)
   452  
   453  		k1, v1, err = c1.Seek([]byte{0, 0, 0, 0})
   454  		assert.NoError(err)
   455  		k2, v2, err = c2.Seek([]byte{0, 0, 0, 0})
   456  		assert.NoError(err)
   457  		assert.Equal(k1, k2)
   458  		assert.Equal(v1, v2)
   459  
   460  		k1, v1, err = c1.Next()
   461  		assert.NoError(err)
   462  		k2, v2, err = c2.Next()
   463  		assert.NoError(err)
   464  		assert.Equal(k1, k2)
   465  		assert.Equal(v1, v2)
   466  		k1, v1, err = c1.Seek([]byte{2})
   467  		assert.NoError(err)
   468  		k2, v2, err = c2.Seek([]byte{2})
   469  		assert.NoError(err)
   470  		assert.Equal(k1, k2)
   471  		assert.Equal(v1, v2)
   472  
   473  		return nil
   474  	}); err != nil {
   475  		assert.NoError(err)
   476  	}
   477  }
   478  
   479  //func TestMultipleBuckets(t *testing.T) {
   480  //	writeDBs, readDBs, closeAll := setupDatabases(ethdb.WithChaindataTables)
   481  //	defer closeAll()
   482  //
   483  //	ctx := context.Background()
   484  //
   485  //	for _, db := range writeDBs {
   486  //		db := db
   487  //		msg := fmt.Sprintf("%T", db)
   488  //		t.Run("FillBuckets "+msg, func(t *testing.T) {
   489  //			if err := db.Update(ctx, func(tx ethdb.Tx) error {
   490  //				c := tx.Cursor(dbutils.ChaindataTables[0])
   491  //				for i := uint8(0); i < 10; i++ {
   492  //					require.NoError(t, c.Put([]byte{i}, []byte{i}))
   493  //				}
   494  //				c2 := tx.Cursor(dbutils.ChaindataTables[1])
   495  //				for i := uint8(0); i < 12; i++ {
   496  //					require.NoError(t, c2.Put([]byte{i}, []byte{i}))
   497  //				}
   498  //
   499  //				// delete from first bucket key 5, then will seek on it and expect to see key 6
   500  //				if err := c.Delete([]byte{5}, nil); err != nil {
   501  //					return err
   502  //				}
   503  //				// delete non-existing key
   504  //				if err := c.Delete([]byte{6, 1}, nil); err != nil {
   505  //					return err
   506  //				}
   507  //
   508  //				return nil
   509  //			}); err != nil {
   510  //				require.NoError(t, err)
   511  //			}
   512  //		})
   513  //	}
   514  //
   515  //	for _, db := range readDBs {
   516  //		db := db
   517  //		msg := fmt.Sprintf("%T", db)
   518  //		t.Run("MultipleBuckets "+msg, func(t *testing.T) {
   519  //			counter2, counter := 0, 0
   520  //			var key, value []byte
   521  //			err := db.View(ctx, func(tx ethdb.Tx) error {
   522  //				c := tx.Cursor(dbutils.ChaindataTables[0])
   523  //				for k, _, err := c.First(); k != nil; k, _, err = c.Next() {
   524  //					if err != nil {
   525  //						return err
   526  //					}
   527  //					counter++
   528  //				}
   529  //
   530  //				c2 := tx.Cursor(dbutils.ChaindataTables[1])
   531  //				for k, _, err := c2.First(); k != nil; k, _, err = c2.Next() {
   532  //					if err != nil {
   533  //						return err
   534  //					}
   535  //					counter2++
   536  //				}
   537  //
   538  //				c3 := tx.Cursor(dbutils.ChaindataTables[0])
   539  //				k, v, err := c3.Seek([]byte{5})
   540  //				if err != nil {
   541  //					return err
   542  //				}
   543  //				key = common.CopyBytes(k)
   544  //				value = common.CopyBytes(v)
   545  //
   546  //				return nil
   547  //			})
   548  //			require.NoError(t, err)
   549  //			assert.Equal(t, 9, counter)
   550  //			assert.Equal(t, 12, counter2)
   551  //			assert.Equal(t, []byte{6}, key)
   552  //			assert.Equal(t, []byte{6}, value)
   553  //		})
   554  //	}
   555  //}
   556  
   557  //func TestReadAfterPut(t *testing.T) {
   558  //	writeDBs, _, closeAll := setupDatabases(ethdb.WithChaindataTables)
   559  //	defer closeAll()
   560  //
   561  //	ctx := context.Background()
   562  //
   563  //	for _, db := range writeDBs {
   564  //		db := db
   565  //		msg := fmt.Sprintf("%T", db)
   566  //		t.Run("GetAfterPut "+msg, func(t *testing.T) {
   567  //			if err := db.Update(ctx, func(tx ethdb.Tx) error {
   568  //				c := tx.Cursor(dbutils.ChaindataTables[0])
   569  //				for i := uint8(0); i < 10; i++ { // don't read in same loop to check that writes don't affect each other (for example by sharing bucket.prefix buffer)
   570  //					require.NoError(t, c.Put([]byte{i}, []byte{i}))
   571  //				}
   572  //
   573  //				for i := uint8(0); i < 10; i++ {
   574  //					v, err := c.SeekExact([]byte{i})
   575  //					require.NoError(t, err)
   576  //					require.Equal(t, []byte{i}, v)
   577  //				}
   578  //
   579  //				c2 := tx.Cursor(dbutils.ChaindataTables[1])
   580  //				for i := uint8(0); i < 12; i++ {
   581  //					require.NoError(t, c2.Put([]byte{i}, []byte{i}))
   582  //				}
   583  //
   584  //				for i := uint8(0); i < 12; i++ {
   585  //					v, err := c2.SeekExact([]byte{i})
   586  //					require.NoError(t, err)
   587  //					require.Equal(t, []byte{i}, v)
   588  //				}
   589  //
   590  //				{
   591  //					require.NoError(t, c2.Delete([]byte{5}, nil))
   592  //					v, err := c2.SeekExact([]byte{5})
   593  //					require.NoError(t, err)
   594  //					require.Nil(t, v)
   595  //
   596  //					require.NoError(t, c2.Delete([]byte{255}, nil)) // delete non-existing key
   597  //				}
   598  //
   599  //				return nil
   600  //			}); err != nil {
   601  //				require.NoError(t, err)
   602  //			}
   603  //		})
   604  //
   605  //		t.Run("cursor put and delete"+msg, func(t *testing.T) {
   606  //			if err := db.Update(ctx, func(tx ethdb.Tx) error {
   607  //				c3 := tx.Cursor(dbutils.ChaindataTables[2])
   608  //				for i := uint8(0); i < 10; i++ { // don't read in same loop to check that writes don't affect each other (for example by sharing bucket.prefix buffer)
   609  //					require.NoError(t, c3.Put([]byte{i}, []byte{i}))
   610  //				}
   611  //				for i := uint8(0); i < 10; i++ {
   612  //					v, err := tx.GetOne(dbutils.ChaindataTables[2], []byte{i})
   613  //					require.NoError(t, err)
   614  //					require.Equal(t, []byte{i}, v)
   615  //				}
   616  //
   617  //				require.NoError(t, c3.Delete([]byte{255}, nil)) // delete non-existing key
   618  //				return nil
   619  //			}); err != nil {
   620  //				t.Error(err)
   621  //			}
   622  //
   623  //			if err := db.Update(ctx, func(tx ethdb.Tx) error {
   624  //				c3 := tx.Cursor(dbutils.ChaindataTables[2])
   625  //				require.NoError(t, c3.Delete([]byte{5}, nil))
   626  //				v, err := tx.GetOne(dbutils.ChaindataTables[2], []byte{5})
   627  //				require.NoError(t, err)
   628  //				require.Nil(t, v)
   629  //				return nil
   630  //			}); err != nil {
   631  //				t.Error(err)
   632  //			}
   633  //		})
   634  //	}
   635  //}