Initialize Data Correctly For Powchain Service (#8812)

* initialize index correctly

* comments

* review comments

* Update beacon-chain/powchain/service.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
This commit is contained in:
Nishant Das
2021-04-25 13:11:15 +08:00
committed by GitHub
parent 424e115331
commit ef9f6c5b4d
2 changed files with 128 additions and 15 deletions

View File

@@ -4,6 +4,7 @@
package powchain
import (
"bytes"
"context"
"fmt"
"math/big"
@@ -220,20 +221,8 @@ func NewService(ctx context.Context, config *Web3ServiceConfig) (*Service, error
if err != nil {
return nil, errors.Wrap(err, "unable to retrieve eth1 data")
}
if eth1Data != nil {
s.depositTrie = trieutil.CreateTrieFromProto(eth1Data.Trie)
s.chainStartData = eth1Data.ChainstartData
if !reflect.ValueOf(eth1Data.BeaconState).IsZero() {
s.preGenesisState, err = stateV0.InitializeFromProto(eth1Data.BeaconState)
if err != nil {
return nil, errors.Wrap(err, "Could not initialize state trie")
}
}
s.latestEth1Data = eth1Data.CurrentEth1Data
s.lastReceivedMerkleIndex = int64(len(s.depositTrie.Items()) - 1)
if err := s.initDepositCaches(ctx, eth1Data.DepositContainers); err != nil {
return nil, errors.Wrap(err, "could not initialize caches")
}
if err := s.initializeEth1Data(ctx, eth1Data); err != nil {
return nil, err
}
return s, nil
}
@@ -936,6 +925,53 @@ func (s *Service) fallbackToNextEndpoint() {
log.Infof("Falling back to alternative endpoint: %s", logutil.MaskCredentialsLogging(s.currHttpEndpoint.Url))
}
// initializes our service from the provided eth1data object by initializing all the relevant
// fields and data.
func (s *Service) initializeEth1Data(ctx context.Context, eth1DataInDB *protodb.ETH1ChainData) error {
// The node has no eth1data persisted on disk, so we exit and instead
// request from contract logs.
if eth1DataInDB == nil {
return nil
}
s.depositTrie = trieutil.CreateTrieFromProto(eth1DataInDB.Trie)
s.chainStartData = eth1DataInDB.ChainstartData
var err error
if !reflect.ValueOf(eth1DataInDB.BeaconState).IsZero() {
s.preGenesisState, err = stateV0.InitializeFromProto(eth1DataInDB.BeaconState)
if err != nil {
return errors.Wrap(err, "Could not initialize state trie")
}
}
s.latestEth1Data = eth1DataInDB.CurrentEth1Data
items := s.depositTrie.Items()
s.lastReceivedMerkleIndex = int64(len(items) - 1)
// Account for 0 elements existing in the deposit trie.
if len(items) == 1 && bytes.Equal(items[0], params.BeaconConfig().ZeroHash[:]) {
s.lastReceivedMerkleIndex = -1
}
if err := s.initDepositCaches(ctx, eth1DataInDB.DepositContainers); err != nil {
return errors.Wrap(err, "could not initialize caches")
}
return nil
}
// validates that all deposit containers are valid and have their relevant indices
// in order.
func (s *Service) validateDepositContainers(ctrs []*protodb.DepositContainer) bool {
ctrLen := len(ctrs)
// Exit for empty containers.
if ctrLen == 0 {
return true
}
for _, c := range ctrs {
if c.Index == 0 {
return true
}
}
log.Info("Recovering missing deposit containers, node is re-requesting missing deposit data")
return false
}
// 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 {
@@ -951,7 +987,7 @@ func (s *Service) ensureValidPowchainData(ctx context.Context) error {
if err != nil {
return errors.Wrap(err, "unable to retrieve eth1 data")
}
if eth1Data == nil || !eth1Data.ChainstartData.Chainstarted {
if eth1Data == nil || !eth1Data.ChainstartData.Chainstarted || !s.validateDepositContainers(eth1Data.DepositContainers) {
pbState, err := stateV0.ProtobufBeaconState(s.preGenesisState.InnerStateUnsafe())
if err != nil {
return err

View File

@@ -620,6 +620,83 @@ func TestService_EnsureConsistentPowchainData(t *testing.T) {
assert.Equal(t, true, eth1Data.ChainstartData.Chainstarted)
}
func TestService_InitializeCorrectly(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.NoError(t, s1.initializeEth1Data(context.Background(), eth1Data))
assert.Equal(t, int64(-1), s1.lastReceivedMerkleIndex, "received incorrect last received merkle index")
}
func TestService_EnsureValidPowchainData(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))
err = s1.cfg.BeaconDB.SavePowchainData(context.Background(), &protodb.ETH1ChainData{
ChainstartData: &protodb.ChainStartData{Chainstarted: true},
DepositContainers: []*protodb.DepositContainer{{Index: 1}},
})
require.NoError(t, err)
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, 0, len(eth1Data.DepositContainers))
}
func TestService_ValidateDepositContainers(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)
ctrs := make([]*protodb.DepositContainer, 0)
assert.Equal(t, true, s1.validateDepositContainers(ctrs))
for i := 0; i < 10; i++ {
ctrs = append(ctrs, &protodb.DepositContainer{Index: int64(i), Eth1BlockHeight: uint64(i + 10)})
}
assert.Equal(t, true, s1.validateDepositContainers(ctrs))
ctrs = make([]*protodb.DepositContainer, 0)
for i := 1; i < 10; i++ {
ctrs = append(ctrs, &protodb.DepositContainer{Index: int64(i), Eth1BlockHeight: uint64(i + 10)})
}
assert.Equal(t, false, s1.validateDepositContainers(ctrs))
}
func TestTimestampIsChecked(t *testing.T) {
timestamp := uint64(time.Now().Unix())
assert.Equal(t, false, eth1HeadIsBehind(timestamp))