diff --git a/beacon-chain/stategen/BUILD.bazel b/beacon-chain/stategen/BUILD.bazel index 543cdee5f33..f1610095774 100644 --- a/beacon-chain/stategen/BUILD.bazel +++ b/beacon-chain/stategen/BUILD.bazel @@ -23,11 +23,14 @@ go_test( srcs = ["replay_test.go"], embed = [":go_default_library"], deps = [ + "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/db:go_default_library", "//beacon-chain/db/testing:go_default_library", "//beacon-chain/state:go_default_library", "//proto/beacon/p2p/v1:go_default_library", "//shared/bytesutil:go_default_library", + "//shared/params:go_default_library", + "//shared/testutil:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_prysmaticlabs_go_ssz//:go_default_library", ], diff --git a/beacon-chain/stategen/replay.go b/beacon-chain/stategen/replay.go index 61a1842b194..85d36135d18 100644 --- a/beacon-chain/stategen/replay.go +++ b/beacon-chain/stategen/replay.go @@ -15,26 +15,19 @@ import ( func (s *State) replayBlocks(ctx context.Context, state *state.BeaconState, signed []*ethpb.SignedBeaconBlock, targetSlot uint64) (*state.BeaconState, error) { var err error // The input block list is sorted in decreasing slots order. - for i := len(signed) - 1; i >= 0; i-- { - // If there is skip slot. - for state.Slot() < signed[i].Block.Slot { - state, err = transition.ProcessSlot(ctx, state) + if len(signed) > 0 { + for i := len(signed) - 1; i >= 0; i-- { + state, err = transition.ExecuteStateTransitionNoVerifyAttSigs(ctx, state, signed[i]) if err != nil { return nil, err } } - state, err = transition.ProcessBlockNoVerifyAttSigs(ctx, state, signed[i]) - if err != nil { - return nil, err - } } // If there is skip slots at the end. - for state.Slot() < targetSlot { - state, err = transition.ProcessSlot(ctx, state) - if err != nil { - return nil, err - } + state, err = transition.ProcessSlots(ctx, state, targetSlot) + if err != nil { + return nil, err } return state, nil diff --git a/beacon-chain/stategen/replay_test.go b/beacon-chain/stategen/replay_test.go index 2b22bef6143..6c1028d80cc 100644 --- a/beacon-chain/stategen/replay_test.go +++ b/beacon-chain/stategen/replay_test.go @@ -7,13 +7,88 @@ import ( ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/go-ssz" + "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/db" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/bytesutil" + "github.com/prysmaticlabs/prysm/shared/params" + "github.com/prysmaticlabs/prysm/shared/testutil" ) +func TestReplayBlocks_AllSkipSlots(t *testing.T) { + db := testDB.SetupDB(t) + defer testDB.TeardownDB(t, db) + + beaconState, _ := testutil.DeterministicGenesisState(t, 32) + genesisBlock := blocks.NewGenesisBlock([]byte{}) + bodyRoot, err := ssz.HashTreeRoot(genesisBlock.Block) + if err != nil { + t.Fatal(err) + } + beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{ + Slot: genesisBlock.Block.Slot, + ParentRoot: genesisBlock.Block.ParentRoot, + StateRoot: params.BeaconConfig().ZeroHash[:], + BodyRoot: bodyRoot[:], + }) + beaconState.SetSlashings(make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)) + cp := beaconState.CurrentJustifiedCheckpoint() + mockRoot := [32]byte{} + copy(mockRoot[:], "hello-world") + cp.Root = mockRoot[:] + beaconState.SetCurrentJustifiedCheckpoint(cp) + beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}) + + service := New(db) + targetSlot := params.BeaconConfig().SlotsPerEpoch - 1 + newState, err := service.replayBlocks(context.Background(), beaconState, []*ethpb.SignedBeaconBlock{}, targetSlot) + if err != nil { + t.Fatal(err) + } + + if newState.Slot() != targetSlot { + t.Error("Did not advance slots") + } +} + +func TestReplayBlocks_SameSlot(t *testing.T) { + db := testDB.SetupDB(t) + defer testDB.TeardownDB(t, db) + + beaconState, _ := testutil.DeterministicGenesisState(t, 32) + genesisBlock := blocks.NewGenesisBlock([]byte{}) + bodyRoot, err := ssz.HashTreeRoot(genesisBlock.Block) + if err != nil { + t.Fatal(err) + } + beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{ + Slot: genesisBlock.Block.Slot, + ParentRoot: genesisBlock.Block.ParentRoot, + StateRoot: params.BeaconConfig().ZeroHash[:], + BodyRoot: bodyRoot[:], + }) + beaconState.SetSlashings(make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)) + cp := beaconState.CurrentJustifiedCheckpoint() + mockRoot := [32]byte{} + copy(mockRoot[:], "hello-world") + cp.Root = mockRoot[:] + beaconState.SetCurrentJustifiedCheckpoint(cp) + beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}) + + service := New(db) + targetSlot := beaconState.Slot() + newState, err := service.replayBlocks(context.Background(), beaconState, []*ethpb.SignedBeaconBlock{}, targetSlot) + if err != nil { + t.Fatal(err) + } + + if newState.Slot() != targetSlot { + t.Error("Did not advance slots") + } +} + func TestLoadBlocks_FirstBranch(t *testing.T) { db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db)