From 3fc83143a03c4da50b1452696da2ab3421aa8343 Mon Sep 17 00:00:00 2001 From: syjn99 Date: Mon, 27 Jan 2025 13:53:04 +0900 Subject: [PATCH 01/12] Add metrics for pruned proofs & pending deposits --- .../cache/depositsnapshot/deposit_fetcher.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go index e7b9f089ad3e..725ed0d2ec36 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go +++ b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go @@ -21,6 +21,14 @@ var ( Name: "beacondb_pending_deposits_eip4881", Help: "The number of pending deposits in memory", }) + prunedProofsCount = promauto.NewGauge(prometheus.GaugeOpts{ + Name: "beacondb_pruned_proofs_eip4881", + Help: "The number of pruned proofs", + }) + prunedPendingDepositsCount = promauto.NewGauge(prometheus.GaugeOpts{ + Name: "beacondb_pruned_pending_deposits_eip4881", + Help: "The number of pruned pending deposits", + }) ) // Cache stores all in-memory deposit objects. This @@ -195,6 +203,7 @@ func (c *Cache) PruneProofs(ctx context.Context, untilDepositIndex int64) error break } c.deposits[i].Deposit.Proof = nil + prunedProofsCount.Inc() } return nil @@ -220,6 +229,10 @@ func (c *Cache) PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) } } + // Add pruned count to prom metric + prunedCount := len(c.pendingDeposits) - len(cleanDeposits) + prunedPendingDepositsCount.Add(float64(prunedCount)) + c.pendingDeposits = cleanDeposits pendingDepositsCount.Set(float64(len(c.pendingDeposits))) } From c53ad3e936fedb54ca846a0865726c9b9804495a Mon Sep 17 00:00:00 2001 From: syjn99 Date: Mon, 27 Jan 2025 14:03:26 +0900 Subject: [PATCH 02/12] Add PruneAllProofs & PruneAllPendingDeposits --- .../cache/depositsnapshot/deposit_fetcher.go | 38 +++++++++++++++++++ beacon-chain/cache/interfaces.go | 2 + 2 files changed, 40 insertions(+) diff --git a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go index 725ed0d2ec36..2b758c8e49f9 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go +++ b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go @@ -209,6 +209,26 @@ func (c *Cache) PruneProofs(ctx context.Context, untilDepositIndex int64) error return nil } +// PruneAllProofs removes proofs from all deposits. +// As EIP-6110 applies and the legacy deposit mechanism is deprecated, +// proofs in deposit snapshot are no longer needed. +// See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation +func (c *Cache) PruneAllProofs(ctx context.Context) { + _, span := trace.StartSpan(ctx, "Cache.PruneAllProofs") + defer span.End() + + c.depositsLock.Lock() + defer c.depositsLock.Unlock() + + for i := len(c.deposits) - 1; i >= 0; i-- { + if c.deposits[i].Deposit.Proof == nil { + break + } + c.deposits[i].Deposit.Proof = nil + prunedProofsCount.Inc() + } +} + // PrunePendingDeposits removes any deposit which is older than the given deposit merkle tree index. func (c *Cache) PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) { _, span := trace.StartSpan(ctx, "Cache.PrunePendingDeposits") @@ -237,6 +257,24 @@ func (c *Cache) PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) pendingDepositsCount.Set(float64(len(c.pendingDeposits))) } +// PruneAllPendingDeposits removes all pending deposits from the cache. +// As EIP-6110 applies and the legacy deposit mechanism is deprecated, +// pending deposits in deposit snapshot are no longer needed. +// See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation +func (c *Cache) PruneAllPendingDeposits(ctx context.Context) { + _, span := trace.StartSpan(ctx, "Cache.PruneAllPendingDeposits") + defer span.End() + + c.depositsLock.Lock() + defer c.depositsLock.Unlock() + + prunedCount := len(c.pendingDeposits) + prunedPendingDepositsCount.Add(float64(prunedCount)) + + c.pendingDeposits = make([]*ethpb.DepositContainer, 0) + pendingDepositsCount.Set(float64(0)) +} + // InsertPendingDeposit into the database. If deposit or block number are nil // then this method does nothing. func (c *Cache) InsertPendingDeposit(ctx context.Context, d *ethpb.Deposit, blockNum uint64, index int64, depositRoot [32]byte) { diff --git a/beacon-chain/cache/interfaces.go b/beacon-chain/cache/interfaces.go index 163dbd0ef777..78d0868fdaaf 100644 --- a/beacon-chain/cache/interfaces.go +++ b/beacon-chain/cache/interfaces.go @@ -24,7 +24,9 @@ type DepositFetcher interface { PendingDeposits(ctx context.Context, untilBlk *big.Int) []*ethpb.Deposit PendingContainers(ctx context.Context, untilBlk *big.Int) []*ethpb.DepositContainer PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) + PruneAllPendingDeposits(ctx context.Context) PruneProofs(ctx context.Context, untilDepositIndex int64) error + PruneAllProofs(ctx context.Context) FinalizedFetcher } From 25e744374f9da9c63fcb2c8b75ca25b75f704e14 Mon Sep 17 00:00:00 2001 From: syjn99 Date: Mon, 27 Jan 2025 14:06:44 +0900 Subject: [PATCH 03/12] Add simple unit tests --- .../depositsnapshot/deposit_cache_test.go | 47 +++++++++++++++++++ .../depositsnapshot/deposit_fetcher_test.go | 18 +++++++ 2 files changed, 65 insertions(+) diff --git a/beacon-chain/cache/depositsnapshot/deposit_cache_test.go b/beacon-chain/cache/depositsnapshot/deposit_cache_test.go index 2c17e8428b5c..d44072357d69 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_cache_test.go +++ b/beacon-chain/cache/depositsnapshot/deposit_cache_test.go @@ -1039,6 +1039,53 @@ func TestPruneProofs_PruneAllWhenDepositIndexTooBig(t *testing.T) { assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) } +func TestPruneAllProofs(t *testing.T) { + dc, err := New() + require.NoError(t, err) + + deposits := []struct { + blkNum uint64 + deposit *ethpb.Deposit + index int64 + }{ + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, + index: 0, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, + index: 1, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, + index: 2, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, + index: 3, + }, + } + + for _, ins := range deposits { + assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) + } + + dc.PruneAllProofs(context.Background()) + + assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) +} + func TestPruneProofs_CorrectlyHandleLastIndex(t *testing.T) { dc, err := New() require.NoError(t, err) diff --git a/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go b/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go index 04c949355402..8923f2e0c77a 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go +++ b/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go @@ -108,3 +108,21 @@ func TestPrunePendingDeposits_OK(t *testing.T) { assert.DeepEqual(t, expected, dc.pendingDeposits) } + +func TestPruneAllPendingDeposits(t *testing.T) { + dc := Cache{} + + dc.pendingDeposits = []*ethpb.DepositContainer{ + {Eth1BlockHeight: 2, Index: 2}, + {Eth1BlockHeight: 4, Index: 4}, + {Eth1BlockHeight: 6, Index: 6}, + {Eth1BlockHeight: 8, Index: 8}, + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + + dc.PruneAllPendingDeposits(context.Background()) + expected := []*ethpb.DepositContainer{} + + assert.DeepEqual(t, expected, dc.pendingDeposits) +} From ea05560fdddbbc866bd162afaabb051b197e425c Mon Sep 17 00:00:00 2001 From: syjn99 Date: Mon, 27 Jan 2025 14:25:03 +0900 Subject: [PATCH 04/12] Add DepositPruner interface --- beacon-chain/cache/interfaces.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/beacon-chain/cache/interfaces.go b/beacon-chain/cache/interfaces.go index 78d0868fdaaf..338613e29636 100644 --- a/beacon-chain/cache/interfaces.go +++ b/beacon-chain/cache/interfaces.go @@ -12,6 +12,7 @@ import ( type DepositCache interface { DepositFetcher DepositInserter + DepositPruner } // DepositFetcher defines a struct which can retrieve deposit information from a store. @@ -23,10 +24,6 @@ type DepositFetcher interface { InsertPendingDeposit(ctx context.Context, d *ethpb.Deposit, blockNum uint64, index int64, depositRoot [32]byte) PendingDeposits(ctx context.Context, untilBlk *big.Int) []*ethpb.Deposit PendingContainers(ctx context.Context, untilBlk *big.Int) []*ethpb.DepositContainer - PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) - PruneAllPendingDeposits(ctx context.Context) - PruneProofs(ctx context.Context, untilDepositIndex int64) error - PruneAllProofs(ctx context.Context) FinalizedFetcher } @@ -44,6 +41,14 @@ type FinalizedFetcher interface { NonFinalizedDeposits(ctx context.Context, lastFinalizedIndex int64, untilBlk *big.Int) []*ethpb.Deposit } +// DepositPruner is an interface for pruning deposits and proofs. +type DepositPruner interface { + PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) + PruneAllPendingDeposits(ctx context.Context) + PruneProofs(ctx context.Context, untilDepositIndex int64) error + PruneAllProofs(ctx context.Context) +} + // FinalizedDeposits defines a method to access a merkle tree containing deposits and their indexes. type FinalizedDeposits interface { Deposits() MerkleTree From 394105413f4900b991b8a75dd42ebcbe19b0800f Mon Sep 17 00:00:00 2001 From: syjn99 Date: Mon, 27 Jan 2025 14:44:22 +0900 Subject: [PATCH 05/12] Add pruning logic at post finalization task --- .../blockchain/process_block_helpers.go | 6 +++++ beacon-chain/blockchain/receive_block.go | 24 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index e4a37ff4b221..3ec993b245f9 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -591,6 +591,12 @@ func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) { log.WithField("duration", time.Since(startTime).String()).Debugf("Finalized deposit insertion completed at index %d", finalizedEth1DepIdx) } +// pruneAllPendingDeposits prunes all proofs and pending deposits in the cache. +func (s *Service) pruneAllPendingDeposits(ctx context.Context) { + s.cfg.DepositCache.PruneAllPendingDeposits(ctx) + s.cfg.DepositCache.PruneAllProofs(ctx) +} + // This ensures that the input root defaults to using genesis root instead of zero hashes. This is needed for handling // fork choice justification routine. func (s *Service) ensureRootNotZeros(root [32]byte) [32]byte { diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index 6a55bf2660c0..fb4072de1c6b 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -278,11 +278,25 @@ func (s *Service) executePostFinalizationTasks(ctx context.Context, finalizedSta go func() { s.sendNewFinalizedEvent(ctx, finalizedState) }() - depCtx, cancel := context.WithTimeout(context.Background(), depositDeadline) - go func() { - s.insertFinalizedDeposits(depCtx, finalized.Root) - cancel() - }() + + // Check if we should prune all pending deposits. + // In post-Electra(after the legacy deposit mechanism is deprecated), + // we can prune all pending deposits in the deposit cache. + shouldPruneAll := false + requestsStartIndex, err := finalizedState.DepositRequestsStartIndex() + if err == nil { + shouldPruneAll = finalizedState.Eth1DepositIndex() == requestsStartIndex + } + + if shouldPruneAll { + s.pruneAllPendingDeposits(ctx) + } else { + depCtx, cancel := context.WithTimeout(context.Background(), depositDeadline) + go func() { + s.insertFinalizedDeposits(depCtx, finalized.Root) + cancel() + }() + } } // ReceiveBlockBatch processes the whole block batch at once, assuming the block batch is linear ,transitioning From a7eae6682d2b30110bf990133d08133181107b6e Mon Sep 17 00:00:00 2001 From: syjn99 Date: Wed, 29 Jan 2025 15:37:32 +0900 Subject: [PATCH 06/12] Move pruner logic into new file(deposit_pruner.go) Rationale: As deposit_fetcher.go contains all pruning logics, it would be better to separate its interest into fetcher/inserter/pruner. --- .../cache/depositsnapshot/BUILD.bazel | 2 + .../depositsnapshot/deposit_cache_test.go | 230 ------------- .../cache/depositsnapshot/deposit_fetcher.go | 97 ------ .../depositsnapshot/deposit_fetcher_test.go | 80 ----- .../cache/depositsnapshot/deposit_pruner.go | 110 ++++++ .../depositsnapshot/deposit_pruner_test.go | 323 ++++++++++++++++++ 6 files changed, 435 insertions(+), 407 deletions(-) create mode 100644 beacon-chain/cache/depositsnapshot/deposit_pruner.go create mode 100644 beacon-chain/cache/depositsnapshot/deposit_pruner_test.go diff --git a/beacon-chain/cache/depositsnapshot/BUILD.bazel b/beacon-chain/cache/depositsnapshot/BUILD.bazel index de6e52e5ee90..12a1835540b9 100644 --- a/beacon-chain/cache/depositsnapshot/BUILD.bazel +++ b/beacon-chain/cache/depositsnapshot/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "deposit_fetcher.go", "deposit_inserter.go", + "deposit_pruner.go", "deposit_tree.go", "deposit_tree_snapshot.go", "merkle_tree.go", @@ -35,6 +36,7 @@ go_test( srcs = [ "deposit_cache_test.go", "deposit_fetcher_test.go", + "deposit_pruner_test.go", "deposit_tree_snapshot_test.go", "merkle_tree_test.go", "spec_test.go", diff --git a/beacon-chain/cache/depositsnapshot/deposit_cache_test.go b/beacon-chain/cache/depositsnapshot/deposit_cache_test.go index d44072357d69..34e2cae987a8 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_cache_test.go +++ b/beacon-chain/cache/depositsnapshot/deposit_cache_test.go @@ -903,236 +903,6 @@ func TestMin(t *testing.T) { } -func TestPruneProofs_Ok(t *testing.T) { - dc, err := New() - require.NoError(t, err) - - deposits := []struct { - blkNum uint64 - deposit *ethpb.Deposit - index int64 - }{ - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, - index: 0, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, - index: 1, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, - index: 2, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, - index: 3, - }, - } - - for _, ins := range deposits { - assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) - } - - require.NoError(t, dc.PruneProofs(context.Background(), 1)) - - assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) - assert.NotNil(t, dc.deposits[2].Deposit.Proof) - assert.NotNil(t, dc.deposits[3].Deposit.Proof) -} - -func TestPruneProofs_SomeAlreadyPruned(t *testing.T) { - dc, err := New() - require.NoError(t, err) - - deposits := []struct { - blkNum uint64 - deposit *ethpb.Deposit - index int64 - }{ - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: nil, Data: ðpb.Deposit_Data{ - PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, - index: 0, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: nil, Data: ðpb.Deposit_Data{ - PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, index: 1, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, - index: 2, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, - index: 3, - }, - } - - for _, ins := range deposits { - assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) - } - - require.NoError(t, dc.PruneProofs(context.Background(), 2)) - - assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) -} - -func TestPruneProofs_PruneAllWhenDepositIndexTooBig(t *testing.T) { - dc, err := New() - require.NoError(t, err) - - deposits := []struct { - blkNum uint64 - deposit *ethpb.Deposit - index int64 - }{ - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, - index: 0, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, - index: 1, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, - index: 2, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, - index: 3, - }, - } - - for _, ins := range deposits { - assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) - } - - require.NoError(t, dc.PruneProofs(context.Background(), 99)) - - assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) -} - -func TestPruneAllProofs(t *testing.T) { - dc, err := New() - require.NoError(t, err) - - deposits := []struct { - blkNum uint64 - deposit *ethpb.Deposit - index int64 - }{ - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, - index: 0, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, - index: 1, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, - index: 2, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, - index: 3, - }, - } - - for _, ins := range deposits { - assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) - } - - dc.PruneAllProofs(context.Background()) - - assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) -} - -func TestPruneProofs_CorrectlyHandleLastIndex(t *testing.T) { - dc, err := New() - require.NoError(t, err) - - deposits := []struct { - blkNum uint64 - deposit *ethpb.Deposit - index int64 - }{ - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, - index: 0, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, - index: 1, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, - index: 2, - }, - { - blkNum: 0, - deposit: ðpb.Deposit{Proof: makeDepositProof(), - Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, - index: 3, - }, - } - - for _, ins := range deposits { - assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) - } - - require.NoError(t, dc.PruneProofs(context.Background(), 4)) - - assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) - assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) -} - func TestDepositMap_WorksCorrectly(t *testing.T) { dc, err := New() require.NoError(t, err) diff --git a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go index 2b758c8e49f9..088e480bcf7f 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go +++ b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go @@ -21,14 +21,6 @@ var ( Name: "beacondb_pending_deposits_eip4881", Help: "The number of pending deposits in memory", }) - prunedProofsCount = promauto.NewGauge(prometheus.GaugeOpts{ - Name: "beacondb_pruned_proofs_eip4881", - Help: "The number of pruned proofs", - }) - prunedPendingDepositsCount = promauto.NewGauge(prometheus.GaugeOpts{ - Name: "beacondb_pruned_pending_deposits_eip4881", - Help: "The number of pruned pending deposits", - }) ) // Cache stores all in-memory deposit objects. This @@ -186,95 +178,6 @@ func (c *Cache) NonFinalizedDeposits(ctx context.Context, lastFinalizedIndex int return deposits } -// PruneProofs removes proofs from all deposits whose index is equal or less than untilDepositIndex. -func (c *Cache) PruneProofs(ctx context.Context, untilDepositIndex int64) error { - _, span := trace.StartSpan(ctx, "Cache.PruneProofs") - defer span.End() - c.depositsLock.Lock() - defer c.depositsLock.Unlock() - - if untilDepositIndex >= int64(len(c.deposits)) { - untilDepositIndex = int64(len(c.deposits) - 1) - } - - for i := untilDepositIndex; i >= 0; i-- { - // Finding a nil proof means that all proofs up to this deposit have been already pruned. - if c.deposits[i].Deposit.Proof == nil { - break - } - c.deposits[i].Deposit.Proof = nil - prunedProofsCount.Inc() - } - - return nil -} - -// PruneAllProofs removes proofs from all deposits. -// As EIP-6110 applies and the legacy deposit mechanism is deprecated, -// proofs in deposit snapshot are no longer needed. -// See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation -func (c *Cache) PruneAllProofs(ctx context.Context) { - _, span := trace.StartSpan(ctx, "Cache.PruneAllProofs") - defer span.End() - - c.depositsLock.Lock() - defer c.depositsLock.Unlock() - - for i := len(c.deposits) - 1; i >= 0; i-- { - if c.deposits[i].Deposit.Proof == nil { - break - } - c.deposits[i].Deposit.Proof = nil - prunedProofsCount.Inc() - } -} - -// PrunePendingDeposits removes any deposit which is older than the given deposit merkle tree index. -func (c *Cache) PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) { - _, span := trace.StartSpan(ctx, "Cache.PrunePendingDeposits") - defer span.End() - - if merkleTreeIndex == 0 { - log.Debug("Ignoring 0 deposit removal") - return - } - - c.depositsLock.Lock() - defer c.depositsLock.Unlock() - - cleanDeposits := make([]*ethpb.DepositContainer, 0, len(c.pendingDeposits)) - for _, dp := range c.pendingDeposits { - if dp.Index >= merkleTreeIndex { - cleanDeposits = append(cleanDeposits, dp) - } - } - - // Add pruned count to prom metric - prunedCount := len(c.pendingDeposits) - len(cleanDeposits) - prunedPendingDepositsCount.Add(float64(prunedCount)) - - c.pendingDeposits = cleanDeposits - pendingDepositsCount.Set(float64(len(c.pendingDeposits))) -} - -// PruneAllPendingDeposits removes all pending deposits from the cache. -// As EIP-6110 applies and the legacy deposit mechanism is deprecated, -// pending deposits in deposit snapshot are no longer needed. -// See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation -func (c *Cache) PruneAllPendingDeposits(ctx context.Context) { - _, span := trace.StartSpan(ctx, "Cache.PruneAllPendingDeposits") - defer span.End() - - c.depositsLock.Lock() - defer c.depositsLock.Unlock() - - prunedCount := len(c.pendingDeposits) - prunedPendingDepositsCount.Add(float64(prunedCount)) - - c.pendingDeposits = make([]*ethpb.DepositContainer, 0) - pendingDepositsCount.Set(float64(0)) -} - // InsertPendingDeposit into the database. If deposit or block number are nil // then this method does nothing. func (c *Cache) InsertPendingDeposit(ctx context.Context, d *ethpb.Deposit, blockNum uint64, index int64, depositRoot [32]byte) { diff --git a/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go b/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go index 8923f2e0c77a..f4e4e373ef96 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go +++ b/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go @@ -45,84 +45,4 @@ func TestPendingDeposits_OK(t *testing.T) { assert.Equal(t, len(dc.pendingDeposits), len(all), "PendingDeposits(ctx, nil) did not return all deposits") } -func TestPrunePendingDeposits_ZeroMerkleIndex(t *testing.T) { - dc := Cache{} - - dc.pendingDeposits = []*ethpb.DepositContainer{ - {Eth1BlockHeight: 2, Index: 2}, - {Eth1BlockHeight: 4, Index: 4}, - {Eth1BlockHeight: 6, Index: 6}, - {Eth1BlockHeight: 8, Index: 8}, - {Eth1BlockHeight: 10, Index: 10}, - {Eth1BlockHeight: 12, Index: 12}, - } - - dc.PrunePendingDeposits(context.Background(), 0) - expected := []*ethpb.DepositContainer{ - {Eth1BlockHeight: 2, Index: 2}, - {Eth1BlockHeight: 4, Index: 4}, - {Eth1BlockHeight: 6, Index: 6}, - {Eth1BlockHeight: 8, Index: 8}, - {Eth1BlockHeight: 10, Index: 10}, - {Eth1BlockHeight: 12, Index: 12}, - } - assert.DeepEqual(t, expected, dc.pendingDeposits) -} - -func TestPrunePendingDeposits_OK(t *testing.T) { - dc := Cache{} - - dc.pendingDeposits = []*ethpb.DepositContainer{ - {Eth1BlockHeight: 2, Index: 2}, - {Eth1BlockHeight: 4, Index: 4}, - {Eth1BlockHeight: 6, Index: 6}, - {Eth1BlockHeight: 8, Index: 8}, - {Eth1BlockHeight: 10, Index: 10}, - {Eth1BlockHeight: 12, Index: 12}, - } - - dc.PrunePendingDeposits(context.Background(), 6) - expected := []*ethpb.DepositContainer{ - {Eth1BlockHeight: 6, Index: 6}, - {Eth1BlockHeight: 8, Index: 8}, - {Eth1BlockHeight: 10, Index: 10}, - {Eth1BlockHeight: 12, Index: 12}, - } - - assert.DeepEqual(t, expected, dc.pendingDeposits) - dc.pendingDeposits = []*ethpb.DepositContainer{ - {Eth1BlockHeight: 2, Index: 2}, - {Eth1BlockHeight: 4, Index: 4}, - {Eth1BlockHeight: 6, Index: 6}, - {Eth1BlockHeight: 8, Index: 8}, - {Eth1BlockHeight: 10, Index: 10}, - {Eth1BlockHeight: 12, Index: 12}, - } - - dc.PrunePendingDeposits(context.Background(), 10) - expected = []*ethpb.DepositContainer{ - {Eth1BlockHeight: 10, Index: 10}, - {Eth1BlockHeight: 12, Index: 12}, - } - - assert.DeepEqual(t, expected, dc.pendingDeposits) -} - -func TestPruneAllPendingDeposits(t *testing.T) { - dc := Cache{} - - dc.pendingDeposits = []*ethpb.DepositContainer{ - {Eth1BlockHeight: 2, Index: 2}, - {Eth1BlockHeight: 4, Index: 4}, - {Eth1BlockHeight: 6, Index: 6}, - {Eth1BlockHeight: 8, Index: 8}, - {Eth1BlockHeight: 10, Index: 10}, - {Eth1BlockHeight: 12, Index: 12}, - } - - dc.PruneAllPendingDeposits(context.Background()) - expected := []*ethpb.DepositContainer{} - - assert.DeepEqual(t, expected, dc.pendingDeposits) -} diff --git a/beacon-chain/cache/depositsnapshot/deposit_pruner.go b/beacon-chain/cache/depositsnapshot/deposit_pruner.go new file mode 100644 index 000000000000..c1a4aba3a54c --- /dev/null +++ b/beacon-chain/cache/depositsnapshot/deposit_pruner.go @@ -0,0 +1,110 @@ +package depositsnapshot + +import ( + "context" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" +) + +var ( + prunedProofsCount = promauto.NewGauge(prometheus.GaugeOpts{ + Name: "beacondb_pruned_proofs_eip4881", + Help: "The number of pruned proofs", + }) + prunedPendingDepositsCount = promauto.NewGauge(prometheus.GaugeOpts{ + Name: "beacondb_pruned_pending_deposits_eip4881", + Help: "The number of pruned pending deposits", + }) +) + +// PruneProofs removes proofs from all deposits whose index is equal or less than untilDepositIndex. +func (c *Cache) PruneProofs(ctx context.Context, untilDepositIndex int64) error { + _, span := trace.StartSpan(ctx, "Cache.PruneProofs") + defer span.End() + c.depositsLock.Lock() + defer c.depositsLock.Unlock() + + if untilDepositIndex >= int64(len(c.deposits)) { + untilDepositIndex = int64(len(c.deposits) - 1) + } + + for i := untilDepositIndex; i >= 0; i-- { + // Finding a nil proof means that all proofs up to this deposit have been already pruned. + if c.deposits[i].Deposit.Proof == nil { + break + } + c.deposits[i].Deposit.Proof = nil + prunedProofsCount.Inc() + } + + return nil +} + +// PruneAllProofs removes proofs from all deposits. +// As EIP-6110 applies and the legacy deposit mechanism is deprecated, +// proofs in deposit snapshot are no longer needed. +// See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation +func (c *Cache) PruneAllProofs(ctx context.Context) { + _, span := trace.StartSpan(ctx, "Cache.PruneAllProofs") + defer span.End() + + c.depositsLock.Lock() + defer c.depositsLock.Unlock() + + for i := len(c.deposits) - 1; i >= 0; i-- { + if c.deposits[i].Deposit.Proof == nil { + break + } + c.deposits[i].Deposit.Proof = nil + prunedProofsCount.Inc() + } +} + +// PrunePendingDeposits removes any deposit which is older than the given deposit merkle tree index. +func (c *Cache) PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) { + _, span := trace.StartSpan(ctx, "Cache.PrunePendingDeposits") + defer span.End() + + if merkleTreeIndex == 0 { + log.Debug("Ignoring 0 deposit removal") + return + } + + c.depositsLock.Lock() + defer c.depositsLock.Unlock() + + cleanDeposits := make([]*ethpb.DepositContainer, 0, len(c.pendingDeposits)) + for _, dp := range c.pendingDeposits { + if dp.Index >= merkleTreeIndex { + cleanDeposits = append(cleanDeposits, dp) + } + } + + // Add pruned count to prom metric + prunedCount := len(c.pendingDeposits) - len(cleanDeposits) + prunedPendingDepositsCount.Add(float64(prunedCount)) + + c.pendingDeposits = cleanDeposits + pendingDepositsCount.Set(float64(len(c.pendingDeposits))) +} + +// PruneAllPendingDeposits removes all pending deposits from the cache. +// As EIP-6110 applies and the legacy deposit mechanism is deprecated, +// pending deposits in deposit snapshot are no longer needed. +// See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation +func (c *Cache) PruneAllPendingDeposits(ctx context.Context) { + _, span := trace.StartSpan(ctx, "Cache.PruneAllPendingDeposits") + defer span.End() + + c.depositsLock.Lock() + defer c.depositsLock.Unlock() + + prunedCount := len(c.pendingDeposits) + prunedPendingDepositsCount.Add(float64(prunedCount)) + + c.pendingDeposits = make([]*ethpb.DepositContainer, 0) + pendingDepositsCount.Set(float64(0)) +} \ No newline at end of file diff --git a/beacon-chain/cache/depositsnapshot/deposit_pruner_test.go b/beacon-chain/cache/depositsnapshot/deposit_pruner_test.go new file mode 100644 index 000000000000..64821f1a1467 --- /dev/null +++ b/beacon-chain/cache/depositsnapshot/deposit_pruner_test.go @@ -0,0 +1,323 @@ +package depositsnapshot + +import ( + "context" + "testing" + + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/testing/assert" + "github.com/prysmaticlabs/prysm/v5/testing/require" +) + +func TestPrunePendingDeposits_ZeroMerkleIndex(t *testing.T) { + dc := Cache{} + + dc.pendingDeposits = []*ethpb.DepositContainer{ + {Eth1BlockHeight: 2, Index: 2}, + {Eth1BlockHeight: 4, Index: 4}, + {Eth1BlockHeight: 6, Index: 6}, + {Eth1BlockHeight: 8, Index: 8}, + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + + dc.PrunePendingDeposits(context.Background(), 0) + expected := []*ethpb.DepositContainer{ + {Eth1BlockHeight: 2, Index: 2}, + {Eth1BlockHeight: 4, Index: 4}, + {Eth1BlockHeight: 6, Index: 6}, + {Eth1BlockHeight: 8, Index: 8}, + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + assert.DeepEqual(t, expected, dc.pendingDeposits) +} + +func TestPrunePendingDeposits_OK(t *testing.T) { + dc := Cache{} + + dc.pendingDeposits = []*ethpb.DepositContainer{ + {Eth1BlockHeight: 2, Index: 2}, + {Eth1BlockHeight: 4, Index: 4}, + {Eth1BlockHeight: 6, Index: 6}, + {Eth1BlockHeight: 8, Index: 8}, + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + + dc.PrunePendingDeposits(context.Background(), 6) + expected := []*ethpb.DepositContainer{ + {Eth1BlockHeight: 6, Index: 6}, + {Eth1BlockHeight: 8, Index: 8}, + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + + assert.DeepEqual(t, expected, dc.pendingDeposits) + + dc.pendingDeposits = []*ethpb.DepositContainer{ + {Eth1BlockHeight: 2, Index: 2}, + {Eth1BlockHeight: 4, Index: 4}, + {Eth1BlockHeight: 6, Index: 6}, + {Eth1BlockHeight: 8, Index: 8}, + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + + dc.PrunePendingDeposits(context.Background(), 10) + expected = []*ethpb.DepositContainer{ + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + + assert.DeepEqual(t, expected, dc.pendingDeposits) +} + +func TestPruneAllPendingDeposits(t *testing.T) { + dc := Cache{} + + dc.pendingDeposits = []*ethpb.DepositContainer{ + {Eth1BlockHeight: 2, Index: 2}, + {Eth1BlockHeight: 4, Index: 4}, + {Eth1BlockHeight: 6, Index: 6}, + {Eth1BlockHeight: 8, Index: 8}, + {Eth1BlockHeight: 10, Index: 10}, + {Eth1BlockHeight: 12, Index: 12}, + } + + dc.PruneAllPendingDeposits(context.Background()) + expected := []*ethpb.DepositContainer{} + + assert.DeepEqual(t, expected, dc.pendingDeposits) +} + +func TestPruneProofs_Ok(t *testing.T) { + dc, err := New() + require.NoError(t, err) + + deposits := []struct { + blkNum uint64 + deposit *ethpb.Deposit + index int64 + }{ + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, + index: 0, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, + index: 1, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, + index: 2, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, + index: 3, + }, + } + + for _, ins := range deposits { + assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) + } + + require.NoError(t, dc.PruneProofs(context.Background(), 1)) + + assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) + assert.NotNil(t, dc.deposits[2].Deposit.Proof) + assert.NotNil(t, dc.deposits[3].Deposit.Proof) +} + +func TestPruneProofs_SomeAlreadyPruned(t *testing.T) { + dc, err := New() + require.NoError(t, err) + + deposits := []struct { + blkNum uint64 + deposit *ethpb.Deposit + index int64 + }{ + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: nil, Data: ðpb.Deposit_Data{ + PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, + index: 0, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: nil, Data: ðpb.Deposit_Data{ + PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, index: 1, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, + index: 2, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, + index: 3, + }, + } + + for _, ins := range deposits { + assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) + } + + require.NoError(t, dc.PruneProofs(context.Background(), 2)) + + assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) +} + +func TestPruneProofs_PruneAllWhenDepositIndexTooBig(t *testing.T) { + dc, err := New() + require.NoError(t, err) + + deposits := []struct { + blkNum uint64 + deposit *ethpb.Deposit + index int64 + }{ + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, + index: 0, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, + index: 1, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, + index: 2, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, + index: 3, + }, + } + + for _, ins := range deposits { + assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) + } + + require.NoError(t, dc.PruneProofs(context.Background(), 99)) + + assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) +} + +func TestPruneProofs_CorrectlyHandleLastIndex(t *testing.T) { + dc, err := New() + require.NoError(t, err) + + deposits := []struct { + blkNum uint64 + deposit *ethpb.Deposit + index int64 + }{ + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, + index: 0, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, + index: 1, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, + index: 2, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, + index: 3, + }, + } + + for _, ins := range deposits { + assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) + } + + require.NoError(t, dc.PruneProofs(context.Background(), 4)) + + assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) +} + +func TestPruneAllProofs(t *testing.T) { + dc, err := New() + require.NoError(t, err) + + deposits := []struct { + blkNum uint64 + deposit *ethpb.Deposit + index int64 + }{ + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk0"), 48)}}, + index: 0, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk1"), 48)}}, + index: 1, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk2"), 48)}}, + index: 2, + }, + { + blkNum: 0, + deposit: ðpb.Deposit{Proof: makeDepositProof(), + Data: ðpb.Deposit_Data{PublicKey: bytesutil.PadTo([]byte("pk3"), 48)}}, + index: 3, + }, + } + + for _, ins := range deposits { + assert.NoError(t, dc.InsertDeposit(context.Background(), ins.deposit, ins.blkNum, ins.index, [32]byte{})) + } + + dc.PruneAllProofs(context.Background()) + + assert.DeepEqual(t, [][]byte(nil), dc.deposits[0].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[1].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[2].Deposit.Proof) + assert.DeepEqual(t, [][]byte(nil), dc.deposits[3].Deposit.Proof) +} From 7874ea65bcde39969bb1080d94f48f73109be4bd Mon Sep 17 00:00:00 2001 From: syjn99 Date: Wed, 29 Jan 2025 15:42:40 +0900 Subject: [PATCH 07/12] Gofmt --- beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go | 2 -- beacon-chain/cache/depositsnapshot/deposit_pruner.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go b/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go index f4e4e373ef96..0c5fbf6ade5e 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go +++ b/beacon-chain/cache/depositsnapshot/deposit_fetcher_test.go @@ -44,5 +44,3 @@ func TestPendingDeposits_OK(t *testing.T) { all := dc.PendingDeposits(context.Background(), nil) assert.Equal(t, len(dc.pendingDeposits), len(all), "PendingDeposits(ctx, nil) did not return all deposits") } - - diff --git a/beacon-chain/cache/depositsnapshot/deposit_pruner.go b/beacon-chain/cache/depositsnapshot/deposit_pruner.go index c1a4aba3a54c..b019fa93b6ed 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_pruner.go +++ b/beacon-chain/cache/depositsnapshot/deposit_pruner.go @@ -107,4 +107,4 @@ func (c *Cache) PruneAllPendingDeposits(ctx context.Context) { c.pendingDeposits = make([]*ethpb.DepositContainer, 0) pendingDepositsCount.Set(float64(0)) -} \ No newline at end of file +} From bd905e9974368507037500869390560d557f912f Mon Sep 17 00:00:00 2001 From: syjn99 Date: Wed, 29 Jan 2025 15:42:56 +0900 Subject: [PATCH 08/12] Add reference link for deprecating eth1 polling --- beacon-chain/blockchain/receive_block.go | 1 + 1 file changed, 1 insertion(+) diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index fb4072de1c6b..eac19db64ab2 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -282,6 +282,7 @@ func (s *Service) executePostFinalizationTasks(ctx context.Context, finalizedSta // Check if we should prune all pending deposits. // In post-Electra(after the legacy deposit mechanism is deprecated), // we can prune all pending deposits in the deposit cache. + // See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation shouldPruneAll := false requestsStartIndex, err := finalizedState.DepositRequestsStartIndex() if err == nil { From 2257b7d4b9296d1c04a3b903aee09bfa43332f80 Mon Sep 17 00:00:00 2001 From: syjn99 Date: Wed, 29 Jan 2025 15:44:10 +0900 Subject: [PATCH 09/12] Add changelog --- changelog/syjn99_prune-deposit-cache.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog/syjn99_prune-deposit-cache.md diff --git a/changelog/syjn99_prune-deposit-cache.md b/changelog/syjn99_prune-deposit-cache.md new file mode 100644 index 000000000000..64962ae683d7 --- /dev/null +++ b/changelog/syjn99_prune-deposit-cache.md @@ -0,0 +1,3 @@ +### Added + +- Prune all pending deposits and proofs in post-Electra. \ No newline at end of file From 1778c4901b930e6d8069df35c5be14bf55a26bf5 Mon Sep 17 00:00:00 2001 From: syjn99 Date: Fri, 7 Feb 2025 01:07:42 +0900 Subject: [PATCH 10/12] Apply reviews from nisdas and james --- .../blockchain/process_block_helpers.go | 14 ++++++++++- beacon-chain/blockchain/process_block_test.go | 8 +++---- beacon-chain/blockchain/receive_block.go | 24 ++++--------------- .../cache/depositsnapshot/deposit_pruner.go | 22 ----------------- 4 files changed, 22 insertions(+), 46 deletions(-) diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index 3ec993b245f9..71cc03cd6c09 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -7,6 +7,7 @@ import ( "strings" "time" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" lightclient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client" "github.com/ethereum/go-ethereum/common" @@ -552,7 +553,8 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, signed inte // inserts finalized deposits into our finalized deposit trie, needs to be // called in the background -func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) { +// Post-Electra: prunes all proofs and pending deposits in the cache +func (s *Service) insertFinalizedDepositsAndPrune(ctx context.Context, fRoot [32]byte) { ctx, span := trace.StartSpan(ctx, "blockChain.insertFinalizedDeposits") defer span.End() startTime := time.Now() @@ -563,6 +565,16 @@ func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) { log.WithError(err).Error("could not fetch finalized state") return } + + // Check if we should prune all pending deposits. + // In post-Electra(after the legacy deposit mechanism is deprecated), + // we can prune all pending deposits in the deposit cache. + // See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation + if helpers.DepositRequestsStarted(finalizedState) { + s.pruneAllPendingDeposits(ctx) + return + } + // We update the cache up to the last deposit index in the finalized block's state. // We can be confident that these deposits will be included in some block // because the Eth1 follow distance makes such long-range reorgs extremely unlikely. diff --git a/beacon-chain/blockchain/process_block_test.go b/beacon-chain/blockchain/process_block_test.go index 36e8383050e6..a41e5a178deb 100644 --- a/beacon-chain/blockchain/process_block_test.go +++ b/beacon-chain/blockchain/process_block_test.go @@ -723,7 +723,7 @@ func TestInsertFinalizedDeposits(t *testing.T) { Signature: zeroSig[:], }, Proof: [][]byte{root}}, 100+i, int64(i), bytesutil.ToBytes32(root))) } - service.insertFinalizedDeposits(ctx, [32]byte{'m', 'o', 'c', 'k'}) + service.insertFinalizedDepositsAndPrune(ctx, [32]byte{'m', 'o', 'c', 'k'}) fDeposits, err := depositCache.FinalizedDeposits(ctx) require.NoError(t, err) assert.Equal(t, 7, int(fDeposits.MerkleTrieIndex()), "Finalized deposits not inserted correctly") @@ -759,7 +759,7 @@ func TestInsertFinalizedDeposits_PrunePendingDeposits(t *testing.T) { Signature: zeroSig[:], }, Proof: [][]byte{root}}, 100+i, int64(i), bytesutil.ToBytes32(root)) } - service.insertFinalizedDeposits(ctx, [32]byte{'m', 'o', 'c', 'k'}) + service.insertFinalizedDepositsAndPrune(ctx, [32]byte{'m', 'o', 'c', 'k'}) fDeposits, err := depositCache.FinalizedDeposits(ctx) require.NoError(t, err) assert.Equal(t, 7, int(fDeposits.MerkleTrieIndex()), "Finalized deposits not inserted correctly") @@ -799,7 +799,7 @@ func TestInsertFinalizedDeposits_MultipleFinalizedRoutines(t *testing.T) { } // Insert 3 deposits before hand. require.NoError(t, depositCache.InsertFinalizedDeposits(ctx, 2, [32]byte{}, 0)) - service.insertFinalizedDeposits(ctx, [32]byte{'m', 'o', 'c', 'k'}) + service.insertFinalizedDepositsAndPrune(ctx, [32]byte{'m', 'o', 'c', 'k'}) fDeposits, err := depositCache.FinalizedDeposits(ctx) require.NoError(t, err) assert.Equal(t, 5, int(fDeposits.MerkleTrieIndex()), "Finalized deposits not inserted correctly") @@ -810,7 +810,7 @@ func TestInsertFinalizedDeposits_MultipleFinalizedRoutines(t *testing.T) { } // Insert New Finalized State with higher deposit count. - service.insertFinalizedDeposits(ctx, [32]byte{'m', 'o', 'c', 'k', '2'}) + service.insertFinalizedDepositsAndPrune(ctx, [32]byte{'m', 'o', 'c', 'k', '2'}) fDeposits, err = depositCache.FinalizedDeposits(ctx) require.NoError(t, err) assert.Equal(t, 12, int(fDeposits.MerkleTrieIndex()), "Finalized deposits not inserted correctly") diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index a07a47d89594..64c5444569aa 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -280,25 +280,11 @@ func (s *Service) executePostFinalizationTasks(ctx context.Context, finalizedSta s.sendNewFinalizedEvent(ctx, finalizedState) }() - // Check if we should prune all pending deposits. - // In post-Electra(after the legacy deposit mechanism is deprecated), - // we can prune all pending deposits in the deposit cache. - // See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation - shouldPruneAll := false - requestsStartIndex, err := finalizedState.DepositRequestsStartIndex() - if err == nil { - shouldPruneAll = finalizedState.Eth1DepositIndex() == requestsStartIndex - } - - if shouldPruneAll { - s.pruneAllPendingDeposits(ctx) - } else { - depCtx, cancel := context.WithTimeout(context.Background(), depositDeadline) - go func() { - s.insertFinalizedDeposits(depCtx, finalized.Root) - cancel() - }() - } + depCtx, cancel := context.WithTimeout(context.Background(), depositDeadline) + go func() { + s.insertFinalizedDepositsAndPrune(depCtx, finalized.Root) + cancel() + }() } // ReceiveBlockBatch processes the whole block batch at once, assuming the block batch is linear ,transitioning diff --git a/beacon-chain/cache/depositsnapshot/deposit_pruner.go b/beacon-chain/cache/depositsnapshot/deposit_pruner.go index b019fa93b6ed..904a3a1b1f47 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_pruner.go +++ b/beacon-chain/cache/depositsnapshot/deposit_pruner.go @@ -3,23 +3,10 @@ package depositsnapshot import ( "context" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" ) -var ( - prunedProofsCount = promauto.NewGauge(prometheus.GaugeOpts{ - Name: "beacondb_pruned_proofs_eip4881", - Help: "The number of pruned proofs", - }) - prunedPendingDepositsCount = promauto.NewGauge(prometheus.GaugeOpts{ - Name: "beacondb_pruned_pending_deposits_eip4881", - Help: "The number of pruned pending deposits", - }) -) - // PruneProofs removes proofs from all deposits whose index is equal or less than untilDepositIndex. func (c *Cache) PruneProofs(ctx context.Context, untilDepositIndex int64) error { _, span := trace.StartSpan(ctx, "Cache.PruneProofs") @@ -37,7 +24,6 @@ func (c *Cache) PruneProofs(ctx context.Context, untilDepositIndex int64) error break } c.deposits[i].Deposit.Proof = nil - prunedProofsCount.Inc() } return nil @@ -59,7 +45,6 @@ func (c *Cache) PruneAllProofs(ctx context.Context) { break } c.deposits[i].Deposit.Proof = nil - prunedProofsCount.Inc() } } @@ -83,10 +68,6 @@ func (c *Cache) PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) } } - // Add pruned count to prom metric - prunedCount := len(c.pendingDeposits) - len(cleanDeposits) - prunedPendingDepositsCount.Add(float64(prunedCount)) - c.pendingDeposits = cleanDeposits pendingDepositsCount.Set(float64(len(c.pendingDeposits))) } @@ -102,9 +83,6 @@ func (c *Cache) PruneAllPendingDeposits(ctx context.Context) { c.depositsLock.Lock() defer c.depositsLock.Unlock() - prunedCount := len(c.pendingDeposits) - prunedPendingDepositsCount.Add(float64(prunedCount)) - c.pendingDeposits = make([]*ethpb.DepositContainer, 0) pendingDepositsCount.Set(float64(0)) } From 02fec8f410e34938527df406254a84e9a922ed74 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Thu, 6 Feb 2025 15:41:49 -0600 Subject: [PATCH 11/12] add pre and post deposit request tests --- beacon-chain/blockchain/receive_block_test.go | 108 ++++++++++++------ 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/beacon-chain/blockchain/receive_block_test.go b/beacon-chain/blockchain/receive_block_test.go index d8d36051a013..1dae450b801b 100644 --- a/beacon-chain/blockchain/receive_block_test.go +++ b/beacon-chain/blockchain/receive_block_test.go @@ -455,41 +455,81 @@ func Test_executePostFinalizationTasks(t *testing.T) { Root: headRoot[:], })) require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:])) + t.Run("pre deposit request", func(t *testing.T) { + require.NoError(t, headState.SetEth1DepositIndex(1)) + s, tr := minimalTestService(t, WithFinalizedStateAtStartUp(headState)) + ctx, beaconDB, stateGen := tr.ctx, tr.db, tr.sg + + require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot)) + util.SaveBlock(t, ctx, beaconDB, genesis) + require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot)) + require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot)) + util.SaveBlock(t, ctx, beaconDB, headBlock) + require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) - s, tr := minimalTestService(t, WithFinalizedStateAtStartUp(headState)) - ctx, beaconDB, stateGen := tr.ctx, tr.db, tr.sg - - require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot)) - util.SaveBlock(t, ctx, beaconDB, genesis) - require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot)) - require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot)) - util.SaveBlock(t, ctx, beaconDB, headBlock) - require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) - - require.NoError(t, err) - require.NoError(t, stateGen.SaveState(ctx, headRoot, headState)) - require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) - - notifier := &blockchainTesting.MockStateNotifier{RecordEvents: true} - s.cfg.StateNotifier = notifier - s.executePostFinalizationTasks(s.ctx, headState) - - time.Sleep(1 * time.Second) // sleep for a second because event is in a separate go routine - require.Equal(t, 1, len(notifier.ReceivedEvents())) - e := notifier.ReceivedEvents()[0] - assert.Equal(t, statefeed.FinalizedCheckpoint, int(e.Type)) - fc, ok := e.Data.(*ethpbv1.EventFinalizedCheckpoint) - require.Equal(t, true, ok, "event has wrong data type") - assert.Equal(t, primitives.Epoch(123), fc.Epoch) - assert.DeepEqual(t, headRoot[:], fc.Block) - assert.DeepEqual(t, finalizedStRoot[:], fc.State) - assert.Equal(t, false, fc.ExecutionOptimistic) + require.NoError(t, err) + require.NoError(t, stateGen.SaveState(ctx, headRoot, headState)) + require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) + + notifier := &blockchainTesting.MockStateNotifier{RecordEvents: true} + s.cfg.StateNotifier = notifier + s.executePostFinalizationTasks(s.ctx, headState) + + time.Sleep(1 * time.Second) // sleep for a second because event is in a separate go routine + require.Equal(t, 1, len(notifier.ReceivedEvents())) + e := notifier.ReceivedEvents()[0] + assert.Equal(t, statefeed.FinalizedCheckpoint, int(e.Type)) + fc, ok := e.Data.(*ethpbv1.EventFinalizedCheckpoint) + require.Equal(t, true, ok, "event has wrong data type") + assert.Equal(t, primitives.Epoch(123), fc.Epoch) + assert.DeepEqual(t, headRoot[:], fc.Block) + assert.DeepEqual(t, finalizedStRoot[:], fc.State) + assert.Equal(t, false, fc.ExecutionOptimistic) + + // check the cache + index, ok := headState.ValidatorIndexByPubkey(bytesutil.ToBytes48(key)) + require.Equal(t, true, ok) + require.Equal(t, primitives.ValidatorIndex(0), index) // first index + + // check deposit + require.LogsContain(t, logHook, "Finalized deposit insertion completed at index") + }) + t.Run("deposit requests started", func(t *testing.T) { + require.NoError(t, headState.SetEth1DepositIndex(1)) + require.NoError(t, headState.SetDepositRequestsStartIndex(1)) + s, tr := minimalTestService(t, WithFinalizedStateAtStartUp(headState)) + ctx, beaconDB, stateGen := tr.ctx, tr.db, tr.sg + + require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot)) + util.SaveBlock(t, ctx, beaconDB, genesis) + require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot)) + require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot)) + util.SaveBlock(t, ctx, beaconDB, headBlock) + require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) - // check the cache - index, ok := headState.ValidatorIndexByPubkey(bytesutil.ToBytes48(key)) - require.Equal(t, true, ok) - require.Equal(t, primitives.ValidatorIndex(0), index) // first index + require.NoError(t, err) + require.NoError(t, stateGen.SaveState(ctx, headRoot, headState)) + require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) + + notifier := &blockchainTesting.MockStateNotifier{RecordEvents: true} + s.cfg.StateNotifier = notifier + s.executePostFinalizationTasks(s.ctx, headState) + + time.Sleep(1 * time.Second) // sleep for a second because event is in a separate go routine + require.Equal(t, 1, len(notifier.ReceivedEvents())) + e := notifier.ReceivedEvents()[0] + assert.Equal(t, statefeed.FinalizedCheckpoint, int(e.Type)) + fc, ok := e.Data.(*ethpbv1.EventFinalizedCheckpoint) + require.Equal(t, true, ok, "event has wrong data type") + assert.Equal(t, primitives.Epoch(123), fc.Epoch) + assert.DeepEqual(t, headRoot[:], fc.Block) + assert.DeepEqual(t, finalizedStRoot[:], fc.State) + assert.Equal(t, false, fc.ExecutionOptimistic) + + // check the cache + index, ok := headState.ValidatorIndexByPubkey(bytesutil.ToBytes48(key)) + require.Equal(t, true, ok) + require.Equal(t, primitives.ValidatorIndex(0), index) // first index + }) - // check deposit - require.LogsContain(t, logHook, "Finalized deposit insertion completed at index") } From 4541537ec764b77bb6fa9f8400fb1937bdff2781 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Thu, 6 Feb 2025 21:55:06 -0600 Subject: [PATCH 12/12] nishant's comment --- beacon-chain/blockchain/process_block_helpers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index 71cc03cd6c09..d751f859ca95 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -571,7 +571,7 @@ func (s *Service) insertFinalizedDepositsAndPrune(ctx context.Context, fRoot [32 // we can prune all pending deposits in the deposit cache. // See: https://eips.ethereum.org/EIPS/eip-6110#eth1data-poll-deprecation if helpers.DepositRequestsStarted(finalizedState) { - s.pruneAllPendingDeposits(ctx) + s.pruneAllPendingDepositsAndProofs(ctx) return } @@ -603,8 +603,8 @@ func (s *Service) insertFinalizedDepositsAndPrune(ctx context.Context, fRoot [32 log.WithField("duration", time.Since(startTime).String()).Debugf("Finalized deposit insertion completed at index %d", finalizedEth1DepIdx) } -// pruneAllPendingDeposits prunes all proofs and pending deposits in the cache. -func (s *Service) pruneAllPendingDeposits(ctx context.Context) { +// pruneAllPendingDepositsAndProofs prunes all proofs and pending deposits in the cache. +func (s *Service) pruneAllPendingDepositsAndProofs(ctx context.Context) { s.cfg.DepositCache.PruneAllPendingDeposits(ctx) s.cfg.DepositCache.PruneAllProofs(ctx) }