Add hot state by slot retrival (#5052)

* Update replay conditions

* loadHotStateBySlot

* Tests and gaz

* Tests
This commit is contained in:
terence tsao 2020-03-09 17:22:45 +01:00 committed by GitHub
parent 0c3af32274
commit 25c13663d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 10 deletions

View File

@ -14,6 +14,7 @@ go_library(
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/cache:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/filters:go_default_library",

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"go.opencensus.io/trace"
@ -59,3 +60,45 @@ func (s *State) loadHotStateByRoot(ctx context.Context, blockRoot [32]byte) (*st
return hotState, nil
}
// This loads a hot state by slot where the slot lies between the epoch boundary points.
// This is a slower implementation (versus ByRoot) as slot is the only argument. It require fetching
// all the blocks between the epoch boundary points for playback.
// Use `loadHotStateByRoot` unless you really don't know the root.
func (s *State) loadHotStateBySlot(ctx context.Context, slot uint64) (*state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "stateGen.loadHotStateBySlot")
defer span.End()
// Gather epoch boundary information, that is where node starts to replay the blocks.
boundarySlot := helpers.StartSlot(helpers.SlotToEpoch(slot))
boundaryRoot, ok := s.epochBoundaryRoot(boundarySlot)
if !ok {
return nil, errUnknownBoundaryRoot
}
// Try the cache first then try the DB.
boundaryState := s.hotStateCache.Get(boundaryRoot)
var err error
if boundaryState == nil {
boundaryState, err = s.beaconDB.State(ctx, boundaryRoot)
if err != nil {
return nil, err
}
if boundaryState == nil {
return nil, errUnknownBoundaryState
}
}
// Gather the last saved block root and the slot number.
lastValidRoot, lastValidSlot, err := s.lastSavedBlock(ctx, slot)
if err != nil {
return nil, errors.Wrap(err, "could not get last valid block for hot state using slot")
}
// Load and replay blocks to get the intermediate state.
replayBlks, err := s.LoadBlocks(ctx, boundaryState.Slot()+1, lastValidSlot, lastValidRoot)
if err != nil {
return nil, err
}
return s.ReplayBlocks(ctx, boundaryState, replayBlks, slot)
}

View File

@ -94,3 +94,45 @@ func TestLoadHoteStateByRoot_FromDBBoundaryCase(t *testing.T) {
t.Error("Did not correctly load state")
}
}
func TestLoadHoteStateBySlot_CanAdvanceSlotUsingCache(t *testing.T) {
ctx := context.Background()
db := testDB.SetupDB(t)
defer testDB.TeardownDB(t, db)
service := New(db)
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
r := [32]byte{'A'}
service.hotStateCache.Put(r, beaconState)
service.setEpochBoundaryRoot(0, r)
slot := uint64(10)
loadedState, err := service.loadHotStateBySlot(ctx, slot)
if err != nil {
t.Fatal(err)
}
if loadedState.Slot() != slot {
t.Error("Did not correctly load state")
}
}
func TestLoadHoteStateBySlot_CanAdvanceSlotUsingDB(t *testing.T) {
ctx := context.Background()
db := testDB.SetupDB(t)
defer testDB.TeardownDB(t, db)
service := New(db)
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
r := [32]byte{'A'}
service.setEpochBoundaryRoot(0, r)
if err := service.beaconDB.SaveState(ctx, beaconState, r); err != nil {
t.Fatal(err)
}
slot := uint64(10)
loadedState, err := service.loadHotStateBySlot(ctx, slot)
if err != nil {
t.Fatal(err)
}
if loadedState.Slot() != slot {
t.Error("Did not correctly load state")
}
}

View File

@ -13,6 +13,7 @@ import (
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
"go.opencensus.io/trace"
)
@ -247,7 +248,8 @@ func (s *State) lastSavedBlock(ctx context.Context, slot uint64) ([32]byte, uint
return [32]byte{}, 0, err
}
if len(rs) == 0 {
return [32]byte{}, 0, errors.New("block root has 0 length")
// Return zero hash if there hasn't been any block in the DB yet.
return params.BeaconChainConfig{}.ZeroHash, 0, nil
}
lastRoot := rs[len(rs)-1]
@ -286,7 +288,8 @@ func (s *State) lastSavedState(ctx context.Context, slot uint64) ([32]byte, erro
return [32]byte{}, err
}
if len(rs) == 0 {
return [32]byte{}, errors.New("block root has 0 length")
// Return zero hash if there hasn't been any block in the DB yet.
return params.BeaconChainConfig{}.ZeroHash, nil
}
for i := len(rs) - 1; i >= 0; i-- {
// Stop until a state is saved.

View File

@ -415,7 +415,7 @@ func TestLastSavedBlock_CanGet(t *testing.T) {
}
}
func TestLastSavedBlock_OutOfRange(t *testing.T) {
func TestLastSavedBlock_NoSavedBlock(t *testing.T) {
db := testDB.SetupDB(t)
defer testDB.TeardownDB(t, db)
ctx := context.Background()
@ -429,9 +429,12 @@ func TestLastSavedBlock_OutOfRange(t *testing.T) {
t.Fatal(err)
}
_, _, err := s.lastSavedBlock(ctx, s.lastArchivedSlot+1)
if err.Error() != "block root has 0 length" {
t.Error("Did not get wanted error")
r, slot, err := s.lastSavedBlock(ctx, s.lastArchivedSlot+1)
if err != nil {
t.Fatal(err)
}
if slot != 0 || r != params.BeaconConfig().ZeroHash {
t.Error("Did not get no saved block info")
}
}
@ -504,7 +507,7 @@ func TestLastSavedState_CanGet(t *testing.T) {
}
}
func TestLastSavedState_OutOfRange(t *testing.T) {
func TestLastSavedState_NoSavedBlockState(t *testing.T) {
db := testDB.SetupDB(t)
defer testDB.TeardownDB(t, db)
ctx := context.Background()
@ -518,9 +521,12 @@ func TestLastSavedState_OutOfRange(t *testing.T) {
t.Fatal(err)
}
_, err := s.lastSavedState(ctx, s.lastArchivedSlot+1)
if err.Error() != "block root has 0 length" {
t.Error("Did not get wanted error")
r, err := s.lastSavedState(ctx, s.lastArchivedSlot+1)
if err != nil {
t.Fatal(err)
}
if r != params.BeaconConfig().ZeroHash {
t.Error("Did not get no saved block info")
}
}