Skip to content

Commit

Permalink
Retrieve last ancestor state from DB. (Radical improvement from 5466) (
Browse files Browse the repository at this point in the history
…#5475)

* Add `lastAncestorState` method
* Add new tests and fix existing test
* Check context deadline exceeds
* Merge refs/heads/master into last-ancestor-state
* Merge refs/heads/master into last-ancestor-state
  • Loading branch information
terencechain authored Apr 18, 2020
1 parent ce6ce5a commit 62213ca
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 10 deletions.
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/process_attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func TestStore_OnAttestation(t *testing.T) {
a: &ethpb.Attestation{Data: &ethpb.AttestationData{Target: &ethpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}},
s: &pb.BeaconState{},
wantErr: true,
wantErrString: "could not get pre state for slot 0: could not get state summary",
wantErrString: "could not get pre state for slot 0: could not get ancestor state",
},
{
name: "process attestation doesn't match current epoch",
Expand Down
45 changes: 36 additions & 9 deletions beacon-chain/state/stategen/hot.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,9 @@ func (s *State) loadHotStateByRoot(ctx context.Context, blockRoot [32]byte) (*st

// Since the hot state is not in cache nor DB, start replaying using the parent state which is
// retrieved using input block's parent root.
blk, err := s.beaconDB.Block(ctx, blockRoot)
startState, err := s.lastAncestorState(ctx, blockRoot)
if err != nil {
return nil, err
}
if blk == nil {
return nil, errUnknownBlock
}
startState, err := s.loadHotStateByRoot(ctx, bytesutil.ToBytes32(blk.Block.ParentRoot))
if err != nil {
return nil, err
return nil, errors.Wrap(err, "could not get ancestor state")
}
if startState == nil {
return nil, errUnknownBoundaryState
Expand Down Expand Up @@ -139,3 +132,37 @@ func (s *State) loadHotStateBySlot(ctx context.Context, slot uint64) (*state.Bea

return s.ReplayBlocks(ctx, startState, replayBlks, slot)
}

// This returns the last saved in DB ancestor state of the input block root.
// It recursively look up block's parent until a corresponding state of the block root
// is found in the DB.
func (s *State) lastAncestorState(ctx context.Context, root [32]byte) (*state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "stateGen.lastAncestorState")
defer span.End()

b, err := s.beaconDB.Block(ctx, root)
if err != nil {
return nil, err
}
if b == nil {
return nil, errUnknownBlock
}

for {
if ctx.Err() != nil {
return nil, ctx.Err()
}
parentRoot := bytesutil.ToBytes32(b.Block.ParentRoot)
if s.beaconDB.HasState(ctx, parentRoot) {
return s.beaconDB.State(ctx, parentRoot)
}

b, err = s.beaconDB.Block(ctx, parentRoot)
if err != nil {
return nil, err
}
if b == nil {
return nil, errUnknownBlock
}
}
}
57 changes: 57 additions & 0 deletions beacon-chain/state/stategen/hot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,60 @@ func TestLoadHoteStateBySlot_CanAdvanceSlotUsingDB(t *testing.T) {
t.Error("Did not correctly load state")
}
}

func TestLastAncestorState_CanGet(t *testing.T) {
ctx := context.Background()
db := testDB.SetupDB(t)
defer testDB.TeardownDB(t, db)
service := New(db, cache.NewStateSummaryCache())

b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: []byte{'a'}}
r0, err := ssz.HashTreeRoot(b0)
if err != nil {
t.Fatal(err)
}
b1 := &ethpb.BeaconBlock{Slot: 1, ParentRoot: r0[:]}
r1, err := ssz.HashTreeRoot(b1)
if err != nil {
t.Fatal(err)
}
b2 := &ethpb.BeaconBlock{Slot: 2, ParentRoot: r1[:]}
r2, err := ssz.HashTreeRoot(b2)
if err != nil {
t.Fatal(err)
}
b3 := &ethpb.BeaconBlock{Slot: 3, ParentRoot: r2[:]}
r3, err := ssz.HashTreeRoot(b3)
if err != nil {
t.Fatal(err)
}

b1State := testutil.NewBeaconState()
if err := b1State.SetSlot(1); err != nil {
t.Fatal(err)
}

if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b0}); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b1}); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b2}); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b3}); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveState(ctx, b1State, r1); err != nil {
t.Fatal(err)
}

lastState, err := service.lastAncestorState(ctx, r3)
if err != nil {
t.Fatal(err)
}
if lastState.Slot() != b1State.Slot() {
t.Error("Did not get wanted state")
}
}

0 comments on commit 62213ca

Please sign in to comment.