Fix Powchain Genesis (#8647)

* fix powchain genesis

* Setup test with a deposit cache

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
This commit is contained in:
Nishant Das 2021-03-24 00:44:57 +08:00 committed by GitHub
parent 8281634131
commit fba56df765
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 0 deletions

View File

@ -208,6 +208,10 @@ func NewService(ctx context.Context, config *Web3ServiceConfig) (*Service, error
headTicker: time.NewTicker(time.Duration(params.BeaconConfig().SecondsPerETH1Block) * time.Second), 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) eth1Data, err := config.BeaconDB.PowchainData(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to retrieve eth1 data") return nil, errors.Wrap(err, "unable to retrieve eth1 data")
@ -722,6 +726,20 @@ func (s *Service) initPOWService() {
s.retryETH1Node(err) s.retryETH1Node(err)
continue 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 return
} }
} }
@ -895,6 +913,45 @@ func (s *Service) fallbackToNextEndpoint() {
log.Infof("Falling back to alternative endpoint: %s", logutil.MaskCredentialsLogging(s.currHttpEndpoint)) 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 { func dedupEndpoints(endpoints []string) []string {
selectionMap := make(map[string]bool) selectionMap := make(map[string]bool)
newEndpoints := make([]string, 0, len(endpoints)) newEndpoints := make([]string, 0, len(endpoints))

View File

@ -193,10 +193,13 @@ func TestStart_NoHTTPEndpointDefinedSucceeds_WithGenesisState(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(context.Background(), st, genRoot)) require.NoError(t, beaconDB.SaveState(context.Background(), st, genRoot))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(context.Background(), genRoot)) require.NoError(t, beaconDB.SaveGenesisBlockRoot(context.Background(), genRoot))
depositCache, err := depositcache.New()
require.NoError(t, err)
s, err := NewService(context.Background(), &Web3ServiceConfig{ s, err := NewService(context.Background(), &Web3ServiceConfig{
HTTPEndpoints: []string{""}, // No endpoint defined! HTTPEndpoints: []string{""}, // No endpoint defined!
DepositContract: testAcc.ContractAddr, DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB, BeaconDB: beaconDB,
DepositCache: depositCache,
}) })
require.NoError(t, err) require.NoError(t, err)
@ -587,3 +590,27 @@ func Test_batchRequestHeaders_UnderflowChecks(t *testing.T) {
_, err = srv.batchRequestHeaders(start, end) _, err = srv.batchRequestHeaders(start, end)
require.ErrorContains(t, "cannot be >", err) 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)
}