From 45118f81de12824eaa6c609f1fc23b117e06219e Mon Sep 17 00:00:00 2001 From: Potuz Date: Sat, 13 May 2023 07:46:12 -0300 Subject: [PATCH 1/2] Save to checkpoint cache if the nsc hits Also move the head check before the checkpoint cache check --- .../blockchain/process_attestation_helpers.go | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/beacon-chain/blockchain/process_attestation_helpers.go b/beacon-chain/blockchain/process_attestation_helpers.go index 9ab1ffd89ff3..5fdf5990c56b 100644 --- a/beacon-chain/blockchain/process_attestation_helpers.go +++ b/beacon-chain/blockchain/process_attestation_helpers.go @@ -20,6 +20,16 @@ import ( // getAttPreState retrieves the att pre state by either from the cache or the DB. func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (state.ReadOnlyBeaconState, error) { + // If the attestation is recent and canonical we can use the head state to compute the shuffling. + headEpoch := slots.ToEpoch(s.HeadSlot()) + if c.Epoch == headEpoch { + targetSlot, err := s.cfg.ForkChoiceStore.Slot([32]byte(c.Root)) + if err == nil && slots.ToEpoch(targetSlot)+1 >= headEpoch { + if s.cfg.ForkChoiceStore.IsCanonical([32]byte(c.Root)) { + return s.HeadStateReadOnly(ctx) + } + } + } // Use a multilock to allow scoped holding of a mutex by a checkpoint root + epoch // allowing us to behave smarter in terms of how this function is used concurrently. epochKey := strconv.FormatUint(uint64(c.Epoch), 10 /* base 10 */) @@ -33,17 +43,6 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (stat if cachedState != nil && !cachedState.IsNil() { return cachedState, nil } - // If the attestation is recent and canonical we can use the head state to compute the shuffling. - headEpoch := slots.ToEpoch(s.HeadSlot()) - if c.Epoch == headEpoch { - targetSlot, err := s.cfg.ForkChoiceStore.Slot([32]byte(c.Root)) - if err == nil && slots.ToEpoch(targetSlot)+1 >= headEpoch { - if s.cfg.ForkChoiceStore.IsCanonical([32]byte(c.Root)) { - return s.HeadStateReadOnly(ctx) - } - } - } - // Try the next slot cache for the early epoch calls, this should mostly have been covered already // but is cheap slot, err := slots.EpochStart(c.Epoch) @@ -52,12 +51,14 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (stat } cachedState = transition.NextSlotState(c.Root, slot) if cachedState != nil && !cachedState.IsNil() { - if cachedState.Slot() == slot { - return cachedState, nil + if cachedState.Slot() != slot { + cachedState, err = transition.ProcessSlots(ctx, cachedState, slot) + if err != nil { + return nil, errors.Wrap(err, "could not process slots") + } } - cachedState, err = transition.ProcessSlots(ctx, cachedState, slot) - if err != nil { - return nil, errors.Wrap(err, "could not process slots") + if err := s.checkpointStateCache.AddCheckpointState(c, cachedState); err != nil { + return nil, errors.Wrap(err, "could not save checkpoint state to cache") } return cachedState, nil } From a23572a48d670861d4b6219af32bf2c1b464f9bb Mon Sep 17 00:00:00 2001 From: Potuz Date: Sat, 13 May 2023 09:41:37 -0300 Subject: [PATCH 2/2] add unit test --- .../blockchain/process_attestation_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/beacon-chain/blockchain/process_attestation_test.go b/beacon-chain/blockchain/process_attestation_test.go index 7896f4a4a15e..22165cd575bc 100644 --- a/beacon-chain/blockchain/process_attestation_test.go +++ b/beacon-chain/blockchain/process_attestation_test.go @@ -328,3 +328,22 @@ func TestVerifyBeaconBlock_OK(t *testing.T) { assert.NoError(t, service.verifyBeaconBlock(ctx, d), "Did not receive the wanted error") } + +func TestGetAttPreState_HeadState(t *testing.T) { + service, tr := minimalTestService(t) + ctx := tr.ctx + baseState, _ := util.DeterministicGenesisState(t, 1) + + epoch := primitives.Epoch(1) + blk := util.NewBeaconBlock() + r1, err := blk.Block.HashTreeRoot() + require.NoError(t, err) + checkpoint := ðpb.Checkpoint{Epoch: epoch, Root: r1[:]} + require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(checkpoint.Root))) + require.NoError(t, transition.UpdateNextSlotCache(ctx, checkpoint.Root, baseState)) + _, err = service.getAttPreState(ctx, checkpoint) + require.NoError(t, err) + st, err := service.checkpointStateCache.StateByCheckpoint(checkpoint) + require.NoError(t, err) + require.Equal(t, params.BeaconConfig().SlotsPerEpoch, st.Slot()) +}