diff --git a/common/changeset/account_changeset_utils.go b/common/changeset/account_changeset_utils.go index e60b19ae7de..56ad446e15e 100644 --- a/common/changeset/account_changeset_utils.go +++ b/common/changeset/account_changeset_utils.go @@ -10,13 +10,11 @@ import ( func findInAccountChangeSet(c ethdb.CursorDupSort, blockNumber uint64, key []byte, keyLen int) ([]byte, error) { fromDBFormat := FromDBFormat(keyLen) - k, v, err := c.SeekBothRange(dbutils.EncodeBlockNumber(blockNumber), key) + k := dbutils.EncodeBlockNumber(blockNumber) + v, err := c.SeekBothRange(k, key) if err != nil { return nil, err } - if k == nil { - return nil, nil - } _, k, v = fromDBFormat(k, v) if !bytes.HasPrefix(k, key) { return nil, nil diff --git a/common/changeset/storage_changeset_utils.go b/common/changeset/storage_changeset_utils.go index 229ecffa96e..d268b668140 100644 --- a/common/changeset/storage_changeset_utils.go +++ b/common/changeset/storage_changeset_utils.go @@ -63,13 +63,11 @@ func doSearch2( binary.BigEndian.PutUint64(seek, blockNumber) copy(seek[8:], addrBytesToFind) binary.BigEndian.PutUint64(seek[8+keyPrefixLen:], incarnation) - k, v, err := c.SeekBothRange(seek, keyBytesToFind) + k := seek + v, err := c.SeekBothRange(seek, keyBytesToFind) if err != nil { return nil, err } - if k == nil { - return nil, ErrNotFound - } if !bytes.HasPrefix(v, keyBytesToFind) { return nil, ErrNotFound } diff --git a/core/state/history.go b/core/state/history.go index 450dbc9d808..36b21bb4877 100644 --- a/core/state/history.go +++ b/core/state/history.go @@ -204,7 +204,8 @@ func WalkAsOfStorage(tx ethdb.Tx, address common.Address, incarnation uint64, st copy(csKey[:], dbutils.EncodeBlockNumber(changeSetBlock)) copy(csKey[8:], address[:]) // address + incarnation binary.BigEndian.PutUint64(csKey[8+common.AddressLength:], incarnation) - kData, data, err3 := csCursor.SeekBothRange(csKey, hLoc) + kData := csKey + data, err3 := csCursor.SeekBothRange(csKey, hLoc) if err3 != nil { return err3 } @@ -299,7 +300,8 @@ func WalkAsOfAccounts(tx ethdb.Tx, startAddress common.Address, timestamp uint64 if ok { // Extract value from the changeSet csKey := dbutils.EncodeBlockNumber(changeSetBlock) - kData, data, err3 := csCursor.SeekBothRange(csKey, hK) + kData := csKey + data, err3 := csCursor.SeekBothRange(csKey, hK) if err3 != nil { return err3 } diff --git a/ethdb/kv_abstract.go b/ethdb/kv_abstract.go index 2dfbd35edc1..69e36463a7b 100644 --- a/ethdb/kv_abstract.go +++ b/ethdb/kv_abstract.go @@ -183,11 +183,11 @@ type CursorDupSort interface { // SeekBothExact - // second parameter can be nil only if searched key has no duplicates, or return error SeekBothExact(key, value []byte) ([]byte, []byte, error) - SeekBothRange(key, value []byte) ([]byte, []byte, error) + SeekBothRange(key, value []byte) ([]byte, error) FirstDup() ([]byte, error) // FirstDup - position at first data item of current key NextDup() ([]byte, []byte, error) // NextDup - position at next data item of current key NextNoDup() ([]byte, []byte, error) // NextNoDup - position at first data item of next key - LastDup(k []byte) ([]byte, error) // LastDup - position at last data item of current key + LastDup() ([]byte, error) // LastDup - position at last data item of current key CountDuplicates() (uint64, error) // CountDuplicates - number of duplicates for the current key DeleteCurrentDuplicates() error // DeleteCurrentDuplicates - deletes all of the data items for the current key diff --git a/ethdb/kv_lmdb.go b/ethdb/kv_lmdb.go index fd8deeece06..0ff9bef5ea4 100644 --- a/ethdb/kv_lmdb.go +++ b/ethdb/kv_lmdb.go @@ -688,7 +688,7 @@ func (tx *lmdbTx) GetOne(bucket string, key []byte) ([]byte, error) { return nil, err } defer c.Close() - _, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { if lmdb.IsNotFound(err) { return nil, nil @@ -720,7 +720,7 @@ func (tx *lmdbTx) HasOne(bucket string, key []byte) (bool, error) { return false, err } defer c.Close() - _, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { if lmdb.IsNotFound(err) { return false, nil @@ -836,15 +836,16 @@ func (c *LmdbCursor) getBoth(k, v []byte) ([]byte, []byte, error) { func (c *LmdbCursor) setRange(k []byte) ([]byte, []byte, error) { return c.c.Get(k, nil, lmdb.SetRange) } -func (c *LmdbCursor) getBothRange(k, v []byte) ([]byte, []byte, error) { - return c.c.Get(k, v, lmdb.GetBothRange) +func (c *LmdbCursor) getBothRange(k, v []byte) ([]byte, error) { + _, v, err := c.c.Get(k, v, lmdb.GetBothRange) + return v, err } func (c *LmdbCursor) firstDup() ([]byte, error) { _, v, err := c.c.Get(nil, nil, lmdb.FirstDup) return v, err } -func (c *LmdbCursor) lastDup(k []byte) ([]byte, error) { - _, v, err := c.c.Get(k, nil, lmdb.LastDup) +func (c *LmdbCursor) lastDup() ([]byte, error) { + _, v, err := c.c.Get(nil, nil, lmdb.LastDup) return v, err } @@ -985,7 +986,7 @@ func (c *LmdbCursor) seekDupSort(seek []byte) (k, v []byte, err error) { } if seek2 != nil && bytes.Equal(seek1, k) { - k, v, err = c.getBothRange(seek1, seek2) + v, err = c.getBothRange(seek1, seek2) if err != nil && lmdb.IsNotFound(err) { k, v, err = c.next() if err != nil { @@ -1166,7 +1167,7 @@ func (c *LmdbCursor) deleteDupSort(key []byte) error { } if len(key) == from { - _, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { // if key not found, or found another one - then nothing to delete if lmdb.IsNotFound(err) { return nil @@ -1250,7 +1251,7 @@ func (c *LmdbCursor) putDupSort(key []byte, value []byte) error { value = append(key[to:], value...) key = key[:to] - _, v, err := c.getBothRange(key, value[:from-to]) + v, err := c.getBothRange(key, value[:from-to]) if err != nil { // if key not found, or found another one - then just insert if lmdb.IsNotFound(err) { return c.put(key, value) @@ -1300,7 +1301,7 @@ func (c *LmdbCursor) SeekExact(key []byte) ([]byte, []byte, error) { b := c.bucketCfg if b.AutoDupSortKeysConversion && len(key) == b.DupFromLen { from, to := b.DupFromLen, b.DupToLen - k, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { if lmdb.IsNotFound(err) { return nil, nil, nil @@ -1310,7 +1311,7 @@ func (c *LmdbCursor) SeekExact(key []byte) ([]byte, []byte, error) { if !bytes.Equal(key[to:], v[:from-to]) { return nil, nil, nil } - return k, v[from-to:], nil + return key[:to], v[from-to:], nil } k, v, err := c.set(key) @@ -1430,21 +1431,21 @@ func (c *LmdbDupSortCursor) SeekBothExact(key, value []byte) ([]byte, []byte, er return k, v, nil } -func (c *LmdbDupSortCursor) SeekBothRange(key, value []byte) ([]byte, []byte, error) { +func (c *LmdbDupSortCursor) SeekBothRange(key, value []byte) ([]byte, error) { if c.c == nil { if err := c.initCursor(); err != nil { - return []byte{}, nil, err + return nil, err } } - k, v, err := c.getBothRange(key, value) + v, err := c.getBothRange(key, value) if err != nil { if lmdb.IsNotFound(err) { - return nil, nil, nil + return nil, nil } - return []byte{}, nil, fmt.Errorf("in SeekBothRange: %w", err) + return nil, fmt.Errorf("in SeekBothRange: %w", err) } - return k, v, nil + return v, nil } func (c *LmdbDupSortCursor) FirstDup() ([]byte, error) { @@ -1534,14 +1535,14 @@ func (c *LmdbDupSortCursor) PrevNoDup() ([]byte, []byte, error) { return k, v, nil } -func (c *LmdbDupSortCursor) LastDup(k []byte) ([]byte, error) { +func (c *LmdbDupSortCursor) LastDup() ([]byte, error) { if c.c == nil { if err := c.initCursor(); err != nil { return nil, err } } - v, err := c.lastDup(k) + v, err := c.lastDup() if err != nil { if lmdb.IsNotFound(err) { return nil, nil diff --git a/ethdb/kv_mdbx.go b/ethdb/kv_mdbx.go index edb0f63985e..5250e177498 100644 --- a/ethdb/kv_mdbx.go +++ b/ethdb/kv_mdbx.go @@ -730,7 +730,7 @@ func (tx *MdbxTx) GetOne(bucket string, key []byte) ([]byte, error) { return nil, err } defer c.Close() - _, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { if mdbx.IsNotFound(err) { return nil, nil @@ -762,7 +762,7 @@ func (tx *MdbxTx) HasOne(bucket string, key []byte) (bool, error) { return false, err } defer c.Close() - _, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { if mdbx.IsNotFound(err) { return false, nil @@ -879,21 +879,23 @@ func (c *MdbxCursor) putNoDupData(k, v []byte) error { return c.c.Put(k func (c *MdbxCursor) append(k, v []byte) error { return c.c.Put(k, v, mdbx.Append) } func (c *MdbxCursor) appendDup(k, v []byte) error { return c.c.Put(k, v, mdbx.AppendDup) } func (c *MdbxCursor) reserve(k []byte, n int) ([]byte, error) { return c.c.PutReserve(k, n, 0) } -func (c *MdbxCursor) getBoth(k, v []byte) ([]byte, []byte, error) { - return c.c.Get(k, v, mdbx.GetBoth) +func (c *MdbxCursor) getBoth(k, v []byte) ([]byte, error) { + _, v, err := c.c.Get(k, v, mdbx.GetBoth) + return v, err } func (c *MdbxCursor) setRange(k []byte) ([]byte, []byte, error) { return c.c.Get(k, nil, mdbx.SetRange) } -func (c *MdbxCursor) getBothRange(k, v []byte) ([]byte, []byte, error) { - return c.c.Get(k, v, mdbx.GetBothRange) +func (c *MdbxCursor) getBothRange(k, v []byte) ([]byte, error) { + _, v, err := c.c.Get(k, v, mdbx.GetBothRange) + return v, err } func (c *MdbxCursor) firstDup() ([]byte, error) { _, v, err := c.c.Get(nil, nil, mdbx.FirstDup) return v, err } -func (c *MdbxCursor) lastDup(k []byte) ([]byte, error) { - _, v, err := c.c.Get(k, nil, mdbx.LastDup) +func (c *MdbxCursor) lastDup() ([]byte, error) { + _, v, err := c.c.Get(nil, nil, mdbx.LastDup) return v, err } @@ -1035,7 +1037,7 @@ func (c *MdbxCursor) seekDupSort(seek []byte) (k, v []byte, err error) { } if seek2 != nil && bytes.Equal(seek1, k) { - k, v, err = c.getBothRange(seek1, seek2) + v, err = c.getBothRange(seek1, seek2) if err != nil && mdbx.IsNotFound(err) { k, v, err = c.next() if err != nil { @@ -1161,7 +1163,7 @@ func (c *MdbxCursor) Delete(k, v []byte) error { } if c.bucketCfg.Flags&mdbx.DupSort != 0 { - _, _, err := c.getBoth(k, v) + _, err := c.getBoth(k, v) if err != nil { if mdbx.IsNotFound(err) { return nil @@ -1215,7 +1217,7 @@ func (c *MdbxCursor) deleteDupSort(key []byte) error { } if len(key) == from { - _, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { // if key not found, or found another one - then nothing to delete if mdbx.IsNotFound(err) { return nil @@ -1299,7 +1301,7 @@ func (c *MdbxCursor) putDupSort(key []byte, value []byte) error { value = append(key[to:], value...) key = key[:to] - _, v, err := c.getBothRange(key, value[:from-to]) + v, err := c.getBothRange(key, value[:from-to]) if err != nil { // if key not found, or found another one - then just insert if mdbx.IsNotFound(err) { return c.put(key, value) @@ -1349,7 +1351,7 @@ func (c *MdbxCursor) SeekExact(key []byte) ([]byte, []byte, error) { b := c.bucketCfg if b.AutoDupSortKeysConversion && len(key) == b.DupFromLen { from, to := b.DupFromLen, b.DupToLen - k, v, err := c.getBothRange(key[:to], key[to:]) + v, err := c.getBothRange(key[:to], key[to:]) if err != nil { if mdbx.IsNotFound(err) { return nil, nil, nil @@ -1359,7 +1361,7 @@ func (c *MdbxCursor) SeekExact(key []byte) ([]byte, []byte, error) { if !bytes.Equal(key[to:], v[:from-to]) { return nil, nil, nil } - return k, v[from-to:], nil + return key[:to], v[from-to:], nil } k, v, err := c.set(key) @@ -1462,7 +1464,7 @@ func (c *MdbxDupSortCursor) DeleteExact(k1, k2 []byte) error { } } - _, _, err := c.getBoth(k1, k2) + _, err := c.getBoth(k1, k2) if err != nil { // if key not found, or found another one - then nothing to delete if mdbx.IsNotFound(err) { return nil @@ -1479,31 +1481,31 @@ func (c *MdbxDupSortCursor) SeekBothExact(key, value []byte) ([]byte, []byte, er } } - k, v, err := c.getBoth(key, value) + v, err := c.getBoth(key, value) if err != nil { if mdbx.IsNotFound(err) { return nil, nil, nil } return []byte{}, nil, fmt.Errorf("in SeekBothExact: %w", err) } - return k, v, nil + return key, v, nil } -func (c *MdbxDupSortCursor) SeekBothRange(key, value []byte) ([]byte, []byte, error) { +func (c *MdbxDupSortCursor) SeekBothRange(key, value []byte) ([]byte, error) { if c.c == nil { if err := c.initCursor(); err != nil { - return []byte{}, nil, err + return nil, err } } - k, v, err := c.getBothRange(key, value) + v, err := c.getBothRange(key, value) if err != nil { if mdbx.IsNotFound(err) { - return nil, nil, nil + return nil, nil } - return []byte{}, nil, fmt.Errorf("in SeekBothRange: %w", err) + return nil, fmt.Errorf("in SeekBothRange: %w", err) } - return k, v, nil + return v, nil } func (c *MdbxDupSortCursor) FirstDup() ([]byte, error) { @@ -1593,14 +1595,14 @@ func (c *MdbxDupSortCursor) PrevNoDup() ([]byte, []byte, error) { return k, v, nil } -func (c *MdbxDupSortCursor) LastDup(k []byte) ([]byte, error) { +func (c *MdbxDupSortCursor) LastDup() ([]byte, error) { if c.c == nil { if err := c.initCursor(); err != nil { return nil, err } } - v, err := c.lastDup(k) + v, err := c.lastDup() if err != nil { if mdbx.IsNotFound(err) { return nil, nil diff --git a/ethdb/kv_remote.go b/ethdb/kv_remote.go index 1b391f6493c..1d10bfa150f 100644 --- a/ethdb/kv_remote.go +++ b/ethdb/kv_remote.go @@ -438,15 +438,15 @@ func (c *remoteCursor) seekExact(k []byte) ([]byte, []byte, error) { } return pair.K, pair.V, nil } -func (c *remoteCursor) getBothRange(k, v []byte) ([]byte, []byte, error) { +func (c *remoteCursor) getBothRange(k, v []byte) ([]byte, error) { if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_SEEK_BOTH, K: k, V: v}); err != nil { - return []byte{}, nil, err + return nil, err } pair, err := c.stream.Recv() if err != nil { - return []byte{}, nil, err + return nil, err } - return pair.K, pair.V, nil + return pair.V, nil } func (c *remoteCursor) seekBothExact(k, v []byte) ([]byte, []byte, error) { if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_SEEK_BOTH_EXACT, K: k, V: v}); err != nil { @@ -468,8 +468,8 @@ func (c *remoteCursor) firstDup() ([]byte, error) { } return pair.V, nil } -func (c *remoteCursor) lastDup(k []byte) ([]byte, error) { - if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_LAST_DUP, K: k}); err != nil { +func (c *remoteCursor) lastDup() ([]byte, error) { + if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_LAST_DUP}); err != nil { return nil, err } pair, err := c.stream.Recv() @@ -592,9 +592,9 @@ func (c *remoteCursorDupSort) SeekBothExact(key, value []byte) ([]byte, []byte, return c.seekBothExact(key, value) } -func (c *remoteCursorDupSort) SeekBothRange(key, value []byte) ([]byte, []byte, error) { +func (c *remoteCursorDupSort) SeekBothRange(key, value []byte) ([]byte, error) { if err := c.initCursor(); err != nil { - return []byte{}, nil, err + return nil, err } return c.getBothRange(key, value) } @@ -635,11 +635,11 @@ func (c *remoteCursorDupSort) PrevNoDup() ([]byte, []byte, error) { } return c.prevNoDup() } -func (c *remoteCursorDupSort) LastDup(k []byte) ([]byte, error) { +func (c *remoteCursorDupSort) LastDup() ([]byte, error) { if err := c.initCursor(); err != nil { return nil, err } - return c.lastDup(k) + return c.lastDup() } func (back *RemoteBackend) AddLocal(signedTx []byte) ([]byte, error) { diff --git a/ethdb/kv_snapshot.go b/ethdb/kv_snapshot.go index 296ea6132ca..c753a26f710 100644 --- a/ethdb/kv_snapshot.go +++ b/ethdb/kv_snapshot.go @@ -561,26 +561,22 @@ func (c *snCursor2Dup) SeekBothExact(key, value []byte) ([]byte, []byte, error) } -func (c *snCursor2Dup) SeekBothRange(key, value []byte) ([]byte, []byte, error) { - dbKey, dbVal, err := c.dbCursorDup.SeekBothRange(key, value) +func (c *snCursor2Dup) SeekBothRange(key, value []byte) ([]byte, error) { + dbVal, err := c.dbCursorDup.SeekBothRange(key, value) if err != nil { - return nil, nil, err + return nil, err } - snDBKey, snDBVal, err := c.sndbCursorDup.SeekBothRange(key, value) + snDBVal, err := c.sndbCursorDup.SeekBothRange(key, value) if err != nil { - return nil, nil, err + return nil, err } - //todo Is it correct comparison - cmp, br := common.KeyCmp(dbKey, snDBKey) - if br { - return nil, nil, nil + if dbVal == nil { + c.saveCurrent(key) + return dbVal, nil } - if cmp >= 0 { - c.saveCurrent(dbKey) - return dbKey, dbVal, nil - } - return snDBKey, snDBVal, nil + + return snDBVal, nil } func (c *snCursor2Dup) FirstDup() ([]byte, error) { @@ -595,7 +591,7 @@ func (c *snCursor2Dup) NextNoDup() ([]byte, []byte, error) { panic("implement me") } -func (c *snCursor2Dup) LastDup(k []byte) ([]byte, error) { +func (c *snCursor2Dup) LastDup() ([]byte, error) { panic("implement me") } diff --git a/ethdb/remote/remotedbserver/server.go b/ethdb/remote/remotedbserver/server.go index c2def02e453..dd92881c626 100644 --- a/ethdb/remote/remotedbserver/server.go +++ b/ethdb/remote/remotedbserver/server.go @@ -146,11 +146,11 @@ func (s *KvServer) Tx(stream remote.KV_TxServer) error { c.c = tx.Cursor(c.bucket) switch casted := c.c.(type) { case ethdb.CursorDupSort: - k, _, err := casted.SeekBothRange(c.k, c.v) + v, err := casted.SeekBothRange(c.k, c.v) if err != nil { return fmt.Errorf("server-side error: %w", err) } - if k == nil { // it may happen that key where we stopped disappeared after transaction reopen, then just move to next key + if v == nil { // it may happen that key where we stopped disappeared after transaction reopen, then just move to next key _, _, err = casted.Next() if err != nil { return fmt.Errorf("server-side error: %w", err) @@ -215,13 +215,13 @@ func handleOp(c ethdb.Cursor, stream remote.KV_TxServer, in *remote.Cursor) erro case remote.Op_SEEK: k, v, err = c.Seek(in.K) case remote.Op_SEEK_BOTH: - k, v, err = c.(ethdb.CursorDupSort).SeekBothRange(in.K, in.V) + v, err = c.(ethdb.CursorDupSort).SeekBothRange(in.K, in.V) case remote.Op_CURRENT: k, v, err = c.Current() case remote.Op_LAST: k, v, err = c.Last() case remote.Op_LAST_DUP: - v, err = c.(ethdb.CursorDupSort).LastDup(in.K) + v, err = c.(ethdb.CursorDupSort).LastDup() case remote.Op_NEXT: k, v, err = c.Next() case remote.Op_NEXT_DUP: diff --git a/migrations/dupsort_state_test.go b/migrations/dupsort_state_test.go index ca843bbd065..aea5d35a218 100644 --- a/migrations/dupsort_state_test.go +++ b/migrations/dupsort_state_test.go @@ -53,9 +53,8 @@ func TestDupSortHashState(t *testing.T) { require.NoError(err) keyLen := common.HashLength + common.IncarnationLength - k, v, err := c.SeekBothRange([]byte(storageKey)[:keyLen], []byte(storageKey)[keyLen:]) + v, err = c.SeekBothRange([]byte(storageKey)[:keyLen], []byte(storageKey)[keyLen:]) require.NoError(err) - require.Equal([]byte(storageKey)[:keyLen], k) require.Equal([]byte(storageKey)[keyLen:], v[:common.HashLength]) require.Equal([]byte{2}, v[common.HashLength:]) } @@ -109,9 +108,8 @@ func TestDupSortPlainState(t *testing.T) { require.Equal([]byte{1}, v) keyLen := common.AddressLength + common.IncarnationLength - k, v, err := c.SeekBothRange([]byte(storageKey)[:keyLen], []byte(storageKey)[keyLen:]) + v, err = c.SeekBothRange([]byte(storageKey)[:keyLen], []byte(storageKey)[keyLen:]) require.NoError(err) - require.Equal([]byte(storageKey)[:keyLen], k) require.Equal([]byte(storageKey)[keyLen:], v[:common.HashLength]) require.Equal([]byte{2}, v[common.HashLength:]) } diff --git a/turbo/trie/trie_root.go b/turbo/trie/trie_root.go index 820d685bc8f..8b13f55fa0d 100644 --- a/turbo/trie/trie_root.go +++ b/turbo/trie/trie_root.go @@ -261,7 +261,8 @@ func (l *FlatDBTrieLoader) CalcTrieRoot(db ethdb.Database, prefix []byte, quit < if storageTrie.skipState { goto SkipStorage } - for kS, vS, err3 := ss.SeekBothRange(accWithInc, storageTrie.FirstNotCoveredPrefix()); kS != nil; kS, vS, err3 = ss.NextDup() { + + for vS, err3 := ss.SeekBothRange(accWithInc, storageTrie.FirstNotCoveredPrefix()); vS != nil; _, vS, err3 = ss.NextDup() { if err3 != nil { return EmptyRoot, err3 } @@ -1736,7 +1737,8 @@ func (l *FlatDBTrieLoader) post(storages ethdb.CursorDupSort, ihStorage *Storage goto SkipStorage } i4++ - for kS, vS, err3 := storages.SeekBothRange(accWithInc, ihStorage.FirstNotCoveredPrefix()); kS != nil; kS, vS, err3 = storages.NextDup() { + + for vS, err3 := storages.SeekBothRange(accWithInc, ihStorage.FirstNotCoveredPrefix()); vS != nil; _, vS, err3 = storages.NextDup() { if err3 != nil { return false, err3 }