mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 19:40:37 +00:00
Remove invalid nodes (#10399)
This commit is contained in:
parent
83a83279d4
commit
3833f78803
@ -114,7 +114,7 @@ func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion, postSta
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not get execution payload")
|
||||
}
|
||||
_, err = s.cfg.ExecutionEngineCaller.NewPayload(ctx, payload)
|
||||
lastValidHash, err := s.cfg.ExecutionEngineCaller.NewPayload(ctx, payload)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case powchain.ErrAcceptedSyncingPayloadStatus:
|
||||
@ -123,6 +123,19 @@ func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion, postSta
|
||||
"blockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash)),
|
||||
}).Info("Called new payload with optimistic block")
|
||||
return false, nil
|
||||
case powchain.ErrInvalidPayloadStatus:
|
||||
root, err := blk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, root, bytesutil.ToBytes32(lastValidHash))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := s.removeInvalidBlockAndState(ctx, invalidRoots); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, errors.New("could not validate an INVALID payload from execution engine")
|
||||
default:
|
||||
return false, errors.Wrap(err, "could not validate execution payload from execution engine")
|
||||
}
|
||||
@ -174,3 +187,20 @@ func (s *Service) optimisticCandidateBlock(ctx context.Context, blk block.Beacon
|
||||
}
|
||||
return parentIsExecutionBlock, nil
|
||||
}
|
||||
|
||||
// removeInvalidBlockAndState removes the invalid block and its corresponding state from the cache and DB.
|
||||
func (s *Service) removeInvalidBlockAndState(ctx context.Context, blkRoots [][32]byte) error {
|
||||
for _, root := range blkRoots {
|
||||
if err := s.cfg.StateGen.DeleteStateFromCaches(ctx, root); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete block also deletes the state as well.
|
||||
if err := s.cfg.BeaconDB.DeleteBlock(ctx, root); err != nil {
|
||||
// TODO(10487): If a caller requests to delete a root that's justified and finalized. We should gracefully shutdown.
|
||||
// This is an irreparable condition, it would me a justified or finalized block has become invalid.
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -183,13 +183,6 @@ func Test_NotifyNewPayload(t *testing.T) {
|
||||
phase0State, _ := util.DeterministicGenesisState(t, 1)
|
||||
altairState, _ := util.DeterministicGenesisStateAltair(t, 1)
|
||||
bellatrixState, _ := util.DeterministicGenesisStateBellatrix(t, 2)
|
||||
blk := ðpb.SignedBeaconBlockBellatrix{
|
||||
Block: ðpb.BeaconBlockBellatrix{
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
ExecutionPayload: &v1.ExecutionPayload{},
|
||||
},
|
||||
},
|
||||
}
|
||||
a := ðpb.SignedBeaconBlockAltair{
|
||||
Block: ðpb.BeaconBlockAltair{
|
||||
Body: ðpb.BeaconBlockBodyAltair{},
|
||||
@ -197,10 +190,32 @@ func Test_NotifyNewPayload(t *testing.T) {
|
||||
}
|
||||
altairBlk, err := wrapper.WrappedSignedBeaconBlock(a)
|
||||
require.NoError(t, err)
|
||||
bellatrixBlk, err := wrapper.WrappedSignedBeaconBlock(blk)
|
||||
blk := ðpb.SignedBeaconBlockBellatrix{
|
||||
Block: ðpb.BeaconBlockBellatrix{
|
||||
Slot: 1,
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
ExecutionPayload: &v1.ExecutionPayload{
|
||||
BlockNumber: 1,
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
bellatrixBlk, err := wrapper.WrappedSignedBeaconBlock(util.HydrateSignedBeaconBlockBellatrix(blk))
|
||||
require.NoError(t, err)
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
r, err := bellatrixBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 0, [32]byte{}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0))
|
||||
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 1, r, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -244,7 +259,7 @@ func Test_NotifyNewPayload(t *testing.T) {
|
||||
preState: bellatrixState,
|
||||
blk: bellatrixBlk,
|
||||
newPayloadErr: powchain.ErrInvalidPayloadStatus,
|
||||
errString: "could not validate execution payload from execution engine: payload status is INVALID",
|
||||
errString: "could not validate an INVALID payload from execution engine",
|
||||
isValidPayload: false,
|
||||
},
|
||||
{
|
||||
@ -588,7 +603,6 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesisBlk := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
wr, err := wrapper.WrappedSignedBeaconBlock(genesisBlk)
|
||||
@ -671,3 +685,59 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
|
||||
require.DeepEqual(t, validCheckpoint.Root, cp.Root)
|
||||
require.Equal(t, validCheckpoint.Epoch, cp.Epoch)
|
||||
}
|
||||
|
||||
func TestService_removeInvalidBlockAndState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(protoarray.New(0, 0, [32]byte{})),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Deleting unknown block should not error.
|
||||
require.NoError(t, service.removeInvalidBlockAndState(ctx, [][32]byte{{'a'}, {'b'}, {'c'}}))
|
||||
|
||||
// Happy case
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
blk1, err := wrapper.WrappedSignedBeaconBlock(b1)
|
||||
require.NoError(t, err)
|
||||
r1, err := blk1.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, blk1))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{
|
||||
Slot: 1,
|
||||
Root: r1[:],
|
||||
}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st, r1))
|
||||
|
||||
b2 := util.NewBeaconBlock()
|
||||
b2.Block.Slot = 2
|
||||
blk2, err := wrapper.WrappedSignedBeaconBlock(b2)
|
||||
require.NoError(t, err)
|
||||
r2, err := blk2.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, blk2))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{
|
||||
Slot: 2,
|
||||
Root: r2[:],
|
||||
}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st, r2))
|
||||
|
||||
require.NoError(t, service.removeInvalidBlockAndState(ctx, [][32]byte{r1, r2}))
|
||||
|
||||
require.Equal(t, false, service.hasBlock(ctx, r1))
|
||||
require.Equal(t, false, service.hasBlock(ctx, r2))
|
||||
require.Equal(t, false, service.cfg.BeaconDB.HasStateSummary(ctx, r1))
|
||||
require.Equal(t, false, service.cfg.BeaconDB.HasStateSummary(ctx, r2))
|
||||
has, err := service.cfg.StateGen.HasState(ctx, r1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, has)
|
||||
has, err = service.cfg.StateGen.HasState(ctx, r2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, has)
|
||||
}
|
||||
|
@ -233,13 +233,17 @@ func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
|
||||
defer span.End()
|
||||
|
||||
if err := s.DeleteState(ctx, root); err != nil {
|
||||
return errDeleteFinalized
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.deleteStateSummary(root); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
if b := bkt.Get(root[:]); b != nil {
|
||||
return errDeleteFinalized
|
||||
return ErrDeleteJustifiedAndFinalized
|
||||
}
|
||||
|
||||
if err := tx.Bucket(blocksBucket).Delete(root[:]); err != nil {
|
||||
|
@ -191,6 +191,16 @@ func TestStore_DeleteBlock(t *testing.T) {
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*4, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
ss := make([]*ethpb.StateSummary, len(blks))
|
||||
for i, blk := range blks {
|
||||
r, err := blk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
ss[i] = ðpb.StateSummary{
|
||||
Slot: blk.Block().Slot(),
|
||||
Root: r[:],
|
||||
}
|
||||
}
|
||||
require.NoError(t, db.SaveStateSummaries(ctx, ss))
|
||||
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
@ -216,11 +226,50 @@ func TestStore_DeleteBlock(t *testing.T) {
|
||||
b, err = db.Block(ctx, root2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, b, nil)
|
||||
require.Equal(t, false, db.HasStateSummary(ctx, root2))
|
||||
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), errDeleteFinalized)
|
||||
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
}
|
||||
|
||||
func TestStore_DeleteJustifiedBlock(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Root: root[:],
|
||||
}
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
blk, err := wrapper.WrappedSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, blk))
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp))
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
}
|
||||
|
||||
func TestStore_DeleteFinalizedBlock(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
b := util.NewBeaconBlock()
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Root: root[:],
|
||||
}
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
blk, err := wrapper.WrappedSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, blk))
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
}
|
||||
func TestStore_GenesisBlock(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
@ -2,8 +2,8 @@ package kv
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
// errDeleteFinalized is raised when we attempt to delete a finalized block/state
|
||||
var errDeleteFinalized = errors.New("cannot delete finalized block or state")
|
||||
// ErrDeleteJustifiedAndFinalized is raised when we attempt to delete a finalized block/state
|
||||
var ErrDeleteJustifiedAndFinalized = errors.New("cannot delete finalized block or state")
|
||||
|
||||
// ErrNotFound can be used directly, or as a wrapped DBError, whenever a db method needs to
|
||||
// indicate that a value couldn't be found.
|
||||
|
@ -346,19 +346,31 @@ func (s *Store) DeleteState(ctx context.Context, blockRoot [32]byte) error {
|
||||
|
||||
bkt = tx.Bucket(checkpointBucket)
|
||||
enc := bkt.Get(finalizedCheckpointKey)
|
||||
checkpoint := ðpb.Checkpoint{}
|
||||
finalized := ðpb.Checkpoint{}
|
||||
if enc == nil {
|
||||
checkpoint = ðpb.Checkpoint{Root: genesisBlockRoot}
|
||||
} else if err := decode(ctx, enc, checkpoint); err != nil {
|
||||
finalized = ðpb.Checkpoint{Root: genesisBlockRoot}
|
||||
} else if err := decode(ctx, enc, finalized); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enc = bkt.Get(justifiedCheckpointKey)
|
||||
justified := ðpb.Checkpoint{}
|
||||
if enc == nil {
|
||||
justified = ðpb.Checkpoint{Root: genesisBlockRoot}
|
||||
} else if err := decode(ctx, enc, justified); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
blockBkt := tx.Bucket(blocksBucket)
|
||||
headBlkRoot := blockBkt.Get(headBlockRootKey)
|
||||
bkt = tx.Bucket(stateBucket)
|
||||
// Safe guard against deleting genesis, finalized, head state.
|
||||
if bytes.Equal(blockRoot[:], checkpoint.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], headBlkRoot) {
|
||||
return errors.New("cannot delete genesis, finalized, or head state")
|
||||
// Safeguard against deleting genesis, finalized, head state.
|
||||
if bytes.Equal(blockRoot[:], finalized.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], justified.Root) {
|
||||
return ErrDeleteJustifiedAndFinalized
|
||||
}
|
||||
|
||||
// Nothing to delete if state doesn't exist.
|
||||
enc = bkt.Get(blockRoot[:])
|
||||
if enc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
slot, err := s.slotByBlockRoot(ctx, tx, blockRoot[:])
|
||||
|
@ -110,3 +110,12 @@ func (s *Store) saveCachedStateSummariesDB(ctx context.Context) error {
|
||||
s.stateSummaryCache.clear()
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteStateSummary deletes a state summary object from the db using input block root.
|
||||
func (s *Store) deleteStateSummary(blockRoot [32]byte) error {
|
||||
s.stateSummaryCache.delete(blockRoot)
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(stateSummaryBucket)
|
||||
return bucket.Delete(blockRoot[:])
|
||||
})
|
||||
}
|
||||
|
@ -37,6 +37,13 @@ func (c *stateSummaryCache) has(r [32]byte) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// delete state summary in cache.
|
||||
func (c *stateSummaryCache) delete(r [32]byte) {
|
||||
c.initSyncStateSummariesLock.Lock()
|
||||
defer c.initSyncStateSummariesLock.Unlock()
|
||||
delete(c.initSyncStateSummaries, r)
|
||||
}
|
||||
|
||||
// get retrieves a state summary from the initial sync state summaries cache using the root of
|
||||
// the block.
|
||||
func (c *stateSummaryCache) get(r [32]byte) *ethpb.StateSummary {
|
||||
|
@ -62,3 +62,17 @@ func TestStateSummary_CacheToDB(t *testing.T) {
|
||||
require.Equal(t, true, db.HasStateSummary(context.Background(), bytesutil.ToBytes32(r)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateSummary_CanDelete(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
r1 := bytesutil.ToBytes32([]byte{'A'})
|
||||
s1 := ðpb.StateSummary{Slot: 1, Root: r1[:]}
|
||||
|
||||
require.Equal(t, false, db.HasStateSummary(ctx, r1), "State summary should not be saved")
|
||||
require.NoError(t, db.SaveStateSummary(ctx, s1))
|
||||
require.Equal(t, true, db.HasStateSummary(ctx, r1), "State summary should be saved")
|
||||
|
||||
require.NoError(t, db.deleteStateSummary(r1))
|
||||
require.Equal(t, false, db.HasStateSummary(ctx, r1), "State summary should not be saved")
|
||||
}
|
||||
|
@ -412,7 +412,7 @@ func TestStore_DeleteGenesisState(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(100))
|
||||
require.NoError(t, db.SaveState(ctx, st, genesisBlockRoot))
|
||||
wantedErr := "cannot delete genesis, finalized, or head state"
|
||||
wantedErr := "cannot delete finalized block or state"
|
||||
assert.ErrorContains(t, wantedErr, db.DeleteState(ctx, genesisBlockRoot))
|
||||
}
|
||||
|
||||
@ -440,7 +440,7 @@ func TestStore_DeleteFinalizedState(t *testing.T) {
|
||||
require.NoError(t, db.SaveState(ctx, finalizedState, finalizedBlockRoot))
|
||||
finalizedCheckpoint := ðpb.Checkpoint{Root: finalizedBlockRoot[:]}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, finalizedCheckpoint))
|
||||
wantedErr := "cannot delete genesis, finalized, or head state"
|
||||
wantedErr := "cannot delete finalized block or state"
|
||||
assert.ErrorContains(t, wantedErr, db.DeleteState(ctx, finalizedBlockRoot))
|
||||
}
|
||||
|
||||
@ -465,8 +465,7 @@ func TestStore_DeleteHeadState(t *testing.T) {
|
||||
require.NoError(t, st.SetSlot(100))
|
||||
require.NoError(t, db.SaveState(ctx, st, headBlockRoot))
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, headBlockRoot))
|
||||
wantedErr := "cannot delete genesis, finalized, or head state"
|
||||
assert.ErrorContains(t, wantedErr, db.DeleteState(ctx, headBlockRoot))
|
||||
require.NoError(t, db.DeleteState(ctx, headBlockRoot)) // Ok to delete head state if it's optimistic.
|
||||
}
|
||||
|
||||
func TestStore_SaveDeleteState_CanGetHighestBelow(t *testing.T) {
|
||||
|
@ -151,6 +151,15 @@ func (e *epochBoundaryState) put(r [32]byte, s state.BeaconState) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// delete the state from the epoch boundary state cache.
|
||||
func (e *epochBoundaryState) delete(r [32]byte) error {
|
||||
e.lock.Lock()
|
||||
defer e.lock.Unlock()
|
||||
return e.rootStateCache.Delete(&rootStateInfo{
|
||||
root: r,
|
||||
})
|
||||
}
|
||||
|
||||
// trim the FIFO queue to the maxSize.
|
||||
func trim(queue *cache.FIFO, maxSize uint64) {
|
||||
for s := uint64(len(queue.ListKeys())); s > maxSize; s-- {
|
||||
|
@ -19,7 +19,7 @@ func TestEpochBoundaryStateCache_BadRootKey(t *testing.T) {
|
||||
assert.ErrorContains(t, errNotRootStateInfo.Error(), err, "Did not get wanted error")
|
||||
}
|
||||
|
||||
func TestEpochBoundaryStateCache_CanSave(t *testing.T) {
|
||||
func TestEpochBoundaryStateCache_CanSaveAndDelete(t *testing.T) {
|
||||
e := newBoundaryStateCache()
|
||||
s, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
@ -46,6 +46,17 @@ func TestEpochBoundaryStateCache_CanSave(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, exists, "Should exist")
|
||||
assert.DeepSSZEqual(t, s.InnerStateUnsafe(), got.state.InnerStateUnsafe(), "Should have the same state")
|
||||
|
||||
require.NoError(t, e.delete(r))
|
||||
got, exists, err = e.getByRoot([32]byte{'b'})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, exists, "Should not exist")
|
||||
assert.Equal(t, (*rootStateInfo)(nil), got, "Should not exist")
|
||||
|
||||
got, exists, err = e.getBySlot(1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, exists, "Should not exist")
|
||||
assert.Equal(t, (*rootStateInfo)(nil), got, "Should not exist")
|
||||
}
|
||||
|
||||
func TestEpochBoundaryStateCache_CanTrim(t *testing.T) {
|
||||
|
@ -39,7 +39,7 @@ func (s *State) HasStateInCache(ctx context.Context, blockRoot [32]byte) (bool,
|
||||
return has, nil
|
||||
}
|
||||
|
||||
// StateByRootIfCached retrieves a state using the input block root only if the state is already in the cache
|
||||
// StateByRootIfCachedNoCopy retrieves a state using the input block root only if the state is already in the cache
|
||||
func (s *State) StateByRootIfCachedNoCopy(blockRoot [32]byte) state.BeaconState {
|
||||
if !s.hotStateCache.has(blockRoot) {
|
||||
return nil
|
||||
@ -146,6 +146,12 @@ func (s *State) RecoverStateSummary(ctx context.Context, blockRoot [32]byte) (*e
|
||||
return nil, errors.New("could not find block in DB")
|
||||
}
|
||||
|
||||
// DeleteStateFromCaches deletes the state from the caches.
|
||||
func (s *State) DeleteStateFromCaches(_ context.Context, blockRoot [32]byte) error {
|
||||
s.hotStateCache.delete(blockRoot)
|
||||
return s.epochBoundaryStateCache.delete(blockRoot)
|
||||
}
|
||||
|
||||
// This loads a beacon state from either the cache or DB then replay blocks up the requested block root.
|
||||
func (s *State) loadStateByRoot(ctx context.Context, blockRoot [32]byte) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "stateGen.loadStateByRoot")
|
||||
|
@ -165,6 +165,35 @@ func TestStateByRoot_HotStateCached(t *testing.T) {
|
||||
require.DeepSSZEqual(t, loadedState.InnerStateUnsafe(), beaconState.InnerStateUnsafe())
|
||||
}
|
||||
|
||||
func TestDeleteStateFromCaches(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
service := New(beaconDB)
|
||||
beaconState, _ := util.DeterministicGenesisState(t, 32)
|
||||
r := [32]byte{'A'}
|
||||
|
||||
require.Equal(t, false, service.hotStateCache.has(r))
|
||||
_, has, err := service.epochBoundaryStateCache.getByRoot(r)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, has)
|
||||
|
||||
service.hotStateCache.put(r, beaconState)
|
||||
require.NoError(t, service.epochBoundaryStateCache.put(r, beaconState))
|
||||
|
||||
require.Equal(t, true, service.hotStateCache.has(r))
|
||||
_, has, err = service.epochBoundaryStateCache.getByRoot(r)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, has)
|
||||
|
||||
require.NoError(t, service.DeleteStateFromCaches(ctx, r))
|
||||
|
||||
require.Equal(t, false, service.hotStateCache.has(r))
|
||||
_, has, err = service.epochBoundaryStateCache.getByRoot(r)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, has)
|
||||
}
|
||||
|
||||
func TestStateByRoot_StateByRootInitialSync(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
@ -23,7 +23,7 @@ func NewMockService() *MockStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// StateByRootIfCached
|
||||
// StateByRootIfCachedNoCopy
|
||||
func (_ *MockStateManager) StateByRootIfCachedNoCopy(_ [32]byte) state.BeaconState {
|
||||
panic("implement me")
|
||||
}
|
||||
@ -124,3 +124,8 @@ func (m *MockStateManager) AddStateForRoot(state state.BeaconState, blockRoot [3
|
||||
func (m *MockStateManager) AddStateForSlot(state state.BeaconState, slot types.Slot) {
|
||||
m.StatesBySlot[slot] = state
|
||||
}
|
||||
|
||||
// DeleteStateFromCaches --
|
||||
func (m *MockStateManager) DeleteStateFromCaches(context.Context, [32]byte) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ type StateManager interface {
|
||||
ForceCheckpoint(ctx context.Context, root []byte) error
|
||||
EnableSaveHotStateToDB(_ context.Context)
|
||||
DisableSaveHotStateToDB(ctx context.Context) error
|
||||
DeleteStateFromCaches(ctx context.Context, blockRoot [32]byte) error
|
||||
}
|
||||
|
||||
// State is a concrete implementation of StateManager.
|
||||
|
Loading…
Reference in New Issue
Block a user