diff --git a/beacon-chain/db/kv/blocks.go b/beacon-chain/db/kv/blocks.go index 9b94098af8e8..0b4105ebf68f 100644 --- a/beacon-chain/db/kv/blocks.go +++ b/beacon-chain/db/kv/blocks.go @@ -328,8 +328,8 @@ func (s *Store) SaveBlocks(ctx context.Context, blks []interfaces.SignedBeaconBl func (s *Store) SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error { ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveHeadBlockRoot") defer span.End() + hasStateSummary := s.HasStateSummary(ctx, blockRoot) return s.db.Update(func(tx *bolt.Tx) error { - hasStateSummary := s.hasStateSummaryBytes(tx, blockRoot) hasStateInDB := tx.Bucket(stateBucket).Get(blockRoot[:]) != nil if !(hasStateInDB || hasStateSummary) { return errors.New("no state or state summary found with head block root") diff --git a/beacon-chain/db/kv/checkpoint.go b/beacon-chain/db/kv/checkpoint.go index 9114a94b3ee2..b734094077da 100644 --- a/beacon-chain/db/kv/checkpoint.go +++ b/beacon-chain/db/kv/checkpoint.go @@ -59,9 +59,9 @@ func (s *Store) SaveJustifiedCheckpoint(ctx context.Context, checkpoint *ethpb.C if err != nil { return err } + hasStateSummary := s.HasStateSummary(ctx, bytesutil.ToBytes32(checkpoint.Root)) return s.db.Update(func(tx *bolt.Tx) error { bucket := tx.Bucket(checkpointBucket) - hasStateSummary := s.hasStateSummaryBytes(tx, bytesutil.ToBytes32(checkpoint.Root)) hasStateInDB := tx.Bucket(stateBucket).Get(checkpoint.Root) != nil if !(hasStateInDB || hasStateSummary) { log.Warnf("Recovering state summary for justified root: %#x", bytesutil.Trunc(checkpoint.Root)) @@ -82,9 +82,9 @@ func (s *Store) SaveFinalizedCheckpoint(ctx context.Context, checkpoint *ethpb.C if err != nil { return err } + hasStateSummary := s.HasStateSummary(ctx, bytesutil.ToBytes32(checkpoint.Root)) return s.db.Update(func(tx *bolt.Tx) error { bucket := tx.Bucket(checkpointBucket) - hasStateSummary := s.hasStateSummaryBytes(tx, bytesutil.ToBytes32(checkpoint.Root)) hasStateInDB := tx.Bucket(stateBucket).Get(checkpoint.Root) != nil if !(hasStateInDB || hasStateSummary) { log.Warnf("Recovering state summary for finalized root: %#x", bytesutil.Trunc(checkpoint.Root)) diff --git a/beacon-chain/db/kv/state_summary.go b/beacon-chain/db/kv/state_summary.go index 8c3e78eff6fc..351a0b49d62f 100644 --- a/beacon-chain/db/kv/state_summary.go +++ b/beacon-chain/db/kv/state_summary.go @@ -67,9 +67,14 @@ func (s *Store) HasStateSummary(ctx context.Context, blockRoot [32]byte) bool { ctx, span := trace.StartSpan(ctx, "BeaconDB.HasStateSummary") defer span.End() + if s.stateSummaryCache.has(blockRoot) { + return true + } + var hasSummary bool if err := s.db.View(func(tx *bolt.Tx) error { - hasSummary = s.hasStateSummaryBytes(tx, blockRoot) + enc := tx.Bucket(stateSummaryBucket).Get(blockRoot[:]) + hasSummary = len(enc) > 0 return nil }); err != nil { return false @@ -77,14 +82,6 @@ func (s *Store) HasStateSummary(ctx context.Context, blockRoot [32]byte) bool { return hasSummary } -func (s *Store) hasStateSummaryBytes(tx *bolt.Tx, blockRoot [32]byte) bool { - if s.stateSummaryCache.has(blockRoot) { - return true - } - enc := tx.Bucket(stateSummaryBucket).Get(blockRoot[:]) - return len(enc) > 0 -} - // This saves all cached state summary objects to DB, and clears up the cache. func (s *Store) saveCachedStateSummariesDB(ctx context.Context) error { summaries := s.stateSummaryCache.getAll() diff --git a/beacon-chain/db/kv/validated_checkpoint.go b/beacon-chain/db/kv/validated_checkpoint.go index 007855b3e45e..0ee20c66870c 100644 --- a/beacon-chain/db/kv/validated_checkpoint.go +++ b/beacon-chain/db/kv/validated_checkpoint.go @@ -38,9 +38,9 @@ func (s *Store) SaveLastValidatedCheckpoint(ctx context.Context, checkpoint *eth if err != nil { return err } + hasStateSummary := s.HasStateSummary(ctx, bytesutil.ToBytes32(checkpoint.Root)) return s.db.Update(func(tx *bolt.Tx) error { bucket := tx.Bucket(checkpointBucket) - hasStateSummary := s.hasStateSummaryBytes(tx, bytesutil.ToBytes32(checkpoint.Root)) hasStateInDB := tx.Bucket(stateBucket).Get(checkpoint.Root) != nil if !(hasStateInDB || hasStateSummary) { log.Warnf("Recovering state summary for last validated root: %#x", bytesutil.Trunc(checkpoint.Root)) diff --git a/beacon-chain/db/kv/validated_checkpoint_test.go b/beacon-chain/db/kv/validated_checkpoint_test.go index 59ea0ab33371..f264c9471572 100644 --- a/beacon-chain/db/kv/validated_checkpoint_test.go +++ b/beacon-chain/db/kv/validated_checkpoint_test.go @@ -51,6 +51,26 @@ func TestStore_LastValidatedCheckpoint_Recover(t *testing.T) { assert.Equal(t, true, proto.Equal(cp, retrieved), "Wanted %v, received %v", cp, retrieved) } +func BenchmarkStore_SaveLastValidatedCheckpoint(b *testing.B) { + db := setupDB(b) + ctx := context.Background() + root := bytesutil.ToBytes32([]byte{'A'}) + cp := ðpb.Checkpoint{ + Epoch: 10, + Root: root[:], + } + st, err := util.NewBeaconState() + require.NoError(b, err) + require.NoError(b, st.SetSlot(1)) + require.NoError(b, db.SaveState(ctx, st, root)) + db.stateSummaryCache.clear() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + require.NoError(b, db.SaveLastValidatedCheckpoint(ctx, cp)) + } +} + func TestStore_LastValidatedCheckpoint_DefaultIsFinalized(t *testing.T) { db := setupDB(t) ctx := context.Background()