Fixed Simulator Can't get ParentSlot (#602)

This commit is contained in:
terence tsao
2018-10-02 11:34:26 -07:00
committed by Raul Jordan
parent 1abed55bdd
commit d5bf733948
17 changed files with 142 additions and 97 deletions

View File

@@ -93,8 +93,8 @@ func NewBeaconChain(genesisJSON string, db ethdb.Database) (*BeaconChain, error)
return beaconChain, nil
}
// GenesisBlock returns the canonical, genesis block.
func (b *BeaconChain) GenesisBlock() (*types.Block, error) {
// genesisBlock returns the canonical, genesis block.
func (b *BeaconChain) genesisBlock() (*types.Block, error) {
genesisExists, err := b.db.Has(genesisLookupKey)
if err != nil {
return nil, err
@@ -130,7 +130,7 @@ func (b *BeaconChain) CanonicalHead() (*types.Block, error) {
// If there has not been a canonical head stored yet, we
// return the genesis block of the chain.
if !has {
return b.GenesisBlock()
return b.genesisBlock()
}
bytes, err := b.db.Get(canonicalHeadLookupKey)
if err != nil {

View File

@@ -78,7 +78,7 @@ func TestNewBeaconChain(t *testing.T) {
t.Errorf("crystallized states not equal. received: %v, wanted: %v", beaconChain.CrystallizedState(), cState)
}
if _, err := beaconChain.GenesisBlock(); err != nil {
if _, err := beaconChain.genesisBlock(); err != nil {
t.Errorf("Getting new beaconchain genesis failed: %v", err)
}
}
@@ -102,7 +102,7 @@ func TestGetGenesisBlock(t *testing.T) {
t.Errorf("unable to save key value of genesis: %v", err)
}
genesisBlock, err := beaconChain.GenesisBlock()
genesisBlock, err := beaconChain.genesisBlock()
if err != nil {
t.Errorf("unable to get key value of genesis: %v", err)
}
@@ -124,7 +124,7 @@ func TestGetGenesisBlock_GenesisNotExist(t *testing.T) {
t.Errorf("unable to delete key value of genesis: %v", err)
}
genesisBlock, err := beaconChain.GenesisBlock()
genesisBlock, err := beaconChain.genesisBlock()
if err != nil {
t.Errorf("unable to get key value of genesis: %v", err)
}

View File

@@ -116,7 +116,10 @@ func (c *ChainService) Stop() error {
// CurrentBeaconSlot based on the seconds since genesis.
func (c *ChainService) CurrentBeaconSlot() uint64 {
secondsSinceGenesis := time.Since(c.genesisTimestamp).Seconds()
return uint64(math.Floor(secondsSinceGenesis / 8.0))
if secondsSinceGenesis-float64(params.GetConfig().SlotDuration) < 0 {
return 0
}
return uint64(math.Floor(secondsSinceGenesis/float64(params.GetConfig().SlotDuration))) - 1
}
// CanonicalHead of the current beacon chain.
@@ -200,6 +203,11 @@ func (c *ChainService) CanonicalBlockBySlotNumber(slotNumber uint64) (*types.Blo
return c.chain.canonicalBlockForSlot(slotNumber)
}
// GenesisBlock returns the contents of the genesis block.
func (c *ChainService) GenesisBlock() (*types.Block, error) {
return c.chain.genesisBlock()
}
// doesPoWBlockExist checks if the referenced PoW block exists.
func (c *ChainService) doesPoWBlockExist(block *types.Block) bool {
powBlock, err := c.web3Service.Client().BlockByHash(context.Background(), block.PowChainRef())
@@ -375,14 +383,13 @@ func (c *ChainService) blockProcessing() {
continue
}
log.Infof("Finished processing received block: %x", blockHash)
log.Infof("Finished processing received block: 0x%x", blockHash)
// We push the hash of the block we just stored to a pending processing
// slice the fork choice rule will utilize.
c.lock.Lock()
c.blocksPendingProcessing = append(c.blocksPendingProcessing, blockHash)
c.lock.Unlock()
log.Info("Finished processing received block")
}
}
}

View File

@@ -378,7 +378,7 @@ func TestRunningChainService(t *testing.T) {
}
chainService, _ := NewChainService(ctx, cfg)
genesis, err := beaconChain.GenesisBlock()
genesis, err := beaconChain.genesisBlock()
if err != nil {
t.Fatalf("unable to get canonical head: %v", err)
}

View File

@@ -192,7 +192,6 @@ func (s *Service) CurrentAssignmentsAndGenesisTime(ctx context.Context, req *pb.
return nil, errors.New("no public keys specified in request")
}
}
log.Info(len(cState.Validators()))
assignments, err := assignmentsForPublicKeys(keys, cState)
if err != nil {
return nil, fmt.Errorf("could not get assignments for public keys: %v", err)
@@ -361,7 +360,6 @@ func (s *Service) ValidatorAssignments(
for {
select {
case cState := <-s.canonicalStateChan:
log.Info("Sending new cycle assignments to validator clients")
var keys []*pb.PublicKey

View File

@@ -6,6 +6,7 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/simulator",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/params:go_default_library",
"//beacon-chain/types:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared:go_default_library",
@@ -22,6 +23,7 @@ go_test(
srcs = ["service_test.go"],
embed = [":go_default_library"],
deps = [
"//beacon-chain/params:go_default_library",
"//beacon-chain/types:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/database:go_default_library",

View File

@@ -6,15 +6,14 @@ import (
"fmt"
"time"
"github.com/golang/protobuf/ptypes"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/gogo/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/prysmaticlabs/prysm/beacon-chain/params"
"github.com/prysmaticlabs/prysm/beacon-chain/types"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared"
"github.com/prysmaticlabs/prysm/shared/p2p"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/sirupsen/logrus"
)
@@ -50,7 +49,7 @@ type Config struct {
// DefaultConfig options for the simulator.
func DefaultConfig() *Config {
return &Config{
Delay: time.Second * 5,
Delay: time.Second * time.Duration(params.GetConfig().SlotDuration),
BlockRequestBuf: 100,
}
}
@@ -156,8 +155,19 @@ func (sim *Simulator) run(delayChan <-chan time.Time, done <-chan struct{}) {
// If we have not broadcast a simulated block yet, we set parent hash
// to the genesis block.
var hash [32]byte
if sim.slotNum == 1 {
parentHash = []byte("genesis")
genesisBlock, err := sim.chainService.GenesisBlock()
if err != nil {
log.Errorf("Failed to retrieve genesis block: %v", err)
continue
}
hash, err = genesisBlock.Hash()
if err != nil {
log.Errorf("Failed to hash genesis block: %v", err)
continue
}
parentHash = hash[:]
} else {
parentHash = sim.broadcastedBlockHashes[len(sim.broadcastedBlockHashes)-1][:]
}
@@ -178,6 +188,9 @@ func (sim *Simulator) run(delayChan <-chan time.Time, done <-chan struct{}) {
ActiveStateHash: activeStateHash[:],
CrystallizedStateHash: crystallizedStateHash[:],
ParentHash: parentHash,
Attestations: []*pb.AggregatedAttestation{
{Slot: sim.slotNum - 1, AttesterBitfield: []byte{byte(255)}},
},
})
sim.slotNum++
@@ -210,7 +223,10 @@ func (sim *Simulator) run(delayChan <-chan time.Time, done <-chan struct{}) {
}
log.Debugf("Responding to full block request for hash: 0x%x", h)
// Sends the full block body to the requester.
res := &pb.BeaconBlockResponse{Block: block.Proto(), Attestation: nil}
res := &pb.BeaconBlockResponse{Block: block.Proto(), Attestation: &pb.AggregatedAttestation{
Slot: sim.slotNum - 1,
AttesterBitfield: []byte{byte(255)},
}}
sim.p2p.Send(res, msg.Peer)
}
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
"github.com/golang/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/params"
"github.com/prysmaticlabs/prysm/beacon-chain/types"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/database"
@@ -50,6 +51,10 @@ func (mc *mockChainService) CurrentCrystallizedState() *types.CrystallizedState
return types.NewCrystallizedState(&pb.CrystallizedState{})
}
func (mc *mockChainService) GenesisBlock() (*types.Block, error) {
return types.NewGenesisBlock([32]byte{}, [32]byte{}), nil
}
func TestLifecycle(t *testing.T) {
hook := logTest.NewGlobal()
db := database.NewKVStore()
@@ -182,7 +187,7 @@ func TestDefaultConfig(t *testing.T) {
if DefaultConfig().BlockRequestBuf != 100 {
t.Errorf("incorrect default config for block request buffer")
}
if DefaultConfig().Delay != time.Second*5 {
if DefaultConfig().Delay != time.Second*time.Duration(params.GetConfig().SlotDuration) {
t.Errorf("incorrect default config for delay")
}
}

View File

@@ -45,26 +45,28 @@ type attestationService interface {
// * Drop peers that send invalid data
// * Throttle incoming requests
type Service struct {
ctx context.Context
cancel context.CancelFunc
p2p shared.P2P
chainService chainService
attestationService attestationService
blockAnnouncementFeed *event.Feed
announceBlockHashBuf chan p2p.Message
blockBuf chan p2p.Message
blockRequestBySlot chan p2p.Message
attestationBuf chan p2p.Message
ctx context.Context
cancel context.CancelFunc
p2p shared.P2P
chainService chainService
attestationService attestationService
blockAnnouncementFeed *event.Feed
announceBlockHashBuf chan p2p.Message
blockBuf chan p2p.Message
blockRequestBySlot chan p2p.Message
attestationBuf chan p2p.Message
enableAttestationValidity bool
}
// Config allows the channel's buffer sizes to be changed.
type Config struct {
BlockHashBufferSize int
BlockBufferSize int
BlockRequestBufferSize int
AttestationBufferSize int
ChainService chainService
AttestService attestationService
BlockHashBufferSize int
BlockBufferSize int
BlockRequestBufferSize int
AttestationBufferSize int
ChainService chainService
AttestService attestationService
EnableAttestationValidity bool
}
// DefaultConfig provides the default configuration for a sync service.
@@ -81,16 +83,17 @@ func DefaultConfig() Config {
func NewSyncService(ctx context.Context, cfg Config, beaconp2p shared.P2P) *Service {
ctx, cancel := context.WithCancel(ctx)
return &Service{
ctx: ctx,
cancel: cancel,
p2p: beaconp2p,
chainService: cfg.ChainService,
attestationService: cfg.AttestService,
blockAnnouncementFeed: new(event.Feed),
announceBlockHashBuf: make(chan p2p.Message, cfg.BlockHashBufferSize),
blockBuf: make(chan p2p.Message, cfg.BlockBufferSize),
blockRequestBySlot: make(chan p2p.Message, cfg.BlockRequestBufferSize),
attestationBuf: make(chan p2p.Message, cfg.AttestationBufferSize),
ctx: ctx,
cancel: cancel,
p2p: beaconp2p,
chainService: cfg.ChainService,
attestationService: cfg.AttestService,
blockAnnouncementFeed: new(event.Feed),
announceBlockHashBuf: make(chan p2p.Message, cfg.BlockHashBufferSize),
blockBuf: make(chan p2p.Message, cfg.BlockBufferSize),
blockRequestBySlot: make(chan p2p.Message, cfg.BlockRequestBufferSize),
attestationBuf: make(chan p2p.Message, cfg.AttestationBufferSize),
enableAttestationValidity: cfg.EnableAttestationValidity,
}
}
@@ -205,34 +208,35 @@ func (ss *Service) receiveBlock(msg p2p.Message) {
return
}
// Verify attestation coming from proposer then forward block to the subscribers.
attestation := types.NewAttestation(response.Attestation)
cState := ss.chainService.CurrentCrystallizedState()
parentSlot, err := ss.chainService.BlockSlotNumberByHash(block.ParentHash())
if err != nil {
log.Errorf("Failed to get parent slot: %v", err)
return
}
proposerShardID, _, err := casper.ProposerShardAndIndex(cState.ShardAndCommitteesForSlots(), cState.LastStateRecalc(), parentSlot)
if err != nil {
log.Errorf("Failed to get proposer shard ID: %v", err)
return
}
// TODO(#258): stubbing public key with empty 32 bytes.
if err := attestation.VerifyProposerAttestation([32]byte{}, proposerShardID); err != nil {
log.Errorf("Failed to verify proposer attestation: %v", err)
return
if ss.enableAttestationValidity {
// Verify attestation coming from proposer then forward block to the subscribers.
attestation := types.NewAttestation(response.Attestation)
cState := ss.chainService.CurrentCrystallizedState()
parentSlot, err := ss.chainService.BlockSlotNumberByHash(block.ParentHash())
if err != nil {
log.Errorf("Failed to get parent slot: %v", err)
return
}
proposerShardID, _, err := casper.ProposerShardAndIndex(cState.ShardAndCommitteesForSlots(), cState.LastStateRecalc(), parentSlot)
if err != nil {
log.Errorf("Failed to get proposer shard ID: %v", err)
return
}
// TODO(#258): stubbing public key with empty 32 bytes.
if err := attestation.VerifyProposerAttestation([32]byte{}, proposerShardID); err != nil {
log.Errorf("Failed to verify proposer attestation: %v", err)
return
}
_, sendAttestationSpan := trace.StartSpan(ctx, "sendAttestation")
log.WithField("attestationHash", fmt.Sprintf("0x%x", attestation.Key())).Debug("Sending newly received attestation to subscribers")
ss.attestationService.IncomingAttestationFeed().Send(attestation)
sendAttestationSpan.End()
}
_, sendBlockSpan := trace.StartSpan(ctx, "sendBlock")
log.WithField("blockHash", fmt.Sprintf("0x%x", blockHash)).Debug("Sending newly received block to subscribers")
ss.chainService.IncomingBlockFeed().Send(block)
sendBlockSpan.End()
_, sendAttestationSpan := trace.StartSpan(ctx, "sendAttestation")
log.WithField("attestationHash", fmt.Sprintf("0x%x", attestation.Key())).Debug("Sending newly received attestation to subscribers")
ss.attestationService.IncomingAttestationFeed().Send(attestation)
sendAttestationSpan.End()
}
// handleBlockRequestBySlot processes a block request from the p2p layer.

View File

@@ -41,6 +41,7 @@ go_test(
"crystallized_state_test.go",
],
embed = [":go_default_library"],
race = "off", # TODO(#604): fix issues with tests failing with race on.
deps = [
"//beacon-chain/params:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",

View File

@@ -169,29 +169,21 @@ func (b *Block) IsValid(
return false
}
// verify proposer from last slot is in the first attestation object in AggregatedAttestation.
_, proposerIndex, err := casper.ProposerShardAndIndex(
cState.ShardAndCommitteesForSlots(),
cState.LastStateRecalc(),
parentSlot)
if err != nil {
log.Errorf("Can not get proposer index %v", err)
return false
}
log.Infof("Proposer index: %v", proposerIndex)
if !shared.CheckBit(b.Attestations()[0].AttesterBitfield, int(proposerIndex)) {
log.Errorf("Can not locate proposer in the first attestation of AttestionRecord %v", err)
return false
}
for index, attestation := range b.Attestations() {
if !b.isAttestationValid(index, chain, aState, cState, parentSlot) {
log.Debugf("attestation invalid: %v", attestation)
if enableAttestationValidity {
// verify proposer from last slot is in the first attestation object in AggregatedAttestation.
_, proposerIndex, err := casper.ProposerShardAndIndex(
cState.ShardAndCommitteesForSlots(),
cState.LastStateRecalc(),
parentSlot)
if err != nil {
log.Errorf("Can not get proposer index %v", err)
return false
}
if !shared.CheckBit(b.Attestations()[0].AttesterBitfield, int(proposerIndex)) {
log.Errorf("Can not locate proposer in the first attestation of AttestionRecord %v", err)
return false
}
}
if enableAttestationValidity {
log.Debugf("Checking block validity. Recent block hash is %d",
aState.data.RecentBlockHashes[0],
)

View File

@@ -47,10 +47,11 @@ type ActiveStateChainService interface {
ContainsActiveState(h [32]byte) bool
}
// StateFetcher defines a struct that can fetch the latest canonical beacon state of a node.
// StateFetcher defines a struct that can fetch the latest canonical beacon state and genesis block of a node.
type StateFetcher interface {
CurrentActiveState() *ActiveState
CurrentCrystallizedState() *CrystallizedState
GenesisBlock() (*Block, error)
}
// POWChainService is an interface for a proof-of-work chain web3 service.

View File

@@ -23,7 +23,7 @@ func (RealClock) Now() time.Time {
// CurrentBeaconSlot based on the seconds since genesis.
func CurrentBeaconSlot() uint64 {
secondsSinceGenesis := time.Since(params.GetConfig().GenesisTime).Seconds()
return uint64(math.Floor(secondsSinceGenesis / 8.0))
return uint64(math.Floor(secondsSinceGenesis/float64(params.GetConfig().SlotDuration))) - 1
}
// BlockingWait sleeps until a specific time is reached after

View File

@@ -25,6 +25,7 @@ go_test(
"//proto/beacon/rpc/v1:go_default_library",
"//shared/testutil:go_default_library",
"//validator/internal:go_default_library",
"//validator/params:go_default_library",
"@com_github_golang_mock//gomock:go_default_library",
"@com_github_golang_protobuf//ptypes:go_default_library_gen",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -135,7 +135,8 @@ func (s *Service) fetchCurrentAssignmentsAndGenesisTime(client pb.BeaconServiceC
for _, assign := range res.Assignments {
if bytes.Equal(assign.PublicKey.PublicKey, s.pubKey) {
s.role = assign.Role
s.assignedSlot = s.CurrentCycleStartSlot() + assign.AssignedSlot
// + 1 to account for the genesis block being slot 0.
s.assignedSlot = s.CurrentCycleStartSlot(params.DemoConfig().CycleLength) + assign.AssignedSlot + 1
s.shardID = assign.ShardId
log.Infof("Validator shuffled. Pub key 0x%s re-assigned to shard ID %d for %v duty at slot %d",
@@ -176,7 +177,12 @@ func (s *Service) listenForAssignmentChange(client pb.BeaconServiceClient) {
for _, assign := range assignment.Assignments {
if bytes.Equal(assign.PublicKey.PublicKey, s.pubKey) {
s.role = assign.Role
s.assignedSlot = s.CurrentCycleStartSlot() + assign.AssignedSlot
if s.CurrentCycleStartSlot(params.DemoConfig().CycleLength) == 0 {
// +1 to account for genesis block being slot 0.
s.assignedSlot = params.DemoConfig().CycleLength + assign.AssignedSlot + 1
} else {
s.assignedSlot = s.CurrentCycleStartSlot(params.DemoConfig().CycleLength) + assign.AssignedSlot + 1
}
s.shardID = assign.ShardId
log.Infof("Validator with pub key 0x%s re-assigned to shard ID %d for %v duty at slot %d",
@@ -280,12 +286,15 @@ func (s *Service) PublicKey() []byte {
// CurrentBeaconSlot based on the genesis timestamp of the protocol.
func (s *Service) CurrentBeaconSlot() uint64 {
secondsSinceGenesis := time.Since(s.genesisTimestamp).Seconds()
return uint64(math.Floor(secondsSinceGenesis / params.DefaultConfig().SlotDuration))
if secondsSinceGenesis-params.DefaultConfig().SlotDuration < 0 {
return 0
}
return uint64(math.Floor(secondsSinceGenesis/params.DefaultConfig().SlotDuration)) - 1
}
// CurrentCycleStartSlot returns the slot at which the current cycle started.
func (s *Service) CurrentCycleStartSlot() uint64 {
func (s *Service) CurrentCycleStartSlot(cycleLength uint64) uint64 {
currentSlot := s.CurrentBeaconSlot()
cycleNum := math.Floor(float64(currentSlot) / float64(params.DefaultConfig().CycleLength))
return uint64(cycleNum) * params.DefaultConfig().CycleLength
cycleNum := currentSlot / cycleLength
return uint64(cycleNum) * cycleLength
}

View File

@@ -16,6 +16,7 @@ import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/validator/internal"
"github.com/prysmaticlabs/prysm/validator/params"
"github.com/sirupsen/logrus"
logTest "github.com/sirupsen/logrus/hooks/test"
)
@@ -301,7 +302,7 @@ func TestListenForAssignmentProposer(t *testing.T) {
stream := internal.NewMockBeaconService_ValidatorAssignmentsClient(ctrl)
// Testing proposer assignment.
assignedSlot := b.CurrentCycleStartSlot() + 2
assignedSlot := b.CurrentCycleStartSlot(params.DefaultConfig().CycleLength) + 2
stream.EXPECT().Recv().Return(&pb.ValidatorAssignmentResponse{Assignments: []*pb.Assignment{{
PublicKey: &pb.PublicKey{PublicKey: []byte{'A'}},
ShardId: 2,

View File

@@ -16,6 +16,14 @@ func DefaultConfig() *Config {
}
}
// DemoConfig for running the system under shorter defaults.
func DemoConfig() *Config {
return &Config{
SlotDuration: 8.0,
CycleLength: 5,
}
}
// DefaultCollationSizeLimit is the integer value representing the maximum
// number of bytes allowed in a given collation.
func DefaultCollationSizeLimit() int64 {