github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/interop-cold-start/service.go (about)

     1  // Package interopcoldstart allows for spinning up a deterministic
     2  // local chain without the need for eth1 deposits useful for
     3  // local client development and interoperability testing.
     4  package interopcoldstart
     5  
     6  import (
     7  	"context"
     8  	"io/ioutil"
     9  	"math/big"
    10  	"time"
    11  
    12  	types "github.com/prysmaticlabs/eth2-types"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
    14  	"github.com/prysmaticlabs/prysm/beacon-chain/db"
    15  	"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
    16  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    18  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    19  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    20  	"github.com/prysmaticlabs/prysm/shared"
    21  	"github.com/prysmaticlabs/prysm/shared/interop"
    22  	"github.com/prysmaticlabs/prysm/shared/slotutil"
    23  )
    24  
    25  var _ shared.Service = (*Service)(nil)
    26  var _ depositcache.DepositFetcher = (*Service)(nil)
    27  var _ powchain.ChainStartFetcher = (*Service)(nil)
    28  
    29  // Service spins up an client interoperability service that handles responsibilities such
    30  // as kickstarting a genesis state for the beacon node from cli flags or a genesis.ssz file.
    31  type Service struct {
    32  	cfg                *Config
    33  	ctx                context.Context
    34  	cancel             context.CancelFunc
    35  	chainStartDeposits []*ethpb.Deposit
    36  }
    37  
    38  // Config options for the interop service.
    39  type Config struct {
    40  	GenesisTime   uint64
    41  	NumValidators uint64
    42  	BeaconDB      db.HeadAccessDatabase
    43  	DepositCache  *depositcache.DepositCache
    44  	GenesisPath   string
    45  }
    46  
    47  // NewService is an interoperability testing service to inject a deterministically generated genesis state
    48  // into the beacon chain database and running services at start up. This service should not be used in production
    49  // as it does not have any value other than ease of use for testing purposes.
    50  func NewService(ctx context.Context, cfg *Config) *Service {
    51  	log.Warn("Saving generated genesis state in database for interop testing")
    52  	ctx, cancel := context.WithCancel(ctx)
    53  
    54  	s := &Service{
    55  		cfg:    cfg,
    56  		ctx:    ctx,
    57  		cancel: cancel,
    58  	}
    59  
    60  	if s.cfg.GenesisPath != "" {
    61  		data, err := ioutil.ReadFile(s.cfg.GenesisPath)
    62  		if err != nil {
    63  			log.Fatalf("Could not read pre-loaded state: %v", err)
    64  		}
    65  		genesisState := &pb.BeaconState{}
    66  		if err := genesisState.UnmarshalSSZ(data); err != nil {
    67  			log.Fatalf("Could not unmarshal pre-loaded state: %v", err)
    68  		}
    69  		genesisTrie, err := v1.InitializeFromProto(genesisState)
    70  		if err != nil {
    71  			log.Fatalf("Could not get state trie: %v", err)
    72  		}
    73  		if err := s.saveGenesisState(ctx, genesisTrie); err != nil {
    74  			log.Fatalf("Could not save interop genesis state %v", err)
    75  		}
    76  		return s
    77  	}
    78  
    79  	// Save genesis state in db
    80  	genesisState, _, err := interop.GenerateGenesisState(ctx, s.cfg.GenesisTime, s.cfg.NumValidators)
    81  	if err != nil {
    82  		log.Fatalf("Could not generate interop genesis state: %v", err)
    83  	}
    84  	genesisTrie, err := v1.InitializeFromProto(genesisState)
    85  	if err != nil {
    86  		log.Fatalf("Could not get state trie: %v", err)
    87  	}
    88  	if s.cfg.GenesisTime == 0 {
    89  		// Generated genesis time; fetch it
    90  		s.cfg.GenesisTime = genesisTrie.GenesisTime()
    91  	}
    92  	gRoot, err := genesisTrie.HashTreeRoot(s.ctx)
    93  	if err != nil {
    94  		log.Fatalf("Could not hash tree root genesis state: %v", err)
    95  	}
    96  	go slotutil.CountdownToGenesis(ctx, time.Unix(int64(s.cfg.GenesisTime), 0), s.cfg.NumValidators, gRoot)
    97  
    98  	if err := s.saveGenesisState(ctx, genesisTrie); err != nil {
    99  		log.Fatalf("Could not save interop genesis state %v", err)
   100  	}
   101  
   102  	return s
   103  }
   104  
   105  // Start initializes the genesis state from configured flags.
   106  func (s *Service) Start() {
   107  }
   108  
   109  // Stop does nothing.
   110  func (s *Service) Stop() error {
   111  	return nil
   112  }
   113  
   114  // Status always returns nil.
   115  func (s *Service) Status() error {
   116  	return nil
   117  }
   118  
   119  // AllDeposits mocks out the deposit cache functionality for interop.
   120  func (s *Service) AllDeposits(_ context.Context, _ *big.Int) []*ethpb.Deposit {
   121  	return []*ethpb.Deposit{}
   122  }
   123  
   124  // ChainStartDeposits mocks out the powchain functionality for interop.
   125  func (s *Service) ChainStartDeposits() []*ethpb.Deposit {
   126  	return s.chainStartDeposits
   127  }
   128  
   129  // ChainStartEth1Data mocks out the powchain functionality for interop.
   130  func (s *Service) ChainStartEth1Data() *ethpb.Eth1Data {
   131  	return &ethpb.Eth1Data{}
   132  }
   133  
   134  // PreGenesisState returns an empty beacon state.
   135  func (s *Service) PreGenesisState() iface.BeaconState {
   136  	return &v1.BeaconState{}
   137  }
   138  
   139  // ClearPreGenesisData --
   140  func (s *Service) ClearPreGenesisData() {
   141  	// no-op
   142  }
   143  
   144  // DepositByPubkey mocks out the deposit cache functionality for interop.
   145  func (s *Service) DepositByPubkey(_ context.Context, _ []byte) (*ethpb.Deposit, *big.Int) {
   146  	return &ethpb.Deposit{}, nil
   147  }
   148  
   149  // DepositsNumberAndRootAtHeight mocks out the deposit cache functionality for interop.
   150  func (s *Service) DepositsNumberAndRootAtHeight(_ context.Context, _ *big.Int) (uint64, [32]byte) {
   151  	return 0, [32]byte{}
   152  }
   153  
   154  // FinalizedDeposits mocks out the deposit cache functionality for interop.
   155  func (s *Service) FinalizedDeposits(_ context.Context) *depositcache.FinalizedDeposits {
   156  	return nil
   157  }
   158  
   159  // NonFinalizedDeposits mocks out the deposit cache functionality for interop.
   160  func (s *Service) NonFinalizedDeposits(_ context.Context, _ *big.Int) []*ethpb.Deposit {
   161  	return []*ethpb.Deposit{}
   162  }
   163  
   164  func (s *Service) saveGenesisState(ctx context.Context, genesisState iface.BeaconState) error {
   165  	if err := s.cfg.BeaconDB.SaveGenesisData(ctx, genesisState); err != nil {
   166  		return err
   167  	}
   168  
   169  	s.chainStartDeposits = make([]*ethpb.Deposit, genesisState.NumValidators())
   170  
   171  	for i := types.ValidatorIndex(0); uint64(i) < uint64(genesisState.NumValidators()); i++ {
   172  		pk := genesisState.PubkeyAtIndex(i)
   173  		s.chainStartDeposits[i] = &ethpb.Deposit{
   174  			Data: &ethpb.Deposit_Data{
   175  				PublicKey: pk[:],
   176  			},
   177  		}
   178  	}
   179  	return nil
   180  }