Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Archived point retrieval and recovery (#5075)
- Loading branch information
1 parent
663d919
commit a90ffab
Showing
7 changed files
with
204 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package stategen | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/prysmaticlabs/prysm/beacon-chain/state" | ||
"go.opencensus.io/trace" | ||
) | ||
|
||
// Given the archive index, this returns the archived cold state in the DB. | ||
// If the archived state does not exist in the state, it'll compute it and save it. | ||
func (s *State) archivedPointByIndex(ctx context.Context, archiveIndex uint64) (*state.BeaconState, error) { | ||
ctx, span := trace.StartSpan(ctx, "stateGen.loadArchivedPointByIndex") | ||
defer span.End() | ||
if s.beaconDB.HasArchivedPoint(ctx, archiveIndex) { | ||
return s.beaconDB.ArchivedPointState(ctx, archiveIndex) | ||
} | ||
|
||
// If for certain reasons, archived point does not exist in DB, | ||
// a node should regenerate it and save it. | ||
return s.recoverArchivedPointByIndex(ctx, archiveIndex) | ||
} | ||
|
||
// This recovers an archived point by index. For certain reasons (ex. user toggles feature flag), | ||
// an archived point may not be present in the DB. This regenerates the archived point state via | ||
// playback and saves the archived root/state to the DB. | ||
func (s *State) recoverArchivedPointByIndex(ctx context.Context, archiveIndex uint64) (*state.BeaconState, error) { | ||
ctx, span := trace.StartSpan(ctx, "stateGen.recoverArchivedPointByIndex") | ||
defer span.End() | ||
|
||
archivedSlot := archiveIndex * s.slotsPerArchivedPoint | ||
archivedState, err := s.ComputeStateUpToSlot(ctx, archivedSlot) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "could not compute state up to archived index slot") | ||
} | ||
if archivedState == nil { | ||
return nil, errUnknownArchivedState | ||
} | ||
lastRoot, _, err := s.lastSavedBlock(ctx, archivedSlot) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "could not get last valid block up to archived index slot") | ||
} | ||
|
||
if err := s.beaconDB.SaveArchivedPointRoot(ctx, lastRoot, archiveIndex); err != nil { | ||
return nil, err | ||
} | ||
if err := s.beaconDB.SaveArchivedPointState(ctx, archivedState, archiveIndex); err != nil { | ||
return nil, err | ||
} | ||
|
||
return archivedState, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package stategen | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/gogo/protobuf/proto" | ||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" | ||
"github.com/prysmaticlabs/go-ssz" | ||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" | ||
"github.com/prysmaticlabs/prysm/shared/testutil" | ||
) | ||
|
||
func TestArchivedPointByIndex_HasPoint(t *testing.T) { | ||
ctx := context.Background() | ||
db := testDB.SetupDB(t) | ||
defer testDB.TeardownDB(t, db) | ||
|
||
service := New(db) | ||
beaconState, _ := testutil.DeterministicGenesisState(t, 32) | ||
index := uint64(999) | ||
if err := service.beaconDB.SaveArchivedPointState(ctx, beaconState, index); err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := service.beaconDB.SaveArchivedPointRoot(ctx, [32]byte{'A'}, index); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
savedArchivedState, err := service.archivedPointByIndex(ctx, index) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !proto.Equal(beaconState.InnerStateUnsafe(), savedArchivedState.InnerStateUnsafe()) { | ||
t.Error("Diff saved state") | ||
} | ||
} | ||
|
||
func TestArchivedPointByIndex_DoesntHavePoint(t *testing.T) { | ||
ctx := context.Background() | ||
db := testDB.SetupDB(t) | ||
defer testDB.TeardownDB(t, db) | ||
|
||
service := New(db) | ||
|
||
gBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}} | ||
gRoot, err := ssz.HashTreeRoot(gBlk.Block) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := service.beaconDB.SaveBlock(ctx, gBlk); err != nil { | ||
t.Fatal(err) | ||
} | ||
beaconState, _ := testutil.DeterministicGenesisState(t, 32) | ||
if err := service.beaconDB.SaveState(ctx, beaconState, gRoot); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
service.slotsPerArchivedPoint = 32 | ||
recoveredState, err := service.archivedPointByIndex(ctx, 2) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if recoveredState.Slot() != service.slotsPerArchivedPoint*2 { | ||
t.Error("Diff state slot") | ||
} | ||
savedArchivedState, err := service.beaconDB.ArchivedPointState(ctx, 2) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !proto.Equal(recoveredState.InnerStateUnsafe(), savedArchivedState.InnerStateUnsafe()) { | ||
t.Error("Diff saved archived state") | ||
} | ||
} | ||
|
||
func TestRecoverArchivedPointByIndex_CanRecover(t *testing.T) { | ||
ctx := context.Background() | ||
db := testDB.SetupDB(t) | ||
defer testDB.TeardownDB(t, db) | ||
|
||
service := New(db) | ||
|
||
gBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}} | ||
gRoot, err := ssz.HashTreeRoot(gBlk.Block) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := service.beaconDB.SaveBlock(ctx, gBlk); err != nil { | ||
t.Fatal(err) | ||
} | ||
beaconState, _ := testutil.DeterministicGenesisState(t, 32) | ||
if err := service.beaconDB.SaveState(ctx, beaconState, gRoot); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
service.slotsPerArchivedPoint = 32 | ||
recoveredState, err := service.recoverArchivedPointByIndex(ctx, 1) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if recoveredState.Slot() != service.slotsPerArchivedPoint { | ||
t.Error("Diff state slot") | ||
} | ||
savedArchivedState, err := service.beaconDB.ArchivedPointState(ctx, 1) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !proto.Equal(recoveredState.InnerStateUnsafe(), savedArchivedState.InnerStateUnsafe()) { | ||
t.Error("Diff saved state") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters