Part 9 of update fork choice - HeadBlock and HeadState getters (#3279)

* Headblock and headstate getters

* Moved mutex around
This commit is contained in:
terence tsao 2019-08-22 19:13:56 -06:00 committed by Raul Jordan
parent 0d64f7b80e
commit c47598514c
4 changed files with 112 additions and 65 deletions

View File

@ -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()

View File

@ -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 := &ethpb.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))
}
}

View File

@ -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
}

View File

@ -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
}