2020-03-12 02:27:16 +00:00
|
|
|
package stategen
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/hex"
|
|
|
|
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"go.opencensus.io/trace"
|
|
|
|
)
|
|
|
|
|
|
|
|
// MigrateToCold advances the split point in between the cold and hot state sections.
|
|
|
|
// It moves the recent finalized states from the hot section to the cold section and
|
|
|
|
// only preserve the ones that's on archived point.
|
2020-03-30 22:10:45 +00:00
|
|
|
func (s *State) MigrateToCold(ctx context.Context, finalizedSlot uint64, finalizedRoot [32]byte) error {
|
2020-03-12 02:27:16 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "stateGen.MigrateToCold")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
// Verify migration is sensible. The new finalized point must increase the current split slot, and
|
|
|
|
// on an epoch boundary for hot state summary scheme to work.
|
|
|
|
currentSplitSlot := s.splitInfo.slot
|
2020-03-30 22:10:45 +00:00
|
|
|
if currentSplitSlot > finalizedSlot {
|
2020-03-12 02:27:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-03-30 22:10:45 +00:00
|
|
|
// Migrate all state summary objects from cache to DB.
|
|
|
|
if err := s.beaconDB.SaveStateSummaries(ctx, s.stateSummaryCache.GetAll()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s.stateSummaryCache.Clear()
|
|
|
|
|
2020-04-11 20:54:19 +00:00
|
|
|
lastArchivedIndex, err := s.beaconDB.LastArchivedIndex(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-12 02:27:16 +00:00
|
|
|
// Move the states between split slot to finalized slot from hot section to the cold section.
|
2020-03-30 22:10:45 +00:00
|
|
|
filter := filters.NewFilter().SetStartSlot(currentSplitSlot).SetEndSlot(finalizedSlot - 1)
|
2020-03-12 02:27:16 +00:00
|
|
|
blockRoots, err := s.beaconDB.BlockRoots(ctx, filter)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, r := range blockRoots {
|
|
|
|
stateSummary, err := s.beaconDB.StateSummary(ctx, r)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if stateSummary == nil || stateSummary.Slot == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-03-16 19:07:07 +00:00
|
|
|
archivedPointIndex := stateSummary.Slot / s.slotsPerArchivedPoint
|
2020-04-11 20:54:19 +00:00
|
|
|
nextArchivedPointSlot := (lastArchivedIndex + 1) * s.slotsPerArchivedPoint
|
|
|
|
// Only migrate if current slot is equal to or greater than next archived point slot.
|
|
|
|
if stateSummary.Slot >= nextArchivedPointSlot {
|
2020-03-27 20:28:38 +00:00
|
|
|
if !s.beaconDB.HasState(ctx, r) {
|
|
|
|
recoveredArchivedState, err := s.ComputeStateUpToSlot(ctx, stateSummary.Slot)
|
2020-03-12 02:27:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-27 20:28:38 +00:00
|
|
|
if err := s.beaconDB.SaveState(ctx, recoveredArchivedState.Copy(), r); err != nil {
|
2020-03-12 02:27:16 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2020-03-16 19:07:07 +00:00
|
|
|
if err := s.beaconDB.SaveArchivedPointRoot(ctx, r, archivedPointIndex); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := s.beaconDB.SaveLastArchivedIndex(ctx, archivedPointIndex); err != nil {
|
2020-03-12 02:27:16 +00:00
|
|
|
return err
|
|
|
|
}
|
2020-04-11 20:54:19 +00:00
|
|
|
lastArchivedIndex++
|
2020-03-12 02:27:16 +00:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"slot": stateSummary.Slot,
|
2020-03-16 19:07:07 +00:00
|
|
|
"archiveIndex": archivedPointIndex,
|
2020-03-12 02:27:16 +00:00
|
|
|
"root": hex.EncodeToString(bytesutil.Trunc(r[:])),
|
|
|
|
}).Info("Saved archived point during state migration")
|
2020-03-27 20:28:38 +00:00
|
|
|
} else {
|
|
|
|
// Do not delete the current finalized state in case user wants to
|
|
|
|
// switch back to old state service, deleting the recent finalized state
|
|
|
|
// could cause issue switching back.
|
|
|
|
if s.beaconDB.HasState(ctx, r) && r != finalizedRoot {
|
|
|
|
if err := s.beaconDB.DeleteState(ctx, r); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"slot": stateSummary.Slot,
|
|
|
|
"root": hex.EncodeToString(bytesutil.Trunc(r[:])),
|
|
|
|
}).Info("Deleted state during migration")
|
2020-03-12 02:27:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the split slot and root.
|
2020-03-30 22:10:45 +00:00
|
|
|
s.splitInfo = &splitSlotAndRoot{slot: finalizedSlot, root: finalizedRoot}
|
2020-03-12 02:27:16 +00:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"slot": s.splitInfo.slot,
|
|
|
|
"root": hex.EncodeToString(bytesutil.Trunc(s.splitInfo.root[:])),
|
|
|
|
}).Info("Set hot and cold state split point")
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|