From 6e0b0e0dbd84dc07681cb2fdf3c7a5696b114c42 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Tue, 17 Dec 2024 19:24:47 +0530 Subject: [PATCH 1/4] Store last message pruned in database --- arbnode/message_pruner.go | 50 +++++++++++++++++++++++++++++++++++---- arbnode/schema.go | 12 ++++++---- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/arbnode/message_pruner.go b/arbnode/message_pruner.go index 840a15f328..c86b88f2d0 100644 --- a/arbnode/message_pruner.go +++ b/arbnode/message_pruner.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/util/stopwaiter" @@ -121,7 +122,7 @@ func (m *MessagePruner) prune(ctx context.Context, count arbutil.MessageIndex, g } func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCount arbutil.MessageIndex, delayedMessageCount uint64) error { - prunedKeysRange, err := deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messageResultPrefix, &m.cachedPrunedMessageResult, uint64(messageCount)) + prunedKeysRange, err := deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messageResultPrefix, lastPrunedMessageResultKey, &m.cachedPrunedMessageResult, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting message results: %w", err) } @@ -129,7 +130,7 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun log.Info("Pruned message results:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, blockHashInputFeedPrefix, &m.cachedPrunedBlockHashesInputFeed, uint64(messageCount)) + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, blockHashInputFeedPrefix, lastPrunedBlockHashInputFeedKey, &m.cachedPrunedBlockHashesInputFeed, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting expected block hashes: %w", err) } @@ -137,7 +138,7 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun log.Info("Pruned expected block hashes:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messagePrefix, &m.cachedPrunedMessages, uint64(messageCount)) + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messagePrefix, lastPrunedMessageKey, &m.cachedPrunedMessages, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting last batch messages: %w", err) } @@ -145,7 +146,7 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun log.Info("Pruned last batch messages:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.inboxTracker.db, rlpDelayedMessagePrefix, &m.cachedPrunedDelayedMessages, delayedMessageCount) + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.inboxTracker.db, rlpDelayedMessagePrefix, lastPrunedRlpDelayedMessageKey, &m.cachedPrunedDelayedMessages, delayedMessageCount) if err != nil { return fmt.Errorf("error deleting last batch delayed messages: %w", err) } @@ -157,8 +158,12 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun // deleteFromLastPrunedUptoEndKey is similar to deleteFromRange but automatically populates the start key // cachedStartMinKey must not be nil. It's set to the new start key at the end of this function if successful. -func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, prefix []byte, cachedStartMinKey *uint64, endMinKey uint64) ([]uint64, error) { +// Checks if the last pruned key is set in the database and uses it as the start key if it is. +func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, prefix []byte, lastPrunedKey []byte, cachedStartMinKey *uint64, endMinKey uint64) ([]uint64, error) { startMinKey := *cachedStartMinKey + if startMinKey == 0 { + startMinKey = fetchLastPrunedKey(db, lastPrunedKey) + } if startMinKey == 0 { startIter := db.NewIterator(prefix, uint64ToKey(1)) if !startIter.Next() { @@ -169,11 +174,46 @@ func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, pref } if endMinKey <= startMinKey { *cachedStartMinKey = startMinKey + insertLastPrunedKey(db, lastPrunedKey, startMinKey) return nil, nil } keys, err := deleteFromRange(ctx, db, prefix, startMinKey, endMinKey-1) if err == nil { *cachedStartMinKey = endMinKey - 1 + insertLastPrunedKey(db, lastPrunedKey, endMinKey-1) } return keys, err } + +func insertLastPrunedKey(db ethdb.Database, lastPrunedKey []byte, lastPrunedValue uint64) { + lastPrunedValueByte, err := rlp.EncodeToBytes(lastPrunedValue) + if err != nil { + log.Error("error encoding last pruned value: %w", err) + } else { + err = db.Put(lastPrunedKey, lastPrunedValueByte) + if err != nil { + log.Error("error saving last pruned value: %w", err) + } + } +} + +func fetchLastPrunedKey(db ethdb.Database, lastPrunedKey []byte) uint64 { + hasKey, err := db.Has(lastPrunedKey) + if err != nil { + log.Warn("error checking for last pruned key: %w", err) + } else if hasKey { + lastPrunedValueByte, err := db.Get(lastPrunedKey) + if err != nil { + log.Warn("error fetching last pruned key: %w", err) + } else { + var lastPrunedValue uint64 + err = rlp.DecodeBytes(lastPrunedValueByte, &lastPrunedValue) + if err != nil { + log.Warn("error decoding last pruned value: %w", err) + } else { + return lastPrunedValue + } + } + } + return 0 +} diff --git a/arbnode/schema.go b/arbnode/schema.go index 1aaded2b95..e06d6a75c7 100644 --- a/arbnode/schema.go +++ b/arbnode/schema.go @@ -13,10 +13,14 @@ var ( sequencerBatchMetaPrefix []byte = []byte("s") // maps a batch sequence number to BatchMetadata delayedSequencedPrefix []byte = []byte("a") // maps a delayed message count to the first sequencer batch sequence number with this delayed count - messageCountKey []byte = []byte("_messageCount") // contains the current message count - delayedMessageCountKey []byte = []byte("_delayedMessageCount") // contains the current delayed message count - sequencerBatchCountKey []byte = []byte("_sequencerBatchCount") // contains the current sequencer message count - dbSchemaVersion []byte = []byte("_schemaVersion") // contains a uint64 representing the database schema version + messageCountKey []byte = []byte("_messageCount") // contains the current message count + lastPrunedMessageResultKey []byte = []byte("_lastPrunedMessageResultKey") // contains the last pruned message result key + lastPrunedBlockHashInputFeedKey []byte = []byte("_lastPrunedBlockHashInputFeedPrefix") // contains the last pruned block hash input feed key + lastPrunedMessageKey []byte = []byte("_lastPrunedMessageKey") // contains the last pruned message key + lastPrunedRlpDelayedMessageKey []byte = []byte("_lastPrunedRlpDelayedMessageKey") // contains the last pruned RLP delayed message key + delayedMessageCountKey []byte = []byte("_delayedMessageCount") // contains the current delayed message count + sequencerBatchCountKey []byte = []byte("_sequencerBatchCount") // contains the current sequencer message count + dbSchemaVersion []byte = []byte("_schemaVersion") // contains a uint64 representing the database schema version ) const currentDbSchemaVersion uint64 = 1 From 693c4066100689aaefee081b3f9a1e0c4175bdb8 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Thu, 2 Jan 2025 20:32:20 +0530 Subject: [PATCH 2/4] Changes based on PR comments --- arbnode/message_pruner.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arbnode/message_pruner.go b/arbnode/message_pruner.go index 5cdd1128d0..3805bd8637 100644 --- a/arbnode/message_pruner.go +++ b/arbnode/message_pruner.go @@ -201,19 +201,21 @@ func fetchLastPrunedKey(db ethdb.Database, lastPrunedKey []byte) uint64 { hasKey, err := db.Has(lastPrunedKey) if err != nil { log.Warn("error checking for last pruned key: %w", err) - } else if hasKey { - lastPrunedValueByte, err := db.Get(lastPrunedKey) - if err != nil { - log.Warn("error fetching last pruned key: %w", err) - } else { - var lastPrunedValue uint64 - err = rlp.DecodeBytes(lastPrunedValueByte, &lastPrunedValue) - if err != nil { - log.Warn("error decoding last pruned value: %w", err) - } else { - return lastPrunedValue - } - } + return 0 + } + if !hasKey { + return 0 + } + lastPrunedValueByte, err := db.Get(lastPrunedKey) + if err != nil { + log.Warn("error fetching last pruned key: %w", err) + return 0 + } + var lastPrunedValue uint64 + err = rlp.DecodeBytes(lastPrunedValueByte, &lastPrunedValue) + if err != nil { + log.Warn("error decoding last pruned value: %w", err) + return 0 } - return 0 + return lastPrunedValue } From 669c5ef052d76ac264c0ba3fed0eeb4717db1a9a Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Thu, 2 Jan 2025 21:01:43 +0530 Subject: [PATCH 3/4] Changes based on PR comments --- arbnode/message_pruner.go | 46 ++++++++++++++++++++++----------------- arbnode/schema.go | 14 +++++------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/arbnode/message_pruner.go b/arbnode/message_pruner.go index 3805bd8637..b18796a4c5 100644 --- a/arbnode/message_pruner.go +++ b/arbnode/message_pruner.go @@ -24,15 +24,13 @@ import ( type MessagePruner struct { stopwaiter.StopWaiter - transactionStreamer *TransactionStreamer - inboxTracker *InboxTracker - config MessagePrunerConfigFetcher - pruningLock sync.Mutex - lastPruneDone time.Time - cachedPrunedMessages uint64 - cachedPrunedBlockHashesInputFeed uint64 - cachedPrunedMessageResult uint64 - cachedPrunedDelayedMessages uint64 + transactionStreamer *TransactionStreamer + inboxTracker *InboxTracker + config MessagePrunerConfigFetcher + pruningLock sync.Mutex + lastPruneDone time.Time + cachedPrunedMessages uint64 + cachedPrunedDelayedMessages uint64 } type MessagePrunerConfig struct { @@ -122,7 +120,14 @@ func (m *MessagePruner) prune(ctx context.Context, count arbutil.MessageIndex, g } func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCount arbutil.MessageIndex, delayedMessageCount uint64) error { - prunedKeysRange, err := deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messageResultPrefix, lastPrunedMessageResultKey, &m.cachedPrunedMessageResult, uint64(messageCount)) + if m.cachedPrunedMessages == 0 { + m.cachedPrunedMessages = fetchLastPrunedKey(m.transactionStreamer.db, lastPrunedMessageKey) + } + if m.cachedPrunedDelayedMessages == 0 { + m.cachedPrunedDelayedMessages = fetchLastPrunedKey(m.inboxTracker.db, lastPrunedDelayedMessageKey) + } + lastPrunedMessage := m.cachedPrunedMessages + prunedKeysRange, err := deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messageResultPrefix, &lastPrunedMessage, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting message results: %w", err) } @@ -130,7 +135,8 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun log.Info("Pruned message results:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, blockHashInputFeedPrefix, lastPrunedBlockHashInputFeedKey, &m.cachedPrunedBlockHashesInputFeed, uint64(messageCount)) + lastPrunedMessage = m.cachedPrunedMessages + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, blockHashInputFeedPrefix, &lastPrunedMessage, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting expected block hashes: %w", err) } @@ -138,32 +144,34 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun log.Info("Pruned expected block hashes:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messagePrefix, lastPrunedMessageKey, &m.cachedPrunedMessages, uint64(messageCount)) + lastPrunedMessage = m.cachedPrunedMessages + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messagePrefix, &lastPrunedMessage, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting last batch messages: %w", err) } if len(prunedKeysRange) > 0 { log.Info("Pruned last batch messages:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } + insertLastPrunedKey(m.transactionStreamer.db, lastPrunedMessageKey, lastPrunedMessage) + m.cachedPrunedMessages = lastPrunedMessage - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.inboxTracker.db, rlpDelayedMessagePrefix, lastPrunedRlpDelayedMessageKey, &m.cachedPrunedDelayedMessages, delayedMessageCount) + lastPrunedDelayedMessage := m.cachedPrunedDelayedMessages + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.inboxTracker.db, rlpDelayedMessagePrefix, &lastPrunedDelayedMessage, delayedMessageCount) if err != nil { return fmt.Errorf("error deleting last batch delayed messages: %w", err) } if len(prunedKeysRange) > 0 { log.Info("Pruned last batch delayed messages:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } + insertLastPrunedKey(m.inboxTracker.db, lastPrunedDelayedMessageKey, lastPrunedMessage) + m.cachedPrunedDelayedMessages = lastPrunedDelayedMessage return nil } // deleteFromLastPrunedUptoEndKey is similar to deleteFromRange but automatically populates the start key // cachedStartMinKey must not be nil. It's set to the new start key at the end of this function if successful. -// Checks if the last pruned key is set in the database and uses it as the start key if it is. -func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, prefix []byte, lastPrunedKey []byte, cachedStartMinKey *uint64, endMinKey uint64) ([]uint64, error) { +func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, prefix []byte, cachedStartMinKey *uint64, endMinKey uint64) ([]uint64, error) { startMinKey := *cachedStartMinKey - if startMinKey == 0 { - startMinKey = fetchLastPrunedKey(db, lastPrunedKey) - } if startMinKey == 0 { startIter := db.NewIterator(prefix, uint64ToKey(1)) if !startIter.Next() { @@ -174,13 +182,11 @@ func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, pref } if endMinKey <= startMinKey { *cachedStartMinKey = startMinKey - insertLastPrunedKey(db, lastPrunedKey, startMinKey) return nil, nil } keys, err := deleteFromRange(ctx, db, prefix, startMinKey, endMinKey-1) if err == nil { *cachedStartMinKey = endMinKey - 1 - insertLastPrunedKey(db, lastPrunedKey, endMinKey-1) } return keys, err } diff --git a/arbnode/schema.go b/arbnode/schema.go index e06d6a75c7..88a31ce90a 100644 --- a/arbnode/schema.go +++ b/arbnode/schema.go @@ -13,14 +13,12 @@ var ( sequencerBatchMetaPrefix []byte = []byte("s") // maps a batch sequence number to BatchMetadata delayedSequencedPrefix []byte = []byte("a") // maps a delayed message count to the first sequencer batch sequence number with this delayed count - messageCountKey []byte = []byte("_messageCount") // contains the current message count - lastPrunedMessageResultKey []byte = []byte("_lastPrunedMessageResultKey") // contains the last pruned message result key - lastPrunedBlockHashInputFeedKey []byte = []byte("_lastPrunedBlockHashInputFeedPrefix") // contains the last pruned block hash input feed key - lastPrunedMessageKey []byte = []byte("_lastPrunedMessageKey") // contains the last pruned message key - lastPrunedRlpDelayedMessageKey []byte = []byte("_lastPrunedRlpDelayedMessageKey") // contains the last pruned RLP delayed message key - delayedMessageCountKey []byte = []byte("_delayedMessageCount") // contains the current delayed message count - sequencerBatchCountKey []byte = []byte("_sequencerBatchCount") // contains the current sequencer message count - dbSchemaVersion []byte = []byte("_schemaVersion") // contains a uint64 representing the database schema version + messageCountKey []byte = []byte("_messageCount") // contains the current message count + lastPrunedMessageKey []byte = []byte("_lastPrunedMessageKey") // contains the last pruned message key + lastPrunedDelayedMessageKey []byte = []byte("_lastPrunedDelayedMessageKey") // contains the last pruned RLP delayed message key + delayedMessageCountKey []byte = []byte("_delayedMessageCount") // contains the current delayed message count + sequencerBatchCountKey []byte = []byte("_sequencerBatchCount") // contains the current sequencer message count + dbSchemaVersion []byte = []byte("_schemaVersion") // contains a uint64 representing the database schema version ) const currentDbSchemaVersion uint64 = 1 From 7200ff5f706693e026e3c70dcee73f640cb718b5 Mon Sep 17 00:00:00 2001 From: Aman Sanghi Date: Fri, 3 Jan 2025 18:05:45 +0530 Subject: [PATCH 4/4] Changes based on PR comments --- arbnode/message_pruner.go | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/arbnode/message_pruner.go b/arbnode/message_pruner.go index b18796a4c5..dedc579a01 100644 --- a/arbnode/message_pruner.go +++ b/arbnode/message_pruner.go @@ -126,8 +126,7 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun if m.cachedPrunedDelayedMessages == 0 { m.cachedPrunedDelayedMessages = fetchLastPrunedKey(m.inboxTracker.db, lastPrunedDelayedMessageKey) } - lastPrunedMessage := m.cachedPrunedMessages - prunedKeysRange, err := deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messageResultPrefix, &lastPrunedMessage, uint64(messageCount)) + prunedKeysRange, _, err := deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messageResultPrefix, m.cachedPrunedMessages, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting message results: %w", err) } @@ -135,8 +134,7 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun log.Info("Pruned message results:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - lastPrunedMessage = m.cachedPrunedMessages - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, blockHashInputFeedPrefix, &lastPrunedMessage, uint64(messageCount)) + prunedKeysRange, _, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, blockHashInputFeedPrefix, m.cachedPrunedMessages, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting expected block hashes: %w", err) } @@ -144,8 +142,7 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun log.Info("Pruned expected block hashes:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - lastPrunedMessage = m.cachedPrunedMessages - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messagePrefix, &lastPrunedMessage, uint64(messageCount)) + prunedKeysRange, lastPrunedMessage, err := deleteFromLastPrunedUptoEndKey(ctx, m.transactionStreamer.db, messagePrefix, m.cachedPrunedMessages, uint64(messageCount)) if err != nil { return fmt.Errorf("error deleting last batch messages: %w", err) } @@ -155,40 +152,34 @@ func (m *MessagePruner) deleteOldMessagesFromDB(ctx context.Context, messageCoun insertLastPrunedKey(m.transactionStreamer.db, lastPrunedMessageKey, lastPrunedMessage) m.cachedPrunedMessages = lastPrunedMessage - lastPrunedDelayedMessage := m.cachedPrunedDelayedMessages - prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(ctx, m.inboxTracker.db, rlpDelayedMessagePrefix, &lastPrunedDelayedMessage, delayedMessageCount) + prunedKeysRange, lastPrunedDelayedMessage, err := deleteFromLastPrunedUptoEndKey(ctx, m.inboxTracker.db, rlpDelayedMessagePrefix, m.cachedPrunedDelayedMessages, delayedMessageCount) if err != nil { return fmt.Errorf("error deleting last batch delayed messages: %w", err) } if len(prunedKeysRange) > 0 { log.Info("Pruned last batch delayed messages:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) } - insertLastPrunedKey(m.inboxTracker.db, lastPrunedDelayedMessageKey, lastPrunedMessage) + insertLastPrunedKey(m.inboxTracker.db, lastPrunedDelayedMessageKey, lastPrunedDelayedMessage) m.cachedPrunedDelayedMessages = lastPrunedDelayedMessage return nil } -// deleteFromLastPrunedUptoEndKey is similar to deleteFromRange but automatically populates the start key -// cachedStartMinKey must not be nil. It's set to the new start key at the end of this function if successful. -func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, prefix []byte, cachedStartMinKey *uint64, endMinKey uint64) ([]uint64, error) { - startMinKey := *cachedStartMinKey +// deleteFromLastPrunedUptoEndKey is similar to deleteFromRange but automatically populates the start key if it's not set. +// It's returns the new start key (i.e. last pruned key) at the end of this function if successful. +func deleteFromLastPrunedUptoEndKey(ctx context.Context, db ethdb.Database, prefix []byte, startMinKey uint64, endMinKey uint64) ([]uint64, uint64, error) { if startMinKey == 0 { startIter := db.NewIterator(prefix, uint64ToKey(1)) if !startIter.Next() { - return nil, nil + return nil, 0, nil } startMinKey = binary.BigEndian.Uint64(bytes.TrimPrefix(startIter.Key(), prefix)) startIter.Release() } if endMinKey <= startMinKey { - *cachedStartMinKey = startMinKey - return nil, nil + return nil, startMinKey, nil } keys, err := deleteFromRange(ctx, db, prefix, startMinKey, endMinKey-1) - if err == nil { - *cachedStartMinKey = endMinKey - 1 - } - return keys, err + return keys, endMinKey - 1, err } func insertLastPrunedKey(db ethdb.Database, lastPrunedKey []byte, lastPrunedValue uint64) {