From e696c11a1e1f1ef8f9cd9458fa3704a5a1bc766a Mon Sep 17 00:00:00 2001 From: Terence Tsao Date: Wed, 6 Feb 2019 21:57:22 +0100 Subject: [PATCH 1/5] fixed epoch_processing --- beacon-chain/core/blocks/block.go | 15 ++++---- beacon-chain/core/epoch/epoch_processing.go | 38 ++++++++++----------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/beacon-chain/core/blocks/block.go b/beacon-chain/core/blocks/block.go index 5436c6bd5bd9..3ab8eacff0d0 100644 --- a/beacon-chain/core/blocks/block.go +++ b/beacon-chain/core/blocks/block.go @@ -17,17 +17,16 @@ import ( "github.com/prysmaticlabs/prysm/shared/ssz" ) -var config = params.BeaconConfig() var clock utils.Clock = &utils.RealClock{} // NewGenesisBlock returns the canonical, genesis block for the beacon chain protocol. func NewGenesisBlock(stateRoot []byte) *pb.BeaconBlock { block := &pb.BeaconBlock{ - Slot: config.GenesisSlot, - ParentRootHash32: config.ZeroHash[:], + Slot: params.BeaconConfig().GenesisSlot, + ParentRootHash32: params.BeaconConfig().ZeroHash[:], StateRootHash32: stateRoot, - RandaoRevealHash32: config.ZeroHash[:], - Signature: config.EmptySignature, + RandaoRevealHash32: params.BeaconConfig().ZeroHash[:], + Signature: params.BeaconConfig().EmptySignature, Body: &pb.BeaconBlockBody{ ProposerSlashings: []*pb.ProposerSlashing{}, AttesterSlashings: []*pb.AttesterSlashing{}, @@ -47,7 +46,7 @@ func IsRandaoValid(blockRandao []byte, stateRandao []byte) bool { // IsSlotValid compares the slot to the system clock to determine if the block is valid. func IsSlotValid(slot uint64, genesisTime time.Time) bool { - slotDuration := time.Duration(slot*config.SlotDuration) * time.Second + slotDuration := time.Duration(slot*params.BeaconConfig().SlotDuration) * time.Second validTimeThreshold := genesisTime.Add(slotDuration) return clock.Now().After(validTimeThreshold) } @@ -90,8 +89,8 @@ func BlockRoot(state *pb.BeaconState, slot uint64) ([]byte, error) { // Set state.latest_block_roots[(state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = previous_block_root. // If state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0 append merkle_root(state.latest_block_roots) to state.batched_block_roots. func ProcessBlockRoots(state *pb.BeaconState, prevBlockRoot [32]byte) *pb.BeaconState { - state.LatestBlockRootHash32S[(state.Slot-1)%config.LatestBlockRootsLength] = prevBlockRoot[:] - if state.Slot%config.LatestBlockRootsLength == 0 { + state.LatestBlockRootHash32S[(state.Slot-1)%params.BeaconConfig().LatestBlockRootsLength] = prevBlockRoot[:] + if state.Slot%params.BeaconConfig().LatestBlockRootsLength == 0 { merkleRoot := hashutil.MerkleRoot(state.LatestBlockRootHash32S) state.BatchedBlockRootHash32S = append(state.BatchedBlockRootHash32S, merkleRoot) } diff --git a/beacon-chain/core/epoch/epoch_processing.go b/beacon-chain/core/epoch/epoch_processing.go index c2683e7e55a4..0b0cee6bedd2 100644 --- a/beacon-chain/core/epoch/epoch_processing.go +++ b/beacon-chain/core/epoch/epoch_processing.go @@ -14,15 +14,13 @@ import ( "github.com/prysmaticlabs/prysm/shared/params" ) -var config = params.BeaconConfig() - // CanProcessEpoch checks the eligibility to process epoch. // The epoch can be processed every EPOCH_LENGTH. // // Spec pseudocode definition: // If state.slot % EPOCH_LENGTH == 0: func CanProcessEpoch(state *pb.BeaconState) bool { - return state.Slot%config.EpochLength == 0 + return state.Slot%params.BeaconConfig().EpochLength == 0 } // CanProcessEth1Data checks the eligibility to process the eth1 data. @@ -31,7 +29,7 @@ func CanProcessEpoch(state *pb.BeaconState) bool { // Spec pseudocode definition: // If state.slot % ETH1_DATA_VOTING_PERIOD == 0: func CanProcessEth1Data(state *pb.BeaconState) bool { - return state.Slot%config.Eth1DataVotingPeriod == 0 + return state.Slot%params.BeaconConfig().Eth1DataVotingPeriod == 0 } // CanProcessValidatorRegistry checks the eligibility to process validator registry. @@ -49,11 +47,11 @@ func CanProcessValidatorRegistry(state *pb.BeaconState) bool { if state.FinalizedEpoch <= state.ValidatorRegistryUpdateEpoch { return false } - shardsProcessed := helpers.CurrentEpochCommitteeCount(state) * config.EpochLength + shardsProcessed := helpers.CurrentEpochCommitteeCount(state) * params.BeaconConfig().EpochLength startShard := state.CurrentEpochStartShard for i := startShard; i < shardsProcessed; i++ { - if state.LatestCrosslinks[i%config.ShardCount].Epoch <= + if state.LatestCrosslinks[i%params.BeaconConfig().ShardCount].Epoch <= state.ValidatorRegistryUpdateEpoch { return false } @@ -73,9 +71,9 @@ func CanProcessValidatorRegistry(state *pb.BeaconState) bool { // Set state.eth1_data_votes = []. // func ProcessEth1Data(state *pb.BeaconState) *pb.BeaconState { - if state.Slot%config.Eth1DataVotingPeriod == 0 { + if state.Slot%params.BeaconConfig().Eth1DataVotingPeriod == 0 { for _, eth1DataVote := range state.Eth1DataVotes { - if eth1DataVote.VoteCount*2 > config.Eth1DataVotingPeriod { + if eth1DataVote.VoteCount*2 > params.BeaconConfig().Eth1DataVotingPeriod { state.LatestEth1Data.DepositRootHash32 = eth1DataVote.Eth1Data.DepositRootHash32 state.LatestEth1Data.BlockHash32 = eth1DataVote.Eth1Data.BlockHash32 } @@ -217,7 +215,7 @@ func ProcessEjections(state *pb.BeaconState) (*pb.BeaconState, error) { var err error activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, state.Slot) for _, index := range activeValidatorIndices { - if state.ValidatorBalances[index] < config.EjectionBalance { + if state.ValidatorBalances[index] < params.BeaconConfig().EjectionBalance { state, err = validators.ExitValidator(state, index) if err != nil { return nil, fmt.Errorf("could not exit validator %d: %v", index, err) @@ -254,14 +252,14 @@ func ProcessValidatorRegistry( state.CurrentCalculationEpoch = state.Slot nextStartShard := (state.CurrentEpochStartShard + - helpers.CurrentEpochCommitteeCount(state)*config.EpochLength) % - config.EpochLength + helpers.CurrentEpochCommitteeCount(state)*params.BeaconConfig().EpochLength) % + params.BeaconConfig().EpochLength state.CurrentEpochStartShard = nextStartShard var randaoMixSlot uint64 - if state.CurrentCalculationEpoch > config.SeedLookahead { + if state.CurrentCalculationEpoch > params.BeaconConfig().SeedLookahead { randaoMixSlot = state.CurrentCalculationEpoch - - config.SeedLookahead + params.BeaconConfig().SeedLookahead } mix, err := helpers.RandaoMix(state, randaoMixSlot) if err != nil { @@ -288,17 +286,17 @@ func ProcessValidatorRegistry( // LATEST_RANDAO_MIXES_LENGTH]. func ProcessPartialValidatorRegistry(state *pb.BeaconState) *pb.BeaconState { epochsSinceLastRegistryChange := (state.Slot - state.ValidatorRegistryUpdateEpoch) / - config.EpochLength + params.BeaconConfig().EpochLength if mathutil.IsPowerOf2(epochsSinceLastRegistryChange) { state.CurrentCalculationEpoch = state.Slot var randaoIndex uint64 - if state.CurrentCalculationEpoch > config.SeedLookahead { - randaoIndex = state.CurrentCalculationEpoch - config.SeedLookahead + if state.CurrentCalculationEpoch > params.BeaconConfig().SeedLookahead { + randaoIndex = state.CurrentCalculationEpoch - params.BeaconConfig().SeedLookahead } - randaoMix := state.LatestRandaoMixesHash32S[randaoIndex%config.LatestRandaoMixesLength] + randaoMix := state.LatestRandaoMixesHash32S[randaoIndex%params.BeaconConfig().LatestRandaoMixesLength] state.CurrentEpochSeedHash32 = randaoMix } return state @@ -330,9 +328,9 @@ func CleanupAttestations(state *pb.BeaconState) *pb.BeaconState { // Set state.latest_penalized_exit_balances[(e+1) % LATEST_PENALIZED_EXIT_LENGTH] = // state.latest_penalized_exit_balances[e % LATEST_PENALIZED_EXIT_LENGTH] func UpdatePenalizedExitBalances(state *pb.BeaconState) *pb.BeaconState { - epoch := state.Slot / config.EpochLength - nextPenalizedEpoch := (epoch + 1) % config.LatestPenalizedExitLength - currPenalizedEpoch := (epoch) % config.LatestPenalizedExitLength + epoch := state.Slot / params.BeaconConfig().EpochLength + nextPenalizedEpoch := (epoch + 1) % params.BeaconConfig().LatestPenalizedExitLength + currPenalizedEpoch := (epoch) % params.BeaconConfig().LatestPenalizedExitLength state.LatestPenalizedBalances[nextPenalizedEpoch] = state.LatestPenalizedBalances[currPenalizedEpoch] return state From b03e09cc7297690baefe13afae347ed2b8285caa Mon Sep 17 00:00:00 2001 From: Terence Tsao Date: Fri, 8 Feb 2019 15:52:09 +0100 Subject: [PATCH 2/5] test p2p --- beacon-chain/core/state/transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon-chain/core/state/transition.go b/beacon-chain/core/state/transition.go index 789c6cc9f4d6..db6a030ce568 100644 --- a/beacon-chain/core/state/transition.go +++ b/beacon-chain/core/state/transition.go @@ -302,7 +302,7 @@ func ProcessEpoch(state *pb.BeaconState) (*pb.BeaconState, error) { if e.CanProcessValidatorRegistry(state) { state, err = e.ProcessValidatorRegistry(state) if err != nil { - return nil, fmt.Errorf("could not process validator registry: %v", err) + return nil, fmt.Errorf("can not process validator registry: %v", err) } } else { state = e.ProcessPartialValidatorRegistry(state) From 5fdcf3e134909d7a0e33f9cde3b28ea9eac43ef4 Mon Sep 17 00:00:00 2001 From: Terence Tsao Date: Mon, 11 Feb 2019 08:03:07 +0100 Subject: [PATCH 3/5] implemented NextEpochCommitteeAssignment --- beacon-chain/chaintest/backend/helpers.go | 2 + beacon-chain/core/helpers/committee.go | 73 +++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/beacon-chain/chaintest/backend/helpers.go b/beacon-chain/chaintest/backend/helpers.go index 10c946ba6f22..716acc890c18 100644 --- a/beacon-chain/chaintest/backend/helpers.go +++ b/beacon-chain/chaintest/backend/helpers.go @@ -139,3 +139,5 @@ func generateInitialSimulatedDeposits(numDeposits uint64) ([]*pb.Deposit, error) } return deposits, nil } + + diff --git a/beacon-chain/core/helpers/committee.go b/beacon-chain/core/helpers/committee.go index 17c38f3c69bb..9cb7ecc85996 100644 --- a/beacon-chain/core/helpers/committee.go +++ b/beacon-chain/core/helpers/committee.go @@ -360,3 +360,76 @@ func AttestationParticipants( } return participants, nil } + +// NextEpochCommitteeAssignment query slots in the next epoch +// for it to discover which shard and slot a validator gets assigned. +// +// Spec pseudocode definition: +// def get_next_epoch_committee_assignment( +// state: BeaconState, +// validator_index: ValidatorIndex, +// registry_change: bool) -> Tuple[List[ValidatorIndex], ShardNumber, SlotNumber, bool]: +// """ +// Return the committee assignment in the next epoch for ``validator_index`` and ``registry_change``. +// ``assignment`` returned is a tuple of the following form: +// * ``assignment[0]`` is the list of validators in the committee +// * ``assignment[1]`` is the shard to which the committee is assigned +// * ``assignment[2]`` is the slot at which the committee is assigned +// * ``assignment[3]`` is a bool signalling if the validator is expected to propose +// a beacon block at the assigned slot. +// """ +// current_epoch = get_current_epoch(state) +// next_epoch = current_epoch + 1 +// next_epoch_start_slot = get_epoch_start_slot(next_epoch) +// for slot in range(next_epoch_start_slot, next_epoch_start_slot + EPOCH_LENGTH): +// crosslink_committees = get_crosslink_committees_at_slot( +// state, +// slot, +// registry_change=registry_change, +// ) +// selected_committees = [ +// committee # Tuple[List[ValidatorIndex], ShardNumber] +// for committee in crosslink_committees +// if validator_index in committee[0] +// ] +// if len(selected_committees) > 0: +// validators = selected_committees[0][0] +// shard = selected_committees[0][1] +// first_committee_at_slot = crosslink_committees[0][0] # List[ValidatorIndex] +// is_proposer = first_committee_at_slot[slot % len(first_committee_at_slot)] == validator_index +// +// assignment = (validators, shard, slot, is_proposer) +// return assignment +func NextEpochCommitteeAssignment( + state *pb.BeaconState, + index uint64, + registryChange bool) ([]uint64, uint64, uint64, bool, error) { + var selectedCommittees []*CrosslinkCommittee + nextEpoch := NextEpoch(state) + nextEpochStartSlot := StartSlot(nextEpoch) + for slot := nextEpochStartSlot; slot < nextEpochStartSlot+params.BeaconConfig().EpochLength; nextEpochStartSlot++ { + crosslinkCommittees, err := CrosslinkCommitteesAtSlot( + state, nextEpochStartSlot, registryChange) + if err != nil { + return []uint64{}, 0, 0, false, fmt.Errorf("could not get crosslink committee: %v", err) + } + + for _, committee := range crosslinkCommittees { + for _, idx := range committee.Committee { + if idx == index { + selectedCommittees = append(selectedCommittees, committee) + } + } + } + + if len(selectedCommittees) > 0 { + validators := selectedCommittees[0].Committee + shard := selectedCommittees[0].Shard + firstCommitteeAtSlot := crosslinkCommittees[0].Committee + isProposer := firstCommitteeAtSlot[slot% + uint64(len(firstCommitteeAtSlot))] == index + return validators, shard, slot, isProposer, nil + } + } + return []uint64{}, 0, 0, false, fmt.Errorf("could not get assignment validator %d", index) +} From d46921b8e817513eba61eb04984085878acb708d Mon Sep 17 00:00:00 2001 From: Terence Tsao Date: Mon, 11 Feb 2019 17:56:39 +0100 Subject: [PATCH 4/5] implemented tests --- beacon-chain/core/helpers/committee.go | 23 +++--- beacon-chain/core/helpers/committee_test.go | 90 +++++++++++++++++++++ 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/beacon-chain/core/helpers/committee.go b/beacon-chain/core/helpers/committee.go index 9cb7ecc85996..ecf234eda267 100644 --- a/beacon-chain/core/helpers/committee.go +++ b/beacon-chain/core/helpers/committee.go @@ -407,28 +407,27 @@ func NextEpochCommitteeAssignment( var selectedCommittees []*CrosslinkCommittee nextEpoch := NextEpoch(state) nextEpochStartSlot := StartSlot(nextEpoch) - for slot := nextEpochStartSlot; slot < nextEpochStartSlot+params.BeaconConfig().EpochLength; nextEpochStartSlot++ { + for slot := nextEpochStartSlot; slot < nextEpochStartSlot+params.BeaconConfig().EpochLength; slot++ { crosslinkCommittees, err := CrosslinkCommitteesAtSlot( - state, nextEpochStartSlot, registryChange) + state, slot, registryChange) if err != nil { return []uint64{}, 0, 0, false, fmt.Errorf("could not get crosslink committee: %v", err) } - for _, committee := range crosslinkCommittees { for _, idx := range committee.Committee { if idx == index { selectedCommittees = append(selectedCommittees, committee) } - } - } - if len(selectedCommittees) > 0 { - validators := selectedCommittees[0].Committee - shard := selectedCommittees[0].Shard - firstCommitteeAtSlot := crosslinkCommittees[0].Committee - isProposer := firstCommitteeAtSlot[slot% - uint64(len(firstCommitteeAtSlot))] == index - return validators, shard, slot, isProposer, nil + if len(selectedCommittees) > 0 { + validators := selectedCommittees[0].Committee + shard := selectedCommittees[0].Shard + firstCommitteeAtSlot := crosslinkCommittees[0].Committee + isProposer := firstCommitteeAtSlot[slot% + uint64(len(firstCommitteeAtSlot))] == index + return validators, shard, slot, isProposer, nil + } + } } } return []uint64{}, 0, 0, false, fmt.Errorf("could not get assignment validator %d", index) diff --git a/beacon-chain/core/helpers/committee_test.go b/beacon-chain/core/helpers/committee_test.go index c27846fab26a..18645d35ff37 100644 --- a/beacon-chain/core/helpers/committee_test.go +++ b/beacon-chain/core/helpers/committee_test.go @@ -314,3 +314,93 @@ func TestAttestationParticipants_IncorrectBitfield(t *testing.T) { t.Error("attestation participants should have failed with incorrect bitfield") } } + +func TestNextEpochCommitteeAssignment_ok(t *testing.T) { + // Initialize test with 128 validators, each slot and each shard gets 2 validators. + validators := make([]*pb.Validator, 2*params.BeaconConfig().EpochLength) + for i := 0; i < len(validators); i++ { + validators[i] = &pb.Validator{ + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + } + } + state := &pb.BeaconState{ + ValidatorRegistry: validators, + Slot: params.BeaconConfig().EpochLength, + } + + tests := []struct { + index uint64 + slot uint64 + committee []uint64 + shard uint64 + isProposer bool + }{ + { + index: 0, + slot: 146, + committee: []uint64{105, 0}, + shard: 18, + isProposer: false, + }, + { + index: 105, + slot: 146, + committee: []uint64{105, 0}, + shard: 18, + isProposer: true, + }, + { + index: 64, + slot: 139, + committee: []uint64{64, 52}, + shard: 11, + isProposer: false, + }, + { + index: 11, + slot: 130, + committee: []uint64{11, 121}, + shard: 2, + isProposer: true, + }, + } + + for _, tt := range tests { + committee, shard, slot, isProposer, err := NextEpochCommitteeAssignment( + state, tt.index, false) + if err != nil { + t.Fatalf("failed to execute NextEpochCommitteeAssignment: %v", err) + } + if shard != tt.shard { + t.Errorf("wanted shard %d, got shard %d", + tt.shard, shard) + } + if slot != tt.slot { + t.Errorf("wanted slot %d, got slot %d", + tt.slot, slot) + } + if isProposer != tt.isProposer { + t.Errorf("wanted isProposer %v, got isProposer %v", + tt.isProposer, isProposer) + } + if !reflect.DeepEqual(committee, tt.committee) { + t.Errorf("wanted committee %v, got committee %v", + tt.committee, committee) + } + } +} + +func TestNextEpochCommitteeAssignment_CantFindValidator(t *testing.T) { + state := &pb.BeaconState{ + Slot: params.BeaconConfig().EpochLength, + } + index := uint64(10000) + want := fmt.Sprintf( + "could not get assignment validator %d", + index, + ) + if _, _, _, _, err := NextEpochCommitteeAssignment( + state, index, false); !strings.Contains(err.Error(), want) { + t.Errorf("Expected %s, received %v", want, err) + } +} From b53809b4a0d5856032825f33b150e144e6be9c49 Mon Sep 17 00:00:00 2001 From: Terence Tsao Date: Mon, 11 Feb 2019 17:57:55 +0100 Subject: [PATCH 5/5] empty lines --- beacon-chain/chaintest/backend/helpers.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/beacon-chain/chaintest/backend/helpers.go b/beacon-chain/chaintest/backend/helpers.go index 716acc890c18..10c946ba6f22 100644 --- a/beacon-chain/chaintest/backend/helpers.go +++ b/beacon-chain/chaintest/backend/helpers.go @@ -139,5 +139,3 @@ func generateInitialSimulatedDeposits(numDeposits uint64) ([]*pb.Deposit, error) } return deposits, nil } - -