diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index bac1c0f4a5c7..dd6cba229b0b 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -170,7 +170,7 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig // Send finalized events and finalized deposits in the background if newFinalized { finalized := s.cfg.ForkChoiceStore.FinalizedCheckpoint() - go s.sendNewFinalizedEvent(blockCopy, postState) + go s.sendNewFinalizedEvent(ctx, postState) depCtx, cancel := context.WithTimeout(context.Background(), depositDeadline) go func() { s.insertFinalizedDeposits(depCtx, finalized.Root) @@ -443,7 +443,7 @@ func (s *Service) updateFinalizationOnBlock(ctx context.Context, preState, postS // sendNewFinalizedEvent sends a new finalization checkpoint event over the // event feed. It needs to be called on the background -func (s *Service) sendNewFinalizedEvent(signed interfaces.ReadOnlySignedBeaconBlock, postState state.BeaconState) { +func (s *Service) sendNewFinalizedEvent(ctx context.Context, postState state.BeaconState) { isValidPayload := false s.headLock.RLock() if s.head != nil { @@ -451,8 +451,17 @@ func (s *Service) sendNewFinalizedEvent(signed interfaces.ReadOnlySignedBeaconBl } s.headLock.RUnlock() + blk, err := s.cfg.BeaconDB.Block(ctx, bytesutil.ToBytes32(postState.FinalizedCheckpoint().Root)) + if err != nil { + log.WithError(err).Error("Could not retrieve block for finalized checkpoint root. Finalized event will not be emitted") + return + } + if blk == nil || blk.IsNil() || blk.Block() == nil || blk.Block().IsNil() { + log.WithError(err).Error("Block retrieved for finalized checkpoint root is nil. Finalized event will not be emitted") + return + } + stateRoot := blk.Block().StateRoot() // Send an event regarding the new finalized checkpoint over a common event feed. - stateRoot := signed.Block().StateRoot() s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ Type: statefeed.FinalizedCheckpoint, Data: ðpbv1.EventFinalizedCheckpoint{ diff --git a/beacon-chain/blockchain/receive_block_test.go b/beacon-chain/blockchain/receive_block_test.go index bc952a531e15..9c065d767506 100644 --- a/beacon-chain/blockchain/receive_block_test.go +++ b/beacon-chain/blockchain/receive_block_test.go @@ -8,12 +8,14 @@ import ( blockchainTesting "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing" "github.com/prysmaticlabs/prysm/v5/beacon-chain/cache" + statefeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/state" "github.com/prysmaticlabs/prysm/v5/beacon-chain/das" "github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v5/testing/assert" "github.com/prysmaticlabs/prysm/v5/testing/require" @@ -378,3 +380,38 @@ func TestHandleBlockBLSToExecutionChanges(t *testing.T) { require.Equal(t, false, pool.ValidatorExists(idx)) }) } + +func Test_sendNewFinalizedEvent(t *testing.T) { + s, _ := minimalTestService(t) + notifier := &blockchainTesting.MockStateNotifier{RecordEvents: true} + s.cfg.StateNotifier = notifier + finalizedSt, err := util.NewBeaconState() + require.NoError(t, err) + finalizedStRoot, err := finalizedSt.HashTreeRoot(s.ctx) + require.NoError(t, err) + b := util.NewBeaconBlock() + b.Block.StateRoot = finalizedStRoot[:] + sbb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + sbbRoot, err := sbb.Block().HashTreeRoot() + require.NoError(t, err) + require.NoError(t, s.cfg.BeaconDB.SaveBlock(s.ctx, sbb)) + st, err := util.NewBeaconState() + require.NoError(t, err) + require.NoError(t, st.SetFinalizedCheckpoint(ðpb.Checkpoint{ + Epoch: 123, + Root: sbbRoot[:], + })) + + s.sendNewFinalizedEvent(s.ctx, st) + + require.Equal(t, 1, len(notifier.ReceivedEvents())) + e := notifier.ReceivedEvents()[0] + assert.Equal(t, statefeed.FinalizedCheckpoint, int(e.Type)) + fc, ok := e.Data.(*ethpbv1.EventFinalizedCheckpoint) + require.Equal(t, true, ok, "event has wrong data type") + assert.Equal(t, primitives.Epoch(123), fc.Epoch) + assert.DeepEqual(t, sbbRoot[:], fc.Block) + assert.DeepEqual(t, finalizedStRoot[:], fc.State) + assert.Equal(t, false, fc.ExecutionOptimistic) +}