Skip to content

Commit 4a9c60f

Browse files
dB2510rkapkaprestonvanloon
authored
Implement beacon db pruner (#14687)
* implement weak subjectivity pruner * fix goimports * add delete before slot method to database * add method to interface * update changelog * add flags * wire pruner * align pruner with backfill service * rename db method * fix imports * delete block slot indices * check for backfill and initial sync * add tests * fix imports * Update beacon-chain/db/kv/blocks.go Co-authored-by: Radosław Kapka <[email protected]> * Update cmd/beacon-chain/flags/base.go Co-authored-by: Preston Van Loon <[email protected]> * Update beacon-chain/db/pruner/pruner.go Co-authored-by: Radosław Kapka <[email protected]> * cleanup * fix buildkite * initialise atomic bool * delete data from remaining buckets * fix build * fix build * address review comments * add test for blockParentRootIndicesBucket * fix changelog * fix build * address kasey's comments * fix build * add trace span to blockRootsBySlotRange --------- Co-authored-by: Radosław Kapka <[email protected]> Co-authored-by: Preston Van Loon <[email protected]>
1 parent 9cf6b93 commit 4a9c60f

File tree

15 files changed

+776
-53
lines changed

15 files changed

+776
-53
lines changed

CHANGELOG.md

+40-40
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Notable features:
6060
- Updated the default `scrape-interval` in `Client-stats` to 2 minutes to accommodate Beaconcha.in API rate limits.
6161
- Switch to compounding when consolidating with source==target.
6262
- Revert block db save when saving state fails.
63-
- Return false from HasBlock if the block is being synced.
63+
- Return false from HasBlock if the block is being synced.
6464
- Cleanup forkchoice on failed insertions.
6565
- Use read only validator for core processing to avoid unnecessary copying.
6666
- Use ROBlock across block processing pipeline.
@@ -73,7 +73,7 @@ Notable features:
7373
- Simplified `EjectedValidatorIndices`.
7474
- `engine_newPayloadV4`,`engine_getPayloadV4` are changes due to new execution request serialization decisions, [PR](https://github.com/prysmaticlabs/prysm/pull/14580)
7575
- Fixed various small things in state-native code.
76-
- Use ROBlock earlier in block syncing pipeline.
76+
- Use ROBlock earlier in block syncing pipeline.
7777
- Changed the signature of `ProcessPayload`.
7878
- Only Build the Protobuf state once during serialization.
7979
- Capella blocks are execution.
@@ -139,9 +139,9 @@ Notable features:
139139

140140
### Security
141141

142-
## [v5.1.2](https://github.com/prysmaticlabs/prysm/compare/v5.1.1...v5.1.2) - 2024-10-16
142+
## [v5.1.2](https://github.com/prysmaticlabs/prysm/compare/v5.1.1...v5.1.2) - 2024-10-16
143143

144-
This is a hotfix release with one change.
144+
This is a hotfix release with one change.
145145

146146
Prysm v5.1.1 contains an updated implementation of the beacon api streaming events endpoint. This
147147
new implementation contains a bug that can cause a panic in certain conditions. The issue is
@@ -153,20 +153,20 @@ prysm REST mode validator (a feature which requires the validator to be configur
153153
api instead of prysm's stock grpc endpoints) or accessory software that connects to the events api,
154154
like https://github.com/ethpandaops/ethereum-metrics-exporter
155155

156-
### Fixed
156+
### Fixed
157157

158158
- Recover from panics when writing the event stream [#14545](https://github.com/prysmaticlabs/prysm/pull/14545)
159159

160160
## [v5.1.1](https://github.com/prysmaticlabs/prysm/compare/v5.1.0...v5.1.1) - 2024-10-15
161161

162-
This release has a number of features and improvements. Most notably, the feature flag
163-
`--enable-experimental-state` has been flipped to "opt out" via `--disable-experimental-state`.
162+
This release has a number of features and improvements. Most notably, the feature flag
163+
`--enable-experimental-state` has been flipped to "opt out" via `--disable-experimental-state`.
164164
The experimental state management design has shown significant improvements in memory usage at
165165
runtime. Updates to libp2p's gossipsub have some bandwidith stability improvements with support for
166-
IDONTWANT control messages.
166+
IDONTWANT control messages.
167167

168168
The gRPC gateway has been deprecated from Prysm in this release. If you need JSON data, consider the
169-
standardized beacon-APIs.
169+
standardized beacon-APIs.
170170

171171
Updating to this release is recommended at your convenience.
172172

@@ -208,7 +208,7 @@ Updating to this release is recommended at your convenience.
208208
- `grpc-gateway-corsdomain` is renamed to http-cors-domain. The old name can still be used as an alias.
209209
- `api-timeout` is changed from int flag to duration flag, default value updated.
210210
- Light client support: abstracted out the light client headers with different versions.
211-
- `ApplyToEveryValidator` has been changed to prevent misuse bugs, it takes a closure that takes a `ReadOnlyValidator` and returns a raw pointer to a `Validator`.
211+
- `ApplyToEveryValidator` has been changed to prevent misuse bugs, it takes a closure that takes a `ReadOnlyValidator` and returns a raw pointer to a `Validator`.
212212
- Removed gorilla mux library and replaced it with net/http updates in go 1.22.
213213
- Clean up `ProposeBlock` for validator client to reduce cognitive scoring and enable further changes.
214214
- Updated k8s-io/client-go to v0.30.4 and k8s-io/apimachinery to v0.30.4
@@ -219,7 +219,7 @@ Updating to this release is recommended at your convenience.
219219
- Updated Sepolia bootnodes.
220220
- Make committee aware packing the default by deprecating `--enable-committee-aware-packing`.
221221
- Moved `ConvertKzgCommitmentToVersionedHash` to the `primitives` package.
222-
- Updated correlation penalty for EIP-7251.
222+
- Updated correlation penalty for EIP-7251.
223223

224224
### Deprecated
225225
- `--disable-grpc-gateway` flag is deprecated due to grpc gateway removal.
@@ -693,34 +693,34 @@ AVX support (eg Celeron) after the Deneb fork. This is not an issue for mainnet.
693693

694694
- Linter: Wastedassign linter enabled to improve code quality.
695695
- API Enhancements:
696-
- Added payload return in Wei for /eth/v3/validator/blocks.
697-
- Added Holesky Deneb Epoch for better epoch management.
696+
- Added payload return in Wei for /eth/v3/validator/blocks.
697+
- Added Holesky Deneb Epoch for better epoch management.
698698
- Testing Enhancements:
699-
- Clear cache in tests of core helpers to ensure test reliability.
700-
- Added Debug State Transition Method for improved debugging.
701-
- Backfilling test: Enabled backfill in E2E tests for more comprehensive coverage.
699+
- Clear cache in tests of core helpers to ensure test reliability.
700+
- Added Debug State Transition Method for improved debugging.
701+
- Backfilling test: Enabled backfill in E2E tests for more comprehensive coverage.
702702
- API Updates: Re-enabled jwt on keymanager API for enhanced security.
703703
- Logging Improvements: Enhanced block by root log for better traceability.
704704
- Validator Client Improvements:
705-
- Added Spans to Core Validator Methods for enhanced monitoring.
706-
- Improved readability in validator client code for better maintenance (various commits).
705+
- Added Spans to Core Validator Methods for enhanced monitoring.
706+
- Improved readability in validator client code for better maintenance (various commits).
707707

708708
### Changed
709709

710710
- Optimizations and Refinements:
711-
- Lowered resource usage in certain processes for efficiency.
712-
- Moved blob rpc validation closer to peer read for optimized processing.
713-
- Cleaned up validate beacon block code for clarity and efficiency.
714-
- Updated Sepolia Deneb fork epoch for alignment with network changes.
715-
- Changed blob latency metrics to milliseconds for more precise measurement.
716-
- Altered getLegacyDatabaseLocation message for better clarity.
717-
- Improved wait for activation method for enhanced performance.
718-
- Capitalized Aggregated Unaggregated Attestations Log for consistency.
719-
- Modified HistoricalRoots usage for accuracy.
720-
- Adjusted checking of attribute emptiness for efficiency.
711+
- Lowered resource usage in certain processes for efficiency.
712+
- Moved blob rpc validation closer to peer read for optimized processing.
713+
- Cleaned up validate beacon block code for clarity and efficiency.
714+
- Updated Sepolia Deneb fork epoch for alignment with network changes.
715+
- Changed blob latency metrics to milliseconds for more precise measurement.
716+
- Altered getLegacyDatabaseLocation message for better clarity.
717+
- Improved wait for activation method for enhanced performance.
718+
- Capitalized Aggregated Unaggregated Attestations Log for consistency.
719+
- Modified HistoricalRoots usage for accuracy.
720+
- Adjusted checking of attribute emptiness for efficiency.
721721
- Database Management:
722-
- Moved --db-backup-output-dir as a deprecated flag for database management simplification.
723-
- Added the Ability to Defragment the Beacon State for improved database performance.
722+
- Moved --db-backup-output-dir as a deprecated flag for database management simplification.
723+
- Added the Ability to Defragment the Beacon State for improved database performance.
724724
- Dependency Update: Bumped quic-go version from 0.39.3 to 0.39.4 for up-to-date dependencies.
725725

726726
### Removed
@@ -731,12 +731,12 @@ AVX support (eg Celeron) after the Deneb fork. This is not an issue for mainnet.
731731
### Fixed
732732

733733
- Bug Fixes:
734-
- Fixed off by one error for improved accuracy.
735-
- Resolved small typo in error messages for clarity.
736-
- Addressed minor issue in blsToExecChange validator for better validation.
737-
- Corrected blobsidecar json tag for commitment inclusion proof.
738-
- Fixed ssz post-requests content type check.
739-
- Resolved issue with port logging in bootnode.
734+
- Fixed off by one error for improved accuracy.
735+
- Resolved small typo in error messages for clarity.
736+
- Addressed minor issue in blsToExecChange validator for better validation.
737+
- Corrected blobsidecar json tag for commitment inclusion proof.
738+
- Fixed ssz post-requests content type check.
739+
- Resolved issue with port logging in bootnode.
740740
- Test Fixes: Re-enabled Slasher E2E Test for more comprehensive testing.
741741

742742
### Security
@@ -1163,9 +1163,9 @@ No security issues in this release.
11631163
now features runtime detection, automatically enabling optimized code paths if your CPU supports it.
11641164
- **Multiarch Containers Preview Available**: multiarch (:wave: arm64 support :wave:) containers will be offered for
11651165
preview at the following locations:
1166-
- Beacon Chain: [gcr.io/prylabs-dev/prysm/beacon-chain:v4.1.0](gcr.io/prylabs-dev/prysm/beacon-chain:v4.1.0)
1167-
- Validator: [gcr.io/prylabs-dev/prysm/validator:v4.1.0](gcr.io/prylabs-dev/prysm/validator:v4.1.0)
1168-
- Please note that in the next cycle, we will exclusively use these containers at the canonical URLs.
1166+
- Beacon Chain: [gcr.io/prylabs-dev/prysm/beacon-chain:v4.1.0](gcr.io/prylabs-dev/prysm/beacon-chain:v4.1.0)
1167+
- Validator: [gcr.io/prylabs-dev/prysm/validator:v4.1.0](gcr.io/prylabs-dev/prysm/validator:v4.1.0)
1168+
- Please note that in the next cycle, we will exclusively use these containers at the canonical URLs.
11691169

11701170
### Added
11711171

@@ -2987,4 +2987,4 @@ There are no security updates in this release.
29872987

29882988
# Older than v2.0.0
29892989

2990-
For changelog history for releases older than v2.0.0, please refer to https://github.com/prysmaticlabs/prysm/releases
2990+
For changelog history for releases older than v2.0.0, please refer to https://github.com/prysmaticlabs/prysm/releases

beacon-chain/db/iface/interface.go

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ type NoHeadAccessDatabase interface {
101101
SaveLightClientBootstrap(ctx context.Context, blockRoot []byte, bootstrap interfaces.LightClientBootstrap) error
102102

103103
CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint primitives.Slot) error
104+
DeleteHistoricalDataBeforeSlot(ctx context.Context, slot primitives.Slot) error
104105
}
105106

106107
// HeadAccessDatabase defines a struct with access to reading chain head data.

beacon-chain/db/kv/blocks.go

+124-12
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,97 @@ func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
227227
return ErrDeleteJustifiedAndFinalized
228228
}
229229

230-
if err := tx.Bucket(blocksBucket).Delete(root[:]); err != nil {
231-
return err
232-
}
233-
if err := tx.Bucket(blockParentRootIndicesBucket).Delete(root[:]); err != nil {
230+
if err := s.deleteBlock(tx, root[:]); err != nil {
234231
return err
235232
}
236233
s.blockCache.Del(string(root[:]))
237234
return nil
238235
})
239236
}
240237

238+
// DeleteHistoricalDataBeforeSlot deletes all blocks and states before the given slot.
239+
// This function deletes data from the following buckets:
240+
// - blocksBucket
241+
// - blockParentRootIndicesBucket
242+
// - finalizedBlockRootsIndexBucket
243+
// - stateBucket
244+
// - stateSummaryBucket
245+
// - blockRootValidatorHashesBucket
246+
// - blockSlotIndicesBucket
247+
// - stateSlotIndicesBucket
248+
func (s *Store) DeleteHistoricalDataBeforeSlot(ctx context.Context, cutoffSlot primitives.Slot) error {
249+
ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteHistoricalDataBeforeSlot")
250+
defer span.End()
251+
252+
// Collect slot/root pairs to perform deletions in a separate read only transaction.
253+
var (
254+
roots [][]byte
255+
slts []primitives.Slot
256+
)
257+
err := s.db.View(func(tx *bolt.Tx) error {
258+
var err error
259+
roots, slts, err = blockRootsBySlotRange(ctx, tx.Bucket(blockSlotIndicesBucket), primitives.Slot(0), cutoffSlot, nil, nil, nil)
260+
if err != nil {
261+
return errors.Wrap(err, "could not retrieve block roots")
262+
}
263+
return nil
264+
})
265+
if err != nil {
266+
return errors.Wrap(err, "could not retrieve block roots and slots")
267+
}
268+
269+
// Perform all deletions in a single transaction for atomicity
270+
return s.db.Update(func(tx *bolt.Tx) error {
271+
for _, root := range roots {
272+
// Delete block
273+
if err = s.deleteBlock(tx, root); err != nil {
274+
return err
275+
}
276+
277+
// Delete finalized block roots index
278+
if err = tx.Bucket(finalizedBlockRootsIndexBucket).Delete(root); err != nil {
279+
return errors.Wrap(err, "could not delete finalized block root index")
280+
}
281+
282+
// Delete state
283+
if err = tx.Bucket(stateBucket).Delete(root); err != nil {
284+
return errors.Wrap(err, "could not delete state")
285+
}
286+
287+
// Delete state summary
288+
if err = tx.Bucket(stateSummaryBucket).Delete(root); err != nil {
289+
return errors.Wrap(err, "could not delete state summary")
290+
}
291+
292+
// Delete validator entries
293+
if err = s.deleteValidatorHashes(tx, root); err != nil {
294+
return errors.Wrap(err, "could not delete validators")
295+
}
296+
}
297+
298+
for _, slot := range slts {
299+
// Delete slot indices
300+
if err = tx.Bucket(blockSlotIndicesBucket).Delete(bytesutil.SlotToBytesBigEndian(slot)); err != nil {
301+
return errors.Wrap(err, "could not delete block slot index")
302+
}
303+
if err = tx.Bucket(stateSlotIndicesBucket).Delete(bytesutil.SlotToBytesBigEndian(slot)); err != nil {
304+
return errors.Wrap(err, "could not delete state slot index")
305+
}
306+
}
307+
308+
// Delete all caches after we have deleted everything from buckets.
309+
// This is done after the buckets are deleted to avoid any issues in case of transaction rollback.
310+
for _, root := range roots {
311+
// Delete block from cache
312+
s.blockCache.Del(string(root))
313+
// Delete state summary from cache
314+
s.stateSummaryCache.delete([32]byte(root))
315+
}
316+
317+
return nil
318+
})
319+
}
320+
241321
// SaveBlock to the db.
242322
func (s *Store) SaveBlock(ctx context.Context, signed interfaces.ReadOnlySignedBeaconBlock) error {
243323
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveBlock")
@@ -609,7 +689,7 @@ func blockRootsByFilter(ctx context.Context, tx *bolt.Tx, f *filters.QueryFilter
609689

610690
// We retrieve block roots that match a filter criteria of slot ranges, if specified.
611691
filtersMap := f.Filters()
612-
rootsBySlotRange, err := blockRootsBySlotRange(
692+
rootsBySlotRange, _, err := blockRootsBySlotRange(
613693
ctx,
614694
tx.Bucket(blockSlotIndicesBucket),
615695
filtersMap[filters.StartSlot],
@@ -627,6 +707,7 @@ func blockRootsByFilter(ctx context.Context, tx *bolt.Tx, f *filters.QueryFilter
627707
// that list of roots to lookup the block. These block will
628708
// meet the filter criteria.
629709
indices := lookupValuesForIndices(ctx, indicesByBucket, tx)
710+
630711
keys := rootsBySlotRange
631712
if len(indices) > 0 {
632713
// If we have found indices that meet the filter criteria, and there are also
@@ -653,13 +734,13 @@ func blockRootsBySlotRange(
653734
ctx context.Context,
654735
bkt *bolt.Bucket,
655736
startSlotEncoded, endSlotEncoded, startEpochEncoded, endEpochEncoded, slotStepEncoded interface{},
656-
) ([][]byte, error) {
737+
) ([][]byte, []primitives.Slot, error) {
657738
_, span := trace.StartSpan(ctx, "BeaconDB.blockRootsBySlotRange")
658739
defer span.End()
659740

660741
// Return nothing when all slot parameters are missing
661742
if startSlotEncoded == nil && endSlotEncoded == nil && startEpochEncoded == nil && endEpochEncoded == nil {
662-
return [][]byte{}, nil
743+
return [][]byte{}, nil, nil
663744
}
664745

665746
var startSlot, endSlot primitives.Slot
@@ -680,11 +761,11 @@ func blockRootsBySlotRange(
680761
if startEpochOk && endEpochOk {
681762
startSlot, err = slots.EpochStart(startEpoch)
682763
if err != nil {
683-
return nil, err
764+
return nil, nil, err
684765
}
685766
endSlot, err = slots.EpochStart(endEpoch)
686767
if err != nil {
687-
return nil, err
768+
return nil, nil, err
688769
}
689770
endSlot = endSlot + params.BeaconConfig().SlotsPerEpoch - 1
690771
}
@@ -695,14 +776,15 @@ func blockRootsBySlotRange(
695776
return key != nil && bytes.Compare(key, max) <= 0
696777
}
697778
if endSlot < startSlot {
698-
return nil, errInvalidSlotRange
779+
return nil, nil, errInvalidSlotRange
699780
}
700781
rootsRange := endSlot.SubSlot(startSlot).Div(step)
701782
roots := make([][]byte, 0, rootsRange)
783+
var slts []primitives.Slot
702784
c := bkt.Cursor()
703785
for k, v := c.Seek(min); conditional(k, max); k, v = c.Next() {
786+
slot := bytesutil.BytesToSlotBigEndian(k)
704787
if step > 1 {
705-
slot := bytesutil.BytesToSlotBigEndian(k)
706788
if slot.SubSlot(startSlot).Mod(step) != 0 {
707789
continue
708790
}
@@ -713,8 +795,9 @@ func blockRootsBySlotRange(
713795
splitRoots = append(splitRoots, v[i:i+32])
714796
}
715797
roots = append(roots, splitRoots...)
798+
slts = append(slts, slot)
716799
}
717-
return roots, nil
800+
return roots, slts, nil
718801
}
719802

720803
// blockRootsBySlot retrieves the block roots by slot
@@ -908,3 +991,32 @@ func keyForBlock(blk interfaces.ReadOnlySignedBeaconBlock) ([]byte, error) {
908991

909992
return nil, fmt.Errorf("unsupported block version: %v", blk.Version())
910993
}
994+
995+
func (s *Store) deleteBlock(tx *bolt.Tx, root []byte) error {
996+
if err := tx.Bucket(blocksBucket).Delete(root); err != nil {
997+
return errors.Wrap(err, "could not delete block")
998+
}
999+
1000+
if err := tx.Bucket(blockParentRootIndicesBucket).Delete(root); err != nil {
1001+
return errors.Wrap(err, "could not delete block parent indices")
1002+
}
1003+
1004+
return nil
1005+
}
1006+
1007+
func (s *Store) deleteValidatorHashes(tx *bolt.Tx, root []byte) error {
1008+
ok, err := s.isStateValidatorMigrationOver()
1009+
if err != nil {
1010+
return err
1011+
}
1012+
if !ok {
1013+
return nil
1014+
}
1015+
1016+
// Delete the validator hash index
1017+
if err = tx.Bucket(blockRootValidatorHashesBucket).Delete(root); err != nil {
1018+
return errors.Wrap(err, "could not delete validator index")
1019+
}
1020+
1021+
return nil
1022+
}

0 commit comments

Comments
 (0)