From e83cd70958e23cace05c9b4582f27cbf2fece2e1 Mon Sep 17 00:00:00 2001 From: Mark Holt <135143369+mh0lt@users.noreply.github.com> Date: Sat, 25 May 2024 05:28:09 +0300 Subject: [PATCH] add flag checking for pruning waypoints (#10468) This add a check for waypoint processing (checkpoints and milestones) to prune operations. It aims to fix: https://github.com/ledgerwatch/erigon/issues/10327 https://github.com/ledgerwatch/erigon/issues/10299 https://github.com/ledgerwatch/erigon/pull/10328 --- core/rawdb/accessors_chain.go | 112 ------------------------ core/rawdb/blockio/block_writer.go | 3 +- eth/stagedsync/stage_bor_heimdall.go | 83 +++++++++--------- polygon/bor/bordb/prune.go | 125 +++++++++++++++++++++++++++ polygon/bor/snaptype/types.go | 20 +++++ 5 files changed, 191 insertions(+), 152 deletions(-) create mode 100644 polygon/bor/bordb/prune.go diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 36b06feccd0..53f8e169329 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -21,7 +21,6 @@ import ( "context" "encoding/binary" "encoding/json" - "errors" "fmt" "math" "math/big" @@ -42,7 +41,6 @@ import ( "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/ethdb/cbor" - "github.com/ledgerwatch/erigon/polygon/heimdall" "github.com/ledgerwatch/erigon/rlp" ) @@ -1085,116 +1083,6 @@ func PruneBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error { return nil } -// PruneBorBlocks - delete [1, to) old blocks after moving it to snapshots. -// keeps genesis in db: [1, to) -// doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs -// doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty -func PruneBorBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int, SpanIdAt func(number uint64) uint64) error { - c, err := tx.Cursor(kv.BorEventNums) - if err != nil { - return err - } - defer c.Close() - var blockNumBytes [8]byte - binary.BigEndian.PutUint64(blockNumBytes[:], blockTo) - k, v, err := c.Seek(blockNumBytes[:]) - if err != nil { - return err - } - var eventIdTo uint64 = math.MaxUint64 - if k != nil { - eventIdTo = binary.BigEndian.Uint64(v) - } - c1, err := tx.RwCursor(kv.BorEvents) - if err != nil { - return err - } - defer c1.Close() - counter := blocksDeleteLimit - for k, _, err = c1.First(); err == nil && k != nil && counter > 0; k, _, err = c1.Next() { - eventId := binary.BigEndian.Uint64(k) - if eventId >= eventIdTo { - break - } - if err = c1.DeleteCurrent(); err != nil { - return err - } - counter-- - } - if err != nil { - return err - } - firstSpanToKeep := SpanIdAt(blockTo) - c2, err := tx.RwCursor(kv.BorSpans) - if err != nil { - return err - } - defer c2.Close() - counter = blocksDeleteLimit - for k, _, err := c2.First(); err == nil && k != nil && counter > 0; k, _, err = c2.Next() { - spanId := binary.BigEndian.Uint64(k) - if spanId >= firstSpanToKeep { - break - } - if err = c2.DeleteCurrent(); err != nil { - return err - } - counter-- - } - - checkpointCursor, err := tx.RwCursor(kv.BorCheckpoints) - if err != nil { - return err - } - - defer checkpointCursor.Close() - lastCheckpointToRemove, err := heimdall.CheckpointIdAt(tx, blockTo) - - if err != nil { - return err - } - - var checkpointIdBytes [8]byte - binary.BigEndian.PutUint64(checkpointIdBytes[:], uint64(lastCheckpointToRemove)) - for k, _, err := checkpointCursor.Seek(checkpointIdBytes[:]); err == nil && k != nil; k, _, err = checkpointCursor.Prev() { - if err = checkpointCursor.DeleteCurrent(); err != nil { - return err - } - } - - milestoneCursor, err := tx.RwCursor(kv.BorMilestones) - - if err != nil { - return err - } - - defer milestoneCursor.Close() - - var lastMilestoneToRemove heimdall.MilestoneId - - for blockCount := 1; err != nil && blockCount < blocksDeleteLimit; blockCount++ { - lastMilestoneToRemove, err = heimdall.MilestoneIdAt(tx, blockTo-uint64(blockCount)) - - if !errors.Is(err, heimdall.ErrMilestoneNotFound) { - return err - } else { - if blockCount == blocksDeleteLimit-1 { - return nil - } - } - } - - var milestoneIdBytes [8]byte - binary.BigEndian.PutUint64(milestoneIdBytes[:], uint64(lastMilestoneToRemove)) - for k, _, err := milestoneCursor.Seek(milestoneIdBytes[:]); err == nil && k != nil; k, _, err = milestoneCursor.Prev() { - if err = milestoneCursor.DeleteCurrent(); err != nil { - return err - } - } - - return nil -} - func TruncateCanonicalChain(ctx context.Context, db kv.RwTx, from uint64) error { return db.ForEach(kv.HeaderCanonical, hexutility.EncodeTs(from), func(k, _ []byte) error { return db.Delete(kv.HeaderCanonical, k) diff --git a/core/rawdb/blockio/block_writer.go b/core/rawdb/blockio/block_writer.go index 21151f0299c..ca2c8c1678d 100644 --- a/core/rawdb/blockio/block_writer.go +++ b/core/rawdb/blockio/block_writer.go @@ -16,6 +16,7 @@ import ( "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/rawdbv3" "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/polygon/bor/bordb" "github.com/ledgerwatch/log/v3" ) @@ -122,5 +123,5 @@ func (w *BlockWriter) PruneBlocks(ctx context.Context, tx kv.RwTx, blockTo uint6 // doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty func (w *BlockWriter) PruneBorBlocks(ctx context.Context, tx kv.RwTx, blockTo uint64, blocksDeleteLimit int, SpanIdAt func(number uint64) uint64) error { defer mxPruneTookBor.ObserveDuration(time.Now()) - return rawdb.PruneBorBlocks(tx, blockTo, blocksDeleteLimit, SpanIdAt) + return bordb.PruneBorBlocks(tx, blockTo, blocksDeleteLimit, SpanIdAt) } diff --git a/eth/stagedsync/stage_bor_heimdall.go b/eth/stagedsync/stage_bor_heimdall.go index 69d4eff0d2a..7e7631ac224 100644 --- a/eth/stagedsync/stage_bor_heimdall.go +++ b/eth/stagedsync/stage_bor_heimdall.go @@ -30,6 +30,7 @@ import ( "github.com/ledgerwatch/erigon/polygon/bor/borcfg" "github.com/ledgerwatch/erigon/polygon/bor/finality" "github.com/ledgerwatch/erigon/polygon/bor/finality/whitelist" + borsnaptype "github.com/ledgerwatch/erigon/polygon/bor/snaptype" "github.com/ledgerwatch/erigon/polygon/bor/valset" "github.com/ledgerwatch/erigon/polygon/heimdall" "github.com/ledgerwatch/erigon/polygon/sync" @@ -898,63 +899,67 @@ func BorHeimdallUnwind(u *UnwindState, ctx context.Context, _ *StageState, tx kv } // Removing checkpoints - if len(cfg.unwindTypes) == 0 || slices.Contains(cfg.unwindTypes, "checkpoints") { - checkpointCursor, err := tx.RwCursor(kv.BorCheckpoints) + if borsnaptype.CheckpointsEnabled() { + if len(cfg.unwindTypes) == 0 || slices.Contains(cfg.unwindTypes, "checkpoints") { + checkpointCursor, err := tx.RwCursor(kv.BorCheckpoints) - if err != nil { - return err - } - - defer checkpointCursor.Close() - lastCheckpointToKeep, err := heimdall.CheckpointIdAt(tx, u.UnwindPoint) - hasCheckpoints := true - - if err != nil { - if !errors.Is(err, heimdall.ErrCheckpointNotFound) { + if err != nil { return err } - hasCheckpoints = false - } + defer checkpointCursor.Close() + lastCheckpointToKeep, err := heimdall.CheckpointIdAt(tx, u.UnwindPoint) + hasCheckpoints := true - if hasCheckpoints { - var checkpointIdBytes [8]byte - binary.BigEndian.PutUint64(checkpointIdBytes[:], uint64(lastCheckpointToKeep+1)) - for k, _, err := checkpointCursor.Seek(checkpointIdBytes[:]); err == nil && k != nil; k, _, err = checkpointCursor.Next() { - if err = checkpointCursor.DeleteCurrent(); err != nil { + if err != nil { + if !errors.Is(err, heimdall.ErrCheckpointNotFound) { return err } - } - } - } - // Removing milestones - if len(cfg.unwindTypes) == 0 || slices.Contains(cfg.unwindTypes, "milestones") { - milestoneCursor, err := tx.RwCursor(kv.BorMilestones) + hasCheckpoints = false + } - if err != nil { - return err + if hasCheckpoints { + var checkpointIdBytes [8]byte + binary.BigEndian.PutUint64(checkpointIdBytes[:], uint64(lastCheckpointToKeep+1)) + for k, _, err := checkpointCursor.Seek(checkpointIdBytes[:]); err == nil && k != nil; k, _, err = checkpointCursor.Next() { + if err = checkpointCursor.DeleteCurrent(); err != nil { + return err + } + } + } } + } - defer milestoneCursor.Close() - lastMilestoneToKeep, err := heimdall.MilestoneIdAt(tx, u.UnwindPoint) - hasMilestones := true + if borsnaptype.MilestonesEnabled() { + // Removing milestones + if len(cfg.unwindTypes) == 0 || slices.Contains(cfg.unwindTypes, "milestones") { + milestoneCursor, err := tx.RwCursor(kv.BorMilestones) - if err != nil { - if !errors.Is(err, heimdall.ErrMilestoneNotFound) { + if err != nil { return err } - hasMilestones = false - } + defer milestoneCursor.Close() + lastMilestoneToKeep, err := heimdall.MilestoneIdAt(tx, u.UnwindPoint) + hasMilestones := true - if hasMilestones { - var milestoneIdBytes [8]byte - binary.BigEndian.PutUint64(milestoneIdBytes[:], uint64(lastMilestoneToKeep+1)) - for k, _, err := milestoneCursor.Seek(milestoneIdBytes[:]); err == nil && k != nil; k, _, err = milestoneCursor.Next() { - if err = milestoneCursor.DeleteCurrent(); err != nil { + if err != nil { + if !errors.Is(err, heimdall.ErrMilestoneNotFound) { return err } + + hasMilestones = false + } + + if hasMilestones { + var milestoneIdBytes [8]byte + binary.BigEndian.PutUint64(milestoneIdBytes[:], uint64(lastMilestoneToKeep+1)) + for k, _, err := milestoneCursor.Seek(milestoneIdBytes[:]); err == nil && k != nil; k, _, err = milestoneCursor.Next() { + if err = milestoneCursor.DeleteCurrent(); err != nil { + return err + } + } } } } diff --git a/polygon/bor/bordb/prune.go b/polygon/bor/bordb/prune.go new file mode 100644 index 00000000000..81c2f264038 --- /dev/null +++ b/polygon/bor/bordb/prune.go @@ -0,0 +1,125 @@ +package bordb + +import ( + "encoding/binary" + "errors" + "math" + + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/polygon/bor/snaptype" + "github.com/ledgerwatch/erigon/polygon/heimdall" +) + +// PruneBorBlocks - delete [1, to) old blocks after moving it to snapshots. +// keeps genesis in db: [1, to) +// doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs +// doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty +func PruneBorBlocks(tx kv.RwTx, blockTo uint64, blocksDeleteLimit int, SpanIdAt func(number uint64) uint64) error { + c, err := tx.Cursor(kv.BorEventNums) + if err != nil { + return err + } + defer c.Close() + var blockNumBytes [8]byte + binary.BigEndian.PutUint64(blockNumBytes[:], blockTo) + k, v, err := c.Seek(blockNumBytes[:]) + if err != nil { + return err + } + var eventIdTo uint64 = math.MaxUint64 + if k != nil { + eventIdTo = binary.BigEndian.Uint64(v) + } + c1, err := tx.RwCursor(kv.BorEvents) + if err != nil { + return err + } + defer c1.Close() + counter := blocksDeleteLimit + for k, _, err = c1.First(); err == nil && k != nil && counter > 0; k, _, err = c1.Next() { + eventId := binary.BigEndian.Uint64(k) + if eventId >= eventIdTo { + break + } + if err = c1.DeleteCurrent(); err != nil { + return err + } + counter-- + } + if err != nil { + return err + } + firstSpanToKeep := SpanIdAt(blockTo) + c2, err := tx.RwCursor(kv.BorSpans) + if err != nil { + return err + } + defer c2.Close() + counter = blocksDeleteLimit + for k, _, err := c2.First(); err == nil && k != nil && counter > 0; k, _, err = c2.Next() { + spanId := binary.BigEndian.Uint64(k) + if spanId >= firstSpanToKeep { + break + } + if err = c2.DeleteCurrent(); err != nil { + return err + } + counter-- + } + + if snaptype.CheckpointsEnabled() { + checkpointCursor, err := tx.RwCursor(kv.BorCheckpoints) + if err != nil { + return err + } + + defer checkpointCursor.Close() + lastCheckpointToRemove, err := heimdall.CheckpointIdAt(tx, blockTo) + + if err != nil { + return err + } + + var checkpointIdBytes [8]byte + binary.BigEndian.PutUint64(checkpointIdBytes[:], uint64(lastCheckpointToRemove)) + for k, _, err := checkpointCursor.Seek(checkpointIdBytes[:]); err == nil && k != nil; k, _, err = checkpointCursor.Prev() { + if err = checkpointCursor.DeleteCurrent(); err != nil { + return err + } + } + } + + if snaptype.MilestonesEnabled() { + milestoneCursor, err := tx.RwCursor(kv.BorMilestones) + + if err != nil { + return err + } + + defer milestoneCursor.Close() + + var lastMilestoneToRemove heimdall.MilestoneId + + for blockCount := 1; err != nil && blockCount < blocksDeleteLimit; blockCount++ { + lastMilestoneToRemove, err = heimdall.MilestoneIdAt(tx, blockTo-uint64(blockCount)) + + if !errors.Is(err, heimdall.ErrMilestoneNotFound) { + return err + } else { + if blockCount == blocksDeleteLimit-1 { + return nil + } + } + } + + var milestoneIdBytes [8]byte + binary.BigEndian.PutUint64(milestoneIdBytes[:], uint64(lastMilestoneToRemove)) + for k, _, err := milestoneCursor.Seek(milestoneIdBytes[:]); err == nil && k != nil; k, _, err = milestoneCursor.Prev() { + if err = milestoneCursor.DeleteCurrent(); err != nil { + return err + } + } + } + + return nil +} diff --git a/polygon/bor/snaptype/types.go b/polygon/bor/snaptype/types.go index c3abcde1a70..15617f521a6 100644 --- a/polygon/bor/snaptype/types.go +++ b/polygon/bor/snaptype/types.go @@ -423,6 +423,26 @@ func BorSnapshotTypes() []snaptype.Type { return []snaptype.Type{BorEvents, BorSpans} } +func CheckpointsEnabled() bool { + for _, snapType := range BorSnapshotTypes() { + if snapType.Enum() == BorCheckpoints.Enum() { + return true + } + } + + return false +} + +func MilestonesEnabled() bool { + for _, snapType := range BorSnapshotTypes() { + if snapType.Enum() == BorMilestones.Enum() { + return true + } + } + + return false +} + func extractValueRange(ctx context.Context, table string, valueFrom, valueTo uint64, db kv.RoDB, collect func([]byte) error, workers int, lvl log.Lvl, logger log.Logger) (uint64, error) { logEvery := time.NewTicker(20 * time.Second) defer logEvery.Stop()