diff --git a/beacon-chain/blockchain/process_block.go b/beacon-chain/blockchain/process_block.go index 41bed94f1..fecea7899 100644 --- a/beacon-chain/blockchain/process_block.go +++ b/beacon-chain/blockchain/process_block.go @@ -305,6 +305,10 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf if err := s.updateFinalized(ctx, fCheckpoint); err != nil { return err } + if featureconfig.Get().UpdateHeadTimely { + s.prevFinalizedCheckpt = s.finalizedCheckpt + s.finalizedCheckpt = fCheckpoint + } } return nil } diff --git a/beacon-chain/blockchain/receive_block_test.go b/beacon-chain/blockchain/receive_block_test.go index f0b8c9612..fd659a725 100644 --- a/beacon-chain/blockchain/receive_block_test.go +++ b/beacon-chain/blockchain/receive_block_test.go @@ -8,6 +8,7 @@ import ( types "github.com/prysmaticlabs/eth2-types" blockchainTesting "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" + "github.com/prysmaticlabs/prysm/beacon-chain/core/state" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray" "github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations" @@ -17,6 +18,7 @@ import ( "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" "github.com/prysmaticlabs/prysm/proto/interfaces" "github.com/prysmaticlabs/prysm/shared/bytesutil" + "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" "github.com/prysmaticlabs/prysm/shared/testutil/assert" @@ -283,6 +285,62 @@ func TestService_ReceiveBlockBatch(t *testing.T) { } } +func TestService_ReceiveBlockBatch_UpdateFinalizedCheckpoint(t *testing.T) { + // Must enable head timely feature flag to test this. + resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{ + UpdateHeadTimely: true, + }) + defer resetCfg() + + ctx := context.Background() + genesis, keys := testutil.DeterministicGenesisState(t, 64) + + // Generate 5 epochs worth of blocks. + var blks []interfaces.SignedBeaconBlock + var roots [][32]byte + copied := genesis.Copy() + for i := types.Slot(1); i < params.BeaconConfig().SlotsPerEpoch*5; i++ { + b, err := testutil.GenerateFullBlock(copied, keys, testutil.DefaultBlockGenConfig(), i) + assert.NoError(t, err) + copied, err = state.ExecuteStateTransition(context.Background(), copied, wrapper.WrappedPhase0SignedBeaconBlock(b)) + assert.NoError(t, err) + r, err := b.Block.HashTreeRoot() + require.NoError(t, err) + blks = append(blks, wrapper.WrappedPhase0SignedBeaconBlock(b)) + roots = append(roots, r) + } + + beaconDB := testDB.SetupDB(t) + genesisBlockRoot, err := genesis.HashTreeRoot(ctx) + require.NoError(t, err) + cfg := &Config{ + BeaconDB: beaconDB, + ForkChoiceStore: protoarray.New( + 0, // justifiedEpoch + 0, // finalizedEpoch + genesisBlockRoot, + ), + StateNotifier: &blockchainTesting.MockStateNotifier{RecordEvents: false}, + StateGen: stategen.New(beaconDB), + } + s, err := NewService(ctx, cfg) + require.NoError(t, err) + err = s.saveGenesisData(ctx, genesis) + require.NoError(t, err) + gBlk, err := s.cfg.BeaconDB.GenesisBlock(ctx) + require.NoError(t, err) + + gRoot, err := gBlk.Block().HashTreeRoot() + require.NoError(t, err) + s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]} + + // Process 5 epochs worth of blocks. + require.NoError(t, s.ReceiveBlockBatch(ctx, blks, roots)) + + // Finalized epoch must be updated. + require.Equal(t, types.Epoch(2), s.finalizedCheckpt.Epoch) +} + func TestService_HasInitSyncBlock(t *testing.T) { s, err := NewService(context.Background(), &Config{StateNotifier: &blockchainTesting.MockStateNotifier{}}) require.NoError(t, err)