github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/blockchain/chain_info.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
    10  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    11  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    12  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    13  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    14  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    15  	"github.com/prysmaticlabs/prysm/shared/copyutil"
    16  	"github.com/prysmaticlabs/prysm/shared/params"
    17  	"go.opencensus.io/trace"
    18  )
    19  
    20  // ChainInfoFetcher defines a common interface for methods in blockchain service which
    21  // directly retrieves chain info related data.
    22  type ChainInfoFetcher interface {
    23  	HeadFetcher
    24  	FinalizationFetcher
    25  	GenesisFetcher
    26  	CanonicalFetcher
    27  	ForkFetcher
    28  }
    29  
    30  // TimeFetcher retrieves the Ethereum consensus data that's related to time.
    31  type TimeFetcher interface {
    32  	GenesisTime() time.Time
    33  	CurrentSlot() types.Slot
    34  }
    35  
    36  // GenesisFetcher retrieves the Ethereum consensus data related to its genesis.
    37  type GenesisFetcher interface {
    38  	GenesisValidatorRoot() [32]byte
    39  }
    40  
    41  // HeadFetcher defines a common interface for methods in blockchain service which
    42  // directly retrieves head related data.
    43  type HeadFetcher interface {
    44  	HeadSlot() types.Slot
    45  	HeadRoot(ctx context.Context) ([]byte, error)
    46  	HeadBlock(ctx context.Context) (interfaces.SignedBeaconBlock, error)
    47  	HeadState(ctx context.Context) (iface.BeaconState, error)
    48  	HeadValidatorsIndices(ctx context.Context, epoch types.Epoch) ([]types.ValidatorIndex, error)
    49  	HeadSeed(ctx context.Context, epoch types.Epoch) ([32]byte, error)
    50  	HeadGenesisValidatorRoot() [32]byte
    51  	HeadETH1Data() *ethpb.Eth1Data
    52  	ProtoArrayStore() *protoarray.Store
    53  	ChainHeads() ([][32]byte, []types.Slot)
    54  }
    55  
    56  // ForkFetcher retrieves the current fork information of the Ethereum beacon chain.
    57  type ForkFetcher interface {
    58  	CurrentFork() *pb.Fork
    59  }
    60  
    61  // CanonicalFetcher retrieves the current chain's canonical information.
    62  type CanonicalFetcher interface {
    63  	IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error)
    64  	VerifyBlkDescendant(ctx context.Context, blockRoot [32]byte) error
    65  }
    66  
    67  // FinalizationFetcher defines a common interface for methods in blockchain service which
    68  // directly retrieves finalization and justification related data.
    69  type FinalizationFetcher interface {
    70  	FinalizedCheckpt() *ethpb.Checkpoint
    71  	CurrentJustifiedCheckpt() *ethpb.Checkpoint
    72  	PreviousJustifiedCheckpt() *ethpb.Checkpoint
    73  }
    74  
    75  // FinalizedCheckpt returns the latest finalized checkpoint from head state.
    76  func (s *Service) FinalizedCheckpt() *ethpb.Checkpoint {
    77  	if s.finalizedCheckpt == nil {
    78  		return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
    79  	}
    80  
    81  	return copyutil.CopyCheckpoint(s.finalizedCheckpt)
    82  }
    83  
    84  // CurrentJustifiedCheckpt returns the current justified checkpoint from head state.
    85  func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint {
    86  	if s.justifiedCheckpt == nil {
    87  		return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
    88  	}
    89  
    90  	return copyutil.CopyCheckpoint(s.justifiedCheckpt)
    91  }
    92  
    93  // PreviousJustifiedCheckpt returns the previous justified checkpoint from head state.
    94  func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint {
    95  	if s.prevJustifiedCheckpt == nil {
    96  		return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
    97  	}
    98  
    99  	return copyutil.CopyCheckpoint(s.prevJustifiedCheckpt)
   100  }
   101  
   102  // HeadSlot returns the slot of the head of the chain.
   103  func (s *Service) HeadSlot() types.Slot {
   104  	s.headLock.RLock()
   105  	defer s.headLock.RUnlock()
   106  
   107  	if !s.hasHeadState() {
   108  		return 0
   109  	}
   110  
   111  	return s.headSlot()
   112  }
   113  
   114  // HeadRoot returns the root of the head of the chain.
   115  func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
   116  	s.headLock.RLock()
   117  	defer s.headLock.RUnlock()
   118  
   119  	if s.headRoot() != params.BeaconConfig().ZeroHash {
   120  		r := s.headRoot()
   121  		return r[:], nil
   122  	}
   123  
   124  	b, err := s.cfg.BeaconDB.HeadBlock(ctx)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	if b == nil || b.IsNil() {
   129  		return params.BeaconConfig().ZeroHash[:], nil
   130  	}
   131  
   132  	r, err := b.Block().HashTreeRoot()
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	return r[:], nil
   138  }
   139  
   140  // HeadBlock returns the head block of the chain.
   141  // If the head is nil from service struct,
   142  // it will attempt to get the head block from DB.
   143  func (s *Service) HeadBlock(ctx context.Context) (interfaces.SignedBeaconBlock, error) {
   144  	s.headLock.RLock()
   145  	defer s.headLock.RUnlock()
   146  
   147  	if s.hasHeadState() {
   148  		return s.headBlock(), nil
   149  	}
   150  
   151  	return s.cfg.BeaconDB.HeadBlock(ctx)
   152  }
   153  
   154  // HeadState returns the head state of the chain.
   155  // If the head is nil from service struct,
   156  // it will attempt to get the head state from DB.
   157  func (s *Service) HeadState(ctx context.Context) (iface.BeaconState, error) {
   158  	ctx, span := trace.StartSpan(ctx, "blockChain.HeadState")
   159  	defer span.End()
   160  	s.headLock.RLock()
   161  	defer s.headLock.RUnlock()
   162  
   163  	ok := s.hasHeadState()
   164  	span.AddAttributes(trace.BoolAttribute("cache_hit", ok))
   165  
   166  	if ok {
   167  		return s.headState(ctx), nil
   168  	}
   169  
   170  	return s.cfg.StateGen.StateByRoot(ctx, s.headRoot())
   171  }
   172  
   173  // HeadValidatorsIndices returns a list of active validator indices from the head view of a given epoch.
   174  func (s *Service) HeadValidatorsIndices(ctx context.Context, epoch types.Epoch) ([]types.ValidatorIndex, error) {
   175  	s.headLock.RLock()
   176  	defer s.headLock.RUnlock()
   177  
   178  	if !s.hasHeadState() {
   179  		return []types.ValidatorIndex{}, nil
   180  	}
   181  	return helpers.ActiveValidatorIndices(s.headState(ctx), epoch)
   182  }
   183  
   184  // HeadSeed returns the seed from the head view of a given epoch.
   185  func (s *Service) HeadSeed(ctx context.Context, epoch types.Epoch) ([32]byte, error) {
   186  	s.headLock.RLock()
   187  	defer s.headLock.RUnlock()
   188  
   189  	if !s.hasHeadState() {
   190  		return [32]byte{}, nil
   191  	}
   192  
   193  	return helpers.Seed(s.headState(ctx), epoch, params.BeaconConfig().DomainBeaconAttester)
   194  }
   195  
   196  // HeadGenesisValidatorRoot returns genesis validator root of the head state.
   197  func (s *Service) HeadGenesisValidatorRoot() [32]byte {
   198  	s.headLock.RLock()
   199  	defer s.headLock.RUnlock()
   200  
   201  	if !s.hasHeadState() {
   202  		return [32]byte{}
   203  	}
   204  
   205  	return s.headGenesisValidatorRoot()
   206  }
   207  
   208  // HeadETH1Data returns the eth1data of the current head state.
   209  func (s *Service) HeadETH1Data() *ethpb.Eth1Data {
   210  	s.headLock.RLock()
   211  	defer s.headLock.RUnlock()
   212  
   213  	if !s.hasHeadState() {
   214  		return &ethpb.Eth1Data{}
   215  	}
   216  	return s.head.state.Eth1Data()
   217  }
   218  
   219  // ProtoArrayStore returns the proto array store object.
   220  func (s *Service) ProtoArrayStore() *protoarray.Store {
   221  	return s.cfg.ForkChoiceStore.Store()
   222  }
   223  
   224  // GenesisTime returns the genesis time of beacon chain.
   225  func (s *Service) GenesisTime() time.Time {
   226  	return s.genesisTime
   227  }
   228  
   229  // GenesisValidatorRoot returns the genesis validator
   230  // root of the chain.
   231  func (s *Service) GenesisValidatorRoot() [32]byte {
   232  	s.headLock.RLock()
   233  	defer s.headLock.RUnlock()
   234  
   235  	if !s.hasHeadState() {
   236  		return [32]byte{}
   237  	}
   238  	return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot())
   239  }
   240  
   241  // CurrentFork retrieves the latest fork information of the beacon chain.
   242  func (s *Service) CurrentFork() *pb.Fork {
   243  	s.headLock.RLock()
   244  	defer s.headLock.RUnlock()
   245  
   246  	if !s.hasHeadState() {
   247  		return &pb.Fork{
   248  			PreviousVersion: params.BeaconConfig().GenesisForkVersion,
   249  			CurrentVersion:  params.BeaconConfig().GenesisForkVersion,
   250  		}
   251  	}
   252  	return s.head.state.Fork()
   253  }
   254  
   255  // IsCanonical returns true if the input block root is part of the canonical chain.
   256  func (s *Service) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error) {
   257  	// If the block has been finalized, the block will always be part of the canonical chain.
   258  	if s.cfg.BeaconDB.IsFinalizedBlock(ctx, blockRoot) {
   259  		return true, nil
   260  	}
   261  
   262  	// If the block has not been finalized, check fork choice store to see if the block is canonical
   263  	return s.cfg.ForkChoiceStore.IsCanonical(blockRoot), nil
   264  }
   265  
   266  // ChainHeads returns all possible chain heads (leaves of fork choice tree).
   267  // Heads roots and heads slots are returned.
   268  func (s *Service) ChainHeads() ([][32]byte, []types.Slot) {
   269  	nodes := s.ProtoArrayStore().Nodes()
   270  
   271  	// Deliberate choice to not preallocate space for below.
   272  	// Heads cant be more than 2-3 in the worst case where pre-allocation will be 64 to begin with.
   273  	headsRoots := make([][32]byte, 0)
   274  	headsSlots := make([]types.Slot, 0)
   275  
   276  	nonExistentNode := ^uint64(0)
   277  	for _, node := range nodes {
   278  		// Possible heads have no children.
   279  		if node.BestDescendant() == nonExistentNode && node.BestChild() == nonExistentNode {
   280  			headsRoots = append(headsRoots, node.Root())
   281  			headsSlots = append(headsSlots, node.Slot())
   282  		}
   283  	}
   284  
   285  	return headsRoots, headsSlots
   286  }