diff --git a/beacon-chain/blockchain/chain_info.go b/beacon-chain/blockchain/chain_info.go index 5c53d4582..7fbfb10e3 100644 --- a/beacon-chain/blockchain/chain_info.go +++ b/beacon-chain/blockchain/chain_info.go @@ -54,6 +54,7 @@ type HeadFetcher interface { HeadValidatorIndexToPublicKey(ctx context.Context, index types.ValidatorIndex) ([fieldparams.BLSPubkeyLength]byte, error) ProtoArrayStore() *protoarray.Store ChainHeads() ([][32]byte, []types.Slot) + IsOptimistic(ctx context.Context) (bool, error) HeadSyncCommitteeFetcher HeadDomainFetcher } @@ -328,6 +329,13 @@ func (s *Service) HeadValidatorIndexToPublicKey(_ context.Context, index types.V return v.PublicKey(), nil } +// IsOptimistic returns true if the current head is optimistic. +func (s *Service) IsOptimistic(ctx context.Context) (bool, error) { + s.headLock.RLock() + defer s.headLock.RUnlock() + return s.cfg.ForkChoiceStore.Optimistic(ctx, s.head.root, s.head.slot) +} + // SetGenesisTime sets the genesis time of beacon chain. func (s *Service) SetGenesisTime(t time.Time) { s.genesisTime = t diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index f31d17825..7fa00e47c 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -355,3 +355,14 @@ func TestService_HeadValidatorIndexToPublicKeyNil(t *testing.T) { require.NoError(t, err) require.Equal(t, [fieldparams.BLSPubkeyLength]byte{}, p) } + +func TestService_IsOptimistic(t *testing.T) { + ctx := context.Background() + c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}} + require.NoError(t, c.cfg.ForkChoiceStore.ProcessBlock(ctx, 100, [32]byte{'a'}, [32]byte{}, [32]byte{}, 0, 0)) + require.NoError(t, c.cfg.ForkChoiceStore.ProcessBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{}, 0, 0)) + + opt, err := c.IsOptimistic(ctx) + require.NoError(t, err) + require.Equal(t, true, opt) +} diff --git a/beacon-chain/blockchain/testing/mock.go b/beacon-chain/blockchain/testing/mock.go index f41a5847b..4a120669e 100644 --- a/beacon-chain/blockchain/testing/mock.go +++ b/beacon-chain/blockchain/testing/mock.go @@ -438,3 +438,8 @@ func (s *ChainService) HeadSyncSelectionProofDomain(_ context.Context, _ types.S func (s *ChainService) HeadSyncContributionProofDomain(_ context.Context, _ types.Slot) ([]byte, error) { return s.SyncContributionProofDomain, nil } + +// IsOptimistic mocks the same method in the chain service. +func (s *ChainService) IsOptimistic(_ context.Context) (bool, error) { + return false, nil +} diff --git a/beacon-chain/forkchoice/interfaces.go b/beacon-chain/forkchoice/interfaces.go index cf3ad391e..a1729e743 100644 --- a/beacon-chain/forkchoice/interfaces.go +++ b/beacon-chain/forkchoice/interfaces.go @@ -18,9 +18,10 @@ type ForkChoicer interface { ProposerBooster // ability to boost timely-proposed block roots. } -// HeadRetriever retrieves head root of the current chain. +// HeadRetriever retrieves head root and optimistic info of the current chain. type HeadRetriever interface { Head(context.Context, types.Epoch, [32]byte, []uint64, types.Epoch) ([32]byte, error) + Optimistic(ctx context.Context, root [32]byte, slot types.Slot) (bool, error) } // BlockProcessor processes the block that's used for accounting fork choice.