From fba56df765460d815937e64b3c3476f4cb0e6d98 Mon Sep 17 00:00:00 2001 From: Nishant Das Date: Wed, 24 Mar 2021 00:44:57 +0800 Subject: [PATCH] Fix Powchain Genesis (#8647) * fix powchain genesis * Setup test with a deposit cache Co-authored-by: Preston Van Loon --- beacon-chain/powchain/service.go | 57 +++++++++++++++++++++++++++ beacon-chain/powchain/service_test.go | 27 +++++++++++++ 2 files changed, 84 insertions(+) diff --git a/beacon-chain/powchain/service.go b/beacon-chain/powchain/service.go index ce5455a63..3959727b8 100644 --- a/beacon-chain/powchain/service.go +++ b/beacon-chain/powchain/service.go @@ -208,6 +208,10 @@ func NewService(ctx context.Context, config *Web3ServiceConfig) (*Service, error headTicker: time.NewTicker(time.Duration(params.BeaconConfig().SecondsPerETH1Block) * time.Second), } + if err := s.ensureValidPowchainData(ctx); err != nil { + return nil, errors.Wrap(err, "unable to validate powchain data") + } + eth1Data, err := config.BeaconDB.PowchainData(ctx) if err != nil { return nil, errors.Wrap(err, "unable to retrieve eth1 data") @@ -722,6 +726,20 @@ func (s *Service) initPOWService() { s.retryETH1Node(err) continue } + // Handle edge case with embedded genesis state by fetching genesis header to determine + // its height. + if s.chainStartData.Chainstarted && s.chainStartData.GenesisBlock == 0 { + genHeader, err := s.eth1DataFetcher.HeaderByHash(ctx, common.BytesToHash(s.chainStartData.Eth1Data.BlockHash)) + if err != nil { + log.Errorf("Unable to retrieve genesis ETH1.0 chain header: %v", err) + s.retryETH1Node(err) + continue + } + s.chainStartData.GenesisBlock = genHeader.Number.Uint64() + if err := s.savePowchainData(ctx); err != nil { + log.Errorf("Unable to save powchain data: %v", err) + } + } return } } @@ -895,6 +913,45 @@ func (s *Service) fallbackToNextEndpoint() { log.Infof("Falling back to alternative endpoint: %s", logutil.MaskCredentialsLogging(s.currHttpEndpoint)) } +// validates the current powchain data saved and makes sure that any +// embedded genesis state is correctly accounted for. +func (s *Service) ensureValidPowchainData(ctx context.Context) error { + genState, err := s.cfg.BeaconDB.GenesisState(ctx) + if err != nil { + return err + } + // Exit early if no genesis state is saved. + if genState == nil { + return nil + } + eth1Data, err := s.cfg.BeaconDB.PowchainData(ctx) + if err != nil { + return errors.Wrap(err, "unable to retrieve eth1 data") + } + if eth1Data == nil || !eth1Data.ChainstartData.Chainstarted { + pbState, err := stateV0.ProtobufBeaconState(s.preGenesisState.InnerStateUnsafe()) + if err != nil { + return err + } + s.chainStartData = &protodb.ChainStartData{ + Chainstarted: true, + GenesisTime: genState.GenesisTime(), + GenesisBlock: 0, + Eth1Data: genState.Eth1Data(), + ChainstartDeposits: make([]*ethpb.Deposit, 0), + } + eth1Data = &protodb.ETH1ChainData{ + CurrentEth1Data: s.latestEth1Data, + ChainstartData: s.chainStartData, + BeaconState: pbState, + Trie: s.depositTrie.ToProto(), + DepositContainers: s.cfg.DepositCache.AllDepositContainers(ctx), + } + return s.cfg.BeaconDB.SavePowchainData(ctx, eth1Data) + } + return nil +} + func dedupEndpoints(endpoints []string) []string { selectionMap := make(map[string]bool) newEndpoints := make([]string, 0, len(endpoints)) diff --git a/beacon-chain/powchain/service_test.go b/beacon-chain/powchain/service_test.go index e07474b3f..bfa72d3e7 100644 --- a/beacon-chain/powchain/service_test.go +++ b/beacon-chain/powchain/service_test.go @@ -193,10 +193,13 @@ func TestStart_NoHTTPEndpointDefinedSucceeds_WithGenesisState(t *testing.T) { require.NoError(t, err) require.NoError(t, beaconDB.SaveState(context.Background(), st, genRoot)) require.NoError(t, beaconDB.SaveGenesisBlockRoot(context.Background(), genRoot)) + depositCache, err := depositcache.New() + require.NoError(t, err) s, err := NewService(context.Background(), &Web3ServiceConfig{ HTTPEndpoints: []string{""}, // No endpoint defined! DepositContract: testAcc.ContractAddr, BeaconDB: beaconDB, + DepositCache: depositCache, }) require.NoError(t, err) @@ -587,3 +590,27 @@ func Test_batchRequestHeaders_UnderflowChecks(t *testing.T) { _, err = srv.batchRequestHeaders(start, end) require.ErrorContains(t, "cannot be >", err) } + +func TestService_EnsureConsistentPowchainData(t *testing.T) { + beaconDB := dbutil.SetupDB(t) + cache, err := depositcache.New() + require.NoError(t, err) + + s1, err := NewService(context.Background(), &Web3ServiceConfig{ + BeaconDB: beaconDB, + DepositCache: cache, + }) + require.NoError(t, err) + genState, err := testutil.NewBeaconState() + require.NoError(t, err) + assert.NoError(t, genState.SetSlot(1000)) + + require.NoError(t, s1.cfg.BeaconDB.SaveGenesisData(context.Background(), genState)) + require.NoError(t, s1.ensureValidPowchainData(context.Background())) + + eth1Data, err := s1.cfg.BeaconDB.PowchainData(context.Background()) + assert.NoError(t, err) + + assert.NotNil(t, eth1Data) + assert.Equal(t, true, eth1Data.ChainstartData.Chainstarted) +}