Skip to content

Commit

Permalink
Initialize Data Correctly For Powchain Service (#8812)
Browse files Browse the repository at this point in the history
* initialize index correctly

* comments

* review comments

* Update beacon-chain/powchain/service.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
  • Loading branch information
nisdas and rauljordan authored Apr 25, 2021
1 parent 424e115 commit ef9f6c5
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 15 deletions.
66 changes: 51 additions & 15 deletions beacon-chain/powchain/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package powchain

import (
"bytes"
"context"
"fmt"
"math/big"
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down
77 changes: 77 additions & 0 deletions beacon-chain/powchain/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down

0 comments on commit ef9f6c5

Please sign in to comment.