From c47598514cd914ac263acbb16bf5af922dd134ff Mon Sep 17 00:00:00 2001 From: terence tsao Date: Thu, 22 Aug 2019 19:13:56 -0600 Subject: [PATCH] Part 9 of update fork choice - HeadBlock and HeadState getters (#3279) * Headblock and headstate getters * Moved mutex around --- beacon-chain/blockchain/chain_info.go | 13 ++++ beacon-chain/blockchain/chain_info_test.go | 23 ++++++- beacon-chain/blockchain/receive_block.go | 61 ----------------- beacon-chain/blockchain/service.go | 80 +++++++++++++++++++++- 4 files changed, 112 insertions(+), 65 deletions(-) diff --git a/beacon-chain/blockchain/chain_info.go b/beacon-chain/blockchain/chain_info.go index dc0e3c309..4ba78690d 100644 --- a/beacon-chain/blockchain/chain_info.go +++ b/beacon-chain/blockchain/chain_info.go @@ -3,6 +3,7 @@ package blockchain import ( "time" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" ) @@ -20,6 +21,8 @@ type ChainInfoRetriever interface { type HeadRetriever interface { HeadSlot() uint64 HeadRoot() []byte + HeadBlock() *ethpb.BeaconBlock + HeadState() *pb.BeaconState } // CanonicalRetriever defines a common interface for methods in blockchain service which @@ -52,6 +55,16 @@ func (c *ChainService) HeadRoot() []byte { return c.canonicalRoots[c.headSlot] } +// HeadBlock returns the head block of the chain. +func (c *ChainService) HeadBlock() *ethpb.BeaconBlock { + return c.headBlock +} + +// HeadState returns the head state of the chain. +func (c *ChainService) HeadState() *pb.BeaconState { + return c.headState +} + // CanonicalRoot returns the canonical root of a given slot. func (c *ChainService) CanonicalRoot(slot uint64) []byte { c.canonicalRootsLock.RLock() diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index 9638f1ef4..bb38e1f54 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -3,11 +3,13 @@ package blockchain import ( "bytes" "context" + "reflect" "testing" "time" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" ) // Ensure ChainService implements chain info interface. @@ -47,11 +49,28 @@ func TestHeadRoot_CanRetrieve(t *testing.T) { } } +func TestHeadBlock_CanRetrieve(t *testing.T) { + b := ðpb.BeaconBlock{Slot: 1} + c := &ChainService{headBlock: b} + if !reflect.DeepEqual(b, c.HeadBlock()) { + t.Error("incorrect head block received") + } +} + +func TestHeadState_CanRetrieve(t *testing.T) { + s := &pb.BeaconState{Slot: 2} + c := &ChainService{headState: s} + if !reflect.DeepEqual(s, c.HeadState()) { + t.Error("incorrect head state received") + } +} + func TestCanonicalRoot_CanRetrieve(t *testing.T) { c := &ChainService{canonicalRoots: make(map[uint64][]byte)} slot := uint64(123) - c.canonicalRoots[slot] = []byte{'B'} - if !bytes.Equal([]byte{'B'}, c.CanonicalRoot(slot)) { + r := []byte{'B'} + c.canonicalRoots[slot] = r + if !bytes.Equal(r, c.CanonicalRoot(slot)) { t.Errorf("Wanted head root: %v, got: %d", []byte{'A'}, c.CanonicalRoot(slot)) } } diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index 258f0b291..8d803f369 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -6,9 +6,6 @@ import ( "github.com/pkg/errors" "github.com/prysmaticlabs/go-ssz" - "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" - "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/sirupsen/logrus" @@ -140,61 +137,3 @@ func (c *ChainService) CleanupBlockOperations(ctx context.Context, block *ethpb. } return nil } - -// saveValidatorIdx saves the validators public key to index mapping in DB, these -// validators were activated from current epoch. After it saves, current epoch key -// is deleted from ActivatedValidators mapping. -func (c *ChainService) saveValidatorIdx(ctx context.Context, state *pb.BeaconState) error { - nextEpoch := helpers.CurrentEpoch(state) + 1 - activatedValidators := validators.ActivatedValFromEpoch(nextEpoch) - var idxNotInState []uint64 - for _, idx := range activatedValidators { - // If for some reason the activated validator indices is not in state, - // we skip them and save them to process for next epoch. - if int(idx) >= len(state.Validators) { - idxNotInState = append(idxNotInState, idx) - continue - } - pubKey := state.Validators[idx].PublicKey - if err := c.beaconDB.SaveValidatorIndex(ctx, bytesutil.ToBytes48(pubKey), idx); err != nil { - return errors.Wrap(err, "could not save validator index") - } - } - // Since we are processing next epoch, save the can't processed validator indices - // to the epoch after that. - validators.InsertActivatedIndices(nextEpoch+1, idxNotInState) - validators.DeleteActivatedVal(helpers.CurrentEpoch(state)) - return nil -} - -// deleteValidatorIdx deletes the validators public key to index mapping in DB, the -// validators were exited from current epoch. After it deletes, current epoch key -// is deleted from ExitedValidators mapping. -func (c *ChainService) deleteValidatorIdx(ctx context.Context, state *pb.BeaconState) error { - exitedValidators := validators.ExitedValFromEpoch(helpers.CurrentEpoch(state) + 1) - for _, idx := range exitedValidators { - pubKey := state.Validators[idx].PublicKey - if err := c.beaconDB.DeleteValidatorIndex(ctx, bytesutil.ToBytes48(pubKey)); err != nil { - return errors.Wrap(err, "could not delete validator index") - } - } - validators.DeleteExitedVal(helpers.CurrentEpoch(state)) - return nil -} - -// This gets called to update canonical root mapping. -func (c *ChainService) saveHead(ctx context.Context, b *ethpb.BeaconBlock, r [32]byte) error { - c.canonicalRootsLock.Lock() - defer c.canonicalRootsLock.Unlock() - c.headSlot = b.Slot - c.canonicalRoots[b.Slot] = r[:] - if err := c.beaconDB.SaveHeadBlockRoot(ctx, r); err != nil { - return errors.Wrap(err, "could not save head root in DB") - } - log.WithFields(logrus.Fields{ - "slots": b.Slot, - "root": hex.EncodeToString(r[:]), - }).Info("Saved head info") - - return nil -} diff --git a/beacon-chain/blockchain/service.go b/beacon-chain/blockchain/service.go index a11d6678b..ea6c014fe 100644 --- a/beacon-chain/blockchain/service.go +++ b/beacon-chain/blockchain/service.go @@ -5,6 +5,7 @@ package blockchain import ( "context" + "encoding/hex" "fmt" "runtime" "sync" @@ -13,12 +14,16 @@ import ( "github.com/pkg/errors" "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/forkchoice" "github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache" + "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/state" + "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" "github.com/prysmaticlabs/prysm/beacon-chain/db" "github.com/prysmaticlabs/prysm/beacon-chain/operations" "github.com/prysmaticlabs/prysm/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/beacon-chain/powchain" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/event" "github.com/sirupsen/logrus" "go.opencensus.io/trace" @@ -46,10 +51,12 @@ type ChainService struct { genesisTime time.Time stateInitializedFeed *event.Feed p2p p2p.Broadcaster - canonicalRoots map[uint64][]byte - canonicalRootsLock sync.RWMutex maxRoutines int64 headSlot uint64 + headBlock *ethpb.BeaconBlock + headState *pb.BeaconState + canonicalRoots map[uint64][]byte + canonicalRootsLock sync.RWMutex } // Config options for the service. @@ -166,3 +173,72 @@ func (c *ChainService) Status() error { func (c *ChainService) StateInitializedFeed() *event.Feed { return c.stateInitializedFeed } + +// saveValidatorIdx saves the validators public key to index mapping in DB, these +// validators were activated from current epoch. After it saves, current epoch key +// is deleted from ActivatedValidators mapping. +func (c *ChainService) saveValidatorIdx(ctx context.Context, state *pb.BeaconState) error { + nextEpoch := helpers.CurrentEpoch(state) + 1 + activatedValidators := validators.ActivatedValFromEpoch(nextEpoch) + var idxNotInState []uint64 + for _, idx := range activatedValidators { + // If for some reason the activated validator indices is not in state, + // we skip them and save them to process for next epoch. + if int(idx) >= len(state.Validators) { + idxNotInState = append(idxNotInState, idx) + continue + } + pubKey := state.Validators[idx].PublicKey + if err := c.beaconDB.SaveValidatorIndex(ctx, bytesutil.ToBytes48(pubKey), idx); err != nil { + return errors.Wrap(err, "could not save validator index") + } + } + // Since we are processing next epoch, save the can't processed validator indices + // to the epoch after that. + validators.InsertActivatedIndices(nextEpoch+1, idxNotInState) + validators.DeleteActivatedVal(helpers.CurrentEpoch(state)) + return nil +} + +// deleteValidatorIdx deletes the validators public key to index mapping in DB, the +// validators were exited from current epoch. After it deletes, current epoch key +// is deleted from ExitedValidators mapping. +func (c *ChainService) deleteValidatorIdx(ctx context.Context, state *pb.BeaconState) error { + exitedValidators := validators.ExitedValFromEpoch(helpers.CurrentEpoch(state) + 1) + for _, idx := range exitedValidators { + pubKey := state.Validators[idx].PublicKey + if err := c.beaconDB.DeleteValidatorIndex(ctx, bytesutil.ToBytes48(pubKey)); err != nil { + return errors.Wrap(err, "could not delete validator index") + } + } + validators.DeleteExitedVal(helpers.CurrentEpoch(state)) + return nil +} + +// This gets called to update canonical root mapping. +func (c *ChainService) saveHead(ctx context.Context, b *ethpb.BeaconBlock, r [32]byte) error { + + c.headSlot = b.Slot + + c.canonicalRootsLock.Lock() + c.canonicalRoots[b.Slot] = r[:] + defer c.canonicalRootsLock.Unlock() + + if err := c.beaconDB.SaveHeadBlockRoot(ctx, r); err != nil { + return errors.Wrap(err, "could not save head root in DB") + } + c.headBlock = b + + s, err := c.beaconDB.State(ctx, r) + if err != nil { + return errors.Wrap(err, "could not retrieve head state in DB") + } + c.headState = s + + log.WithFields(logrus.Fields{ + "slots": b.Slot, + "root": hex.EncodeToString(r[:]), + }).Info("Saved head info") + + return nil +}