From 30e34745e56c093b252c732b3b6e9b8c8a737e65 Mon Sep 17 00:00:00 2001 From: Raul Jordan Date: Thu, 22 Nov 2018 11:18:06 -0800 Subject: [PATCH] Refactor More Casper Functions Into Beacon-Chain/Core (#890) --- beacon-chain/casper/BUILD.bazel | 40 ------- beacon-chain/core/incentives/BUILD.bazel | 2 + beacon-chain/core/incentives/incentives.go | 112 +++++++++++------- .../core/incentives/incentives_test.go | 6 +- beacon-chain/core/state/BUILD.bazel | 24 ++++ .../state/processing.go} | 74 +----------- .../state/processing_test.go} | 112 +----------------- beacon-chain/core/validators/BUILD.bazel | 12 +- .../validators/committees.go} | 21 ++-- .../validators/committees_test.go} | 9 +- beacon-chain/types/BUILD.bazel | 7 +- beacon-chain/types/crystallized_state.go | 35 ++++-- beacon-chain/types/crystallized_state_test.go | 4 +- 13 files changed, 161 insertions(+), 297 deletions(-) delete mode 100644 beacon-chain/casper/BUILD.bazel create mode 100644 beacon-chain/core/state/BUILD.bazel rename beacon-chain/{casper/state_transition.go => core/state/processing.go} (50%) rename beacon-chain/{casper/state_transition_test.go => core/state/processing_test.go} (55%) rename beacon-chain/{casper/sharding.go => core/validators/committees.go} (87%) rename beacon-chain/{casper/sharding_test.go => core/validators/committees_test.go} (95%) diff --git a/beacon-chain/casper/BUILD.bazel b/beacon-chain/casper/BUILD.bazel deleted file mode 100644 index b81e63130258..000000000000 --- a/beacon-chain/casper/BUILD.bazel +++ /dev/null @@ -1,40 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "sharding.go", - "state_transition.go", - ], - importpath = "github.com/prysmaticlabs/prysm/beacon-chain/casper", - visibility = ["//beacon-chain:__subpackages__"], - deps = [ - "//beacon-chain/core/incentives:go_default_library", - "//beacon-chain/core/validators:go_default_library", - "//beacon-chain/utils:go_default_library", - "//proto/beacon/p2p/v1:go_default_library", - "//shared/bitutil:go_default_library", - "//shared/params:go_default_library", - "@com_github_ethereum_go_ethereum//common:go_default_library", - ], -) - -go_test( - name = "go_default_test", - size = "large", - timeout = "short", - srcs = [ - "sharding_test.go", - "state_transition_test.go", - ], - embed = [":go_default_library"], - race = "off", # TODO(#604): fix issues with tests failing with race on. - deps = [ - "//beacon-chain/core/validators:go_default_library", - "//beacon-chain/utils:go_default_library", - "//proto/beacon/p2p/v1:go_default_library", - "//shared/bytes:go_default_library", - "//shared/params:go_default_library", - "@com_github_ethereum_go_ethereum//common:go_default_library", - ], -) diff --git a/beacon-chain/core/incentives/BUILD.bazel b/beacon-chain/core/incentives/BUILD.bazel index 62204424d20b..fa10cad77a59 100644 --- a/beacon-chain/core/incentives/BUILD.bazel +++ b/beacon-chain/core/incentives/BUILD.bazel @@ -6,7 +6,9 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/incentives", visibility = ["//beacon-chain:__subpackages__"], deps = [ + "//beacon-chain/utils:go_default_library", "//proto/beacon/p2p/v1:go_default_library", + "//shared/bitutil:go_default_library", "//shared/mathutil:go_default_library", "//shared/params:go_default_library", ], diff --git a/beacon-chain/core/incentives/incentives.go b/beacon-chain/core/incentives/incentives.go index ad195afdd9b7..5528d6fb347c 100644 --- a/beacon-chain/core/incentives/incentives.go +++ b/beacon-chain/core/incentives/incentives.go @@ -5,11 +5,42 @@ package incentives import ( + "github.com/prysmaticlabs/prysm/beacon-chain/utils" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/bitutil" "github.com/prysmaticlabs/prysm/shared/mathutil" "github.com/prysmaticlabs/prysm/shared/params" ) +// TallyVoteBalances calculates all the votes behind a block and +// then rewards validators for their participation in voting for that block. +func TallyVoteBalances( + blockHash [32]byte, + blockVoteCache utils.BlockVoteCache, + validators []*pb.ValidatorRecord, + activeValidatorIndices []uint32, + totalActiveValidatorDeposit uint64, + timeSinceFinality uint64, +) (uint64, []*pb.ValidatorRecord) { + blockVote, ok := blockVoteCache[blockHash] + if !ok { + return 0, validators + } + + blockVoteBalance := blockVote.VoteTotalDeposit + voterIndices := blockVote.VoterIndices + validators = CalculateRewards( + voterIndices, + activeValidatorIndices, + validators, + totalActiveValidatorDeposit, + blockVoteBalance, + timeSinceFinality, + ) + + return blockVoteBalance, validators +} + // CalculateRewards adjusts validators balances by applying rewards or penalties // based on FFG incentive structure. // FFG Rewards scheme rewards validator who have voted on blocks, and penalises those validators @@ -35,7 +66,7 @@ func CalculateRewards( if voterIndex == validatorIndex { voted = true balance := validators[validatorIndex].GetBalance() - newBalance := calculateBalance(balance, rewardQuotient, totalParticipatedDeposit, totalActiveValidatorDeposit) + newBalance := int64(balance) + int64(balance/rewardQuotient)*(2*int64(totalParticipatedDeposit)-int64(totalActiveValidatorDeposit))/int64(totalActiveValidatorDeposit) validators[validatorIndex].Balance = uint64(newBalance) break } @@ -71,6 +102,35 @@ func CalculateRewards( return validators } +// ApplyCrosslinkRewardsAndPenalties applies the appropriate rewards and +// penalties according to the attestation for a shard. +func ApplyCrosslinkRewardsAndPenalties( + crosslinkRecords []*pb.CrosslinkRecord, + slot uint64, + attesterIndices []uint32, + attestation *pb.AggregatedAttestation, + validators []*pb.ValidatorRecord, + totalActiveValidatorDeposit uint64, + totalBalance uint64, + voteBalance uint64, +) error { + rewardQuotient := RewardQuotient(totalActiveValidatorDeposit) + for _, attesterIndex := range attesterIndices { + timeSinceLastConfirmation := slot - crosslinkRecords[attestation.Shard].GetSlot() + + checkBit, err := bitutil.CheckBit(attestation.AttesterBitfield, int(attesterIndex)) + if err != nil { + return err + } + if checkBit { + RewardValidatorCrosslink(totalBalance, voteBalance, rewardQuotient, validators[attesterIndex]) + } else { + PenaliseValidatorCrosslink(timeSinceLastConfirmation, rewardQuotient, validators[attesterIndex]) + } + } + return nil +} + // RewardQuotient returns the reward quotient for validators which will be used to // reward validators for voting on blocks, or penalise them for being offline. func RewardQuotient(totalActiveValidatorDeposit uint64) uint64 { @@ -93,55 +153,27 @@ func QuadraticPenalty(numberOfSlots uint64) uint64 { return slotFactor / penaltyQuotient } -// RewardValidatorCrosslink applies rewards to validators part of a shard -// committee for voting on a shard. +// RewardValidatorCrosslink applies rewards to validators part of a shard committee for voting on a shard. +// TODO(#538): Change this to big.Int as tests using 64 bit integers fail due to integer overflow. func RewardValidatorCrosslink( totalDeposit uint64, participatedDeposits uint64, rewardQuotient uint64, validator *pb.ValidatorRecord, -) *pb.ValidatorRecord { - balance := calculateBalance(validator.Balance, rewardQuotient, participatedDeposits, totalDeposit) - return &pb.ValidatorRecord{ - Pubkey: validator.Pubkey, - WithdrawalShard: validator.WithdrawalShard, - WithdrawalAddress: validator.WithdrawalAddress, - RandaoCommitment: validator.RandaoCommitment, - Balance: balance, - Status: validator.Status, - ExitSlot: validator.ExitSlot, - } +) { + currentBalance := int64(validator.Balance) + currentBalance += int64(currentBalance) / int64(rewardQuotient) * (2*int64(participatedDeposits) - int64(totalDeposit)) / int64(totalDeposit) + validator.Balance = uint64(currentBalance) } -// PenaliseValidatorCrosslink applies penalties to validators part of a shard committee -// for not voting on a shard. +// PenaliseValidatorCrosslink applies penalties to validators part of a shard committee for not voting on a shard. func PenaliseValidatorCrosslink( timeSinceLastConfirmation uint64, rewardQuotient uint64, validator *pb.ValidatorRecord, -) *pb.ValidatorRecord { +) { + newBalance := validator.Balance quadraticQuotient := QuadraticPenaltyQuotient() - balance := validator.Balance - balance -= balance/rewardQuotient + balance*timeSinceLastConfirmation/quadraticQuotient - return &pb.ValidatorRecord{ - Pubkey: validator.Pubkey, - WithdrawalShard: validator.WithdrawalShard, - WithdrawalAddress: validator.WithdrawalAddress, - RandaoCommitment: validator.RandaoCommitment, - Balance: balance, - Status: validator.Status, - ExitSlot: validator.ExitSlot, - } -} - -// calculateBalance applies the Casper FFG reward calculation based on reward quotients -// and total deposits from validators. -func calculateBalance( - balance uint64, - rewardQuotient uint64, - totalParticipatedDeposit uint64, - totalActiveValidatorDeposit uint64, -) uint64 { - participationNumerator := 2*int64(totalParticipatedDeposit) - int64(totalActiveValidatorDeposit) - return uint64(int64(balance) + int64(balance/rewardQuotient)*participationNumerator/int64(totalActiveValidatorDeposit)) + newBalance -= newBalance/rewardQuotient + newBalance*timeSinceLastConfirmation/quadraticQuotient + validator.Balance = newBalance } diff --git a/beacon-chain/core/incentives/incentives_test.go b/beacon-chain/core/incentives/incentives_test.go index 9bb42c114492..24ee8f410082 100644 --- a/beacon-chain/core/incentives/incentives_test.go +++ b/beacon-chain/core/incentives/incentives_test.go @@ -57,7 +57,7 @@ func TestComputeValidatorRewardsAndPenalties(t *testing.T) { t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidators[0].Balance, expectedBalance) } - expectedBalance = calculateBalance(defaultBalance, rewQuotient, participatedDeposit, totalDeposit) + expectedBalance = uint64(int64(defaultBalance) + int64(defaultBalance/rewQuotient)*(2*int64(participatedDeposit)-int64(totalDeposit))/int64(totalDeposit)) if rewardedValidators[6].Balance != expectedBalance { t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidators[6].Balance, expectedBalance) @@ -142,7 +142,7 @@ func TestRewardCrosslink(t *testing.T) { Balance: 1e18, } - validator = RewardValidatorCrosslink(totalDeposit, participatedDeposit, rewardQuotient, validator) + RewardValidatorCrosslink(totalDeposit, participatedDeposit, rewardQuotient, validator) if validator.Balance != 1e18 { t.Errorf("validator balances have changed when they were not supposed to %d", validator.Balance) @@ -158,7 +158,7 @@ func TestPenaltyCrosslink(t *testing.T) { timeSinceConfirmation := uint64(10) quadraticQuotient := QuadraticPenaltyQuotient() - validator = PenaliseValidatorCrosslink(timeSinceConfirmation, rewardQuotient, validator) + PenaliseValidatorCrosslink(timeSinceConfirmation, rewardQuotient, validator) expectedBalance := 1e18 - (1e18/rewardQuotient + 1e18*timeSinceConfirmation/quadraticQuotient) if validator.Balance != expectedBalance { diff --git a/beacon-chain/core/state/BUILD.bazel b/beacon-chain/core/state/BUILD.bazel new file mode 100644 index 000000000000..7cfc40839575 --- /dev/null +++ b/beacon-chain/core/state/BUILD.bazel @@ -0,0 +1,24 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["processing.go"], + importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/state", + visibility = ["//beacon-chain:__subpackages__"], + deps = [ + "//beacon-chain/core/validators:go_default_library", + "//proto/beacon/p2p/v1:go_default_library", + "//shared/params:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["processing_test.go"], + embed = [":go_default_library"], + deps = [ + "//proto/beacon/p2p/v1:go_default_library", + "//shared/bytes:go_default_library", + "//shared/params:go_default_library", + ], +) diff --git a/beacon-chain/casper/state_transition.go b/beacon-chain/core/state/processing.go similarity index 50% rename from beacon-chain/casper/state_transition.go rename to beacon-chain/core/state/processing.go index 3dd4a06d1fea..1d7391ab9e98 100644 --- a/beacon-chain/casper/state_transition.go +++ b/beacon-chain/core/state/processing.go @@ -1,51 +1,18 @@ -package casper +package state import ( "encoding/binary" - "github.com/prysmaticlabs/prysm/beacon-chain/core/incentives" v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" - "github.com/prysmaticlabs/prysm/beacon-chain/utils" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/bitutil" "github.com/prysmaticlabs/prysm/shared/params" ) -// TallyVoteBalances calculates all the votes behind a block and then rewards validators for their -// participation in voting for that block. -func TallyVoteBalances( - blockHash [32]byte, - blockVoteCache utils.BlockVoteCache, - validators []*pb.ValidatorRecord, - timeSinceFinality uint64) (uint64, []*pb.ValidatorRecord) { - - blockVote, ok := blockVoteCache[blockHash] - if !ok { - return 0, validators - } - - blockVoteBalance := blockVote.VoteTotalDeposit - voterIndices := blockVote.VoterIndices - activeValidatorIndices := v.ActiveValidatorIndices(validators) - totalDeposit := v.TotalActiveValidatorDeposit(validators) - validators = incentives.CalculateRewards( - voterIndices, - activeValidatorIndices, - validators, - totalDeposit, - blockVoteBalance, - timeSinceFinality, - ) - - return blockVoteBalance, validators -} - // FinalizeAndJustifySlots justifies slots and sets the justified streak according to Casper FFG // conditions. It also finalizes slots when the conditions are fulfilled. func FinalizeAndJustifySlots( slot uint64, justifiedSlot uint64, finalizedSlot uint64, justifiedStreak uint64, blockVoteBalance uint64, totalDeposits uint64) (uint64, uint64, uint64) { - cycleLength := params.BeaconConfig().CycleLength if 3*blockVoteBalance >= 2*totalDeposits { @@ -66,41 +33,10 @@ func FinalizeAndJustifySlots( return justifiedSlot, finalizedSlot, justifiedStreak } -// ApplyCrosslinkRewardsAndPenalties applies the appropriate rewards and penalties according to the attestation -// for a shard. -func ApplyCrosslinkRewardsAndPenalties( - crosslinkRecords []*pb.CrosslinkRecord, - slot uint64, - attesterIndices []uint32, - attestation *pb.AggregatedAttestation, - validators []*pb.ValidatorRecord, - totalBalance uint64, - voteBalance uint64) error { - - totalDeposit := v.TotalActiveValidatorDeposit(validators) - rewardQuotient := incentives.RewardQuotient(totalDeposit) - - for _, attesterIndex := range attesterIndices { - timeSinceLastConfirmation := slot - crosslinkRecords[attestation.Shard].GetSlot() - - checkBit, err := bitutil.CheckBit(attestation.AttesterBitfield, int(attesterIndex)) - if err != nil { - return err - } - if checkBit { - validators[attesterIndex] = incentives.RewardValidatorCrosslink(totalBalance, voteBalance, rewardQuotient, validators[attesterIndex]) - } else { - validators[attesterIndex] = incentives.PenaliseValidatorCrosslink(timeSinceLastConfirmation, rewardQuotient, validators[attesterIndex]) - } - } - return nil -} - // ProcessCrosslink checks the vote balances and if there is a supermajority it sets the crosslink // for that shard. func ProcessCrosslink(slot uint64, voteBalance uint64, totalBalance uint64, attestation *pb.AggregatedAttestation, crosslinkRecords []*pb.CrosslinkRecord) []*pb.CrosslinkRecord { - // if 2/3 of committee voted on this crosslink, update the crosslink // with latest dynasty number, shard block hash, and slot number. voteMajority := 3*voteBalance >= 2*totalBalance @@ -115,18 +51,18 @@ func ProcessCrosslink(slot uint64, voteBalance uint64, totalBalance uint64, // ProcessSpecialRecords processes the pending special record objects, // this is called during crystallized state transition. -func ProcessSpecialRecords(slotNumber uint64, validators []*pb.ValidatorRecord, pendingSpecials []*pb.SpecialRecord) ([]*pb.ValidatorRecord, error) { +func ProcessSpecialRecords(slotNumber uint64, validators []*pb.ValidatorRecord, + pendingSpecials []*pb.SpecialRecord) ([]*pb.ValidatorRecord, error) { // For each special record object in active state. for _, specialRecord := range pendingSpecials { - // Covers validators submitted logouts from last cycle. if specialRecord.Kind == uint32(params.Logout) { validatorIndex := binary.BigEndian.Uint64(specialRecord.Data[0]) exitedValidator := v.ExitValidator(validators[validatorIndex], slotNumber, false) validators[validatorIndex] = exitedValidator - // TODO(#633): Verify specialRecord.Data[1] as signature. BLSVerify(pubkey=validator.pubkey, msg=hash(LOGOUT_MESSAGE + bytes8(version)) + // TODO(#633): Verify specialRecord.Data[1] as signature. + // BLSVerify(pubkey=validator.pubkey, msg=hash(LOGOUT_MESSAGE + bytes8(version)) } - } return validators, nil } diff --git a/beacon-chain/casper/state_transition_test.go b/beacon-chain/core/state/processing_test.go similarity index 55% rename from beacon-chain/casper/state_transition_test.go rename to beacon-chain/core/state/processing_test.go index ff8662d55dfc..7ccdb3415389 100644 --- a/beacon-chain/casper/state_transition_test.go +++ b/beacon-chain/core/state/processing_test.go @@ -1,65 +1,14 @@ -package casper +package state import ( "bytes" "testing" - "github.com/prysmaticlabs/prysm/beacon-chain/utils" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" b "github.com/prysmaticlabs/prysm/shared/bytes" "github.com/prysmaticlabs/prysm/shared/params" ) -func TestTallyVoteBalances(t *testing.T) { - - var validators []*pb.ValidatorRecord - var blockHash [32]byte - - blockVoteCache := utils.NewBlockVoteCache() - initialBalance := uint64(1e9) - for i := 0; i < 1000; i++ { - validator := &pb.ValidatorRecord{ - WithdrawalShard: 0, - Balance: initialBalance} - - validators = append(validators, validator) - } - - validators[20].Status = uint64(params.Active) - validators[10].Status = uint64(params.Active) - - blockVote := &utils.BlockVote{ - VoterIndices: []uint32{20, 10}, - VoteTotalDeposit: 300, - } - copy(blockHash[:], []byte{'t', 'e', 's', 't', 'i', 'n', 'g'}) - - blockVoteCache[blockHash] = blockVote - - zeroBalance, _ := TallyVoteBalances([32]byte{}, blockVoteCache, validators, 2) - - if zeroBalance != 0 { - t.Fatalf("votes have been calculated despite blockhash not existing in cache") - } - - voteBalance, newValidators := TallyVoteBalances(blockHash, blockVoteCache, validators, 2) - if voteBalance != 300 { - t.Fatalf("vote balances is not the amount expected %d", voteBalance) - } - - if newValidators[1].Balance != initialBalance { - t.Fatalf("validator balance changed %d ", newValidators[1].Balance) - } - - if newValidators[20].Balance == initialBalance { - t.Fatalf("validator balance not changed %d ", newValidators[20].Balance) - } - - if newValidators[10].Balance == initialBalance { - t.Errorf("validator balance not changed %d ", newValidators[10].Balance) - } -} - func TestFinalizeAndJustifySlots(t *testing.T) { slot := uint64(10) justifiedSlot := uint64(8) @@ -120,65 +69,6 @@ func TestFinalizeAndJustifySlots(t *testing.T) { } -func TestApplyCrosslinkRewardsAndPenalties(t *testing.T) { - var validators []*pb.ValidatorRecord - initialBalance := uint64(1e9) - totalBalance := uint64(5e9) - voteBalance := uint64(4e9) - indices := []uint32{20, 10} - - for i := 0; i < 1000; i++ { - validator := &pb.ValidatorRecord{ - WithdrawalShard: 0, - Balance: initialBalance} - - validators = append(validators, validator) - } - - validators[20].Status = uint64(params.Active) - validators[10].Status = uint64(params.Active) - - crossLinks := []*pb.CrosslinkRecord{ - { - ShardBlockHash: []byte{'A'}, - Slot: 10, - }, - { - ShardBlockHash: []byte{'B'}, - Slot: 10, - }, - { - ShardBlockHash: []byte{'C'}, - Slot: 10, - }, - { - ShardBlockHash: []byte{'D'}, - Slot: 10, - }, - } - - attestation := &pb.AggregatedAttestation{ - Slot: 10, - Shard: 1, - AttesterBitfield: []byte{100, 128, 8}, - } - - ApplyCrosslinkRewardsAndPenalties(crossLinks, 12, indices, attestation, validators, totalBalance, voteBalance) - - if validators[20].Balance <= initialBalance { - t.Fatalf("validator balance has not been updated %d", validators[20].Balance) - } - - if validators[10].Balance >= initialBalance { - t.Fatalf("validator balance has not been updated %d", validators[10].Balance) - } - - if validators[1].Balance != initialBalance { - t.Fatalf("validator balance updated when it was not supposed to %d", validators[1].Balance) - } - -} - func TestCrosslinks(t *testing.T) { totalBalance := uint64(5e9) voteBalance := uint64(4e9) diff --git a/beacon-chain/core/validators/BUILD.bazel b/beacon-chain/core/validators/BUILD.bazel index f67f114b6376..9b85e59682ea 100644 --- a/beacon-chain/core/validators/BUILD.bazel +++ b/beacon-chain/core/validators/BUILD.bazel @@ -2,10 +2,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = ["validator.go"], + srcs = [ + "committees.go", + "validator.go", + ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/validators", visibility = ["//beacon-chain:__subpackages__"], deps = [ + "//beacon-chain/utils:go_default_library", "//proto/beacon/p2p/v1:go_default_library", "//proto/beacon/rpc/v1:go_default_library", "//shared/bitutil:go_default_library", @@ -16,11 +20,15 @@ go_library( go_test( name = "go_default_test", - srcs = ["validator_test.go"], + srcs = [ + "committees_test.go", + "validator_test.go", + ], embed = [":go_default_library"], deps = [ "//proto/beacon/p2p/v1:go_default_library", "//shared/bitutil:go_default_library", "//shared/params:go_default_library", + "@com_github_ethereum_go_ethereum//common:go_default_library", ], ) diff --git a/beacon-chain/casper/sharding.go b/beacon-chain/core/validators/committees.go similarity index 87% rename from beacon-chain/casper/sharding.go rename to beacon-chain/core/validators/committees.go index 4422523104c7..fbb31a8a4f7e 100644 --- a/beacon-chain/casper/sharding.go +++ b/beacon-chain/core/validators/committees.go @@ -1,31 +1,31 @@ -package casper +package validators import ( - "github.com/ethereum/go-ethereum/common" - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" "github.com/prysmaticlabs/prysm/beacon-chain/utils" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" ) // ShuffleValidatorsToCommittees shuffles validator indices and splits them by slot and shard. -func ShuffleValidatorsToCommittees(seed common.Hash, validators []*pb.ValidatorRecord, crosslinkStartShard uint64) ([]*pb.ShardAndCommitteeArray, error) { - indices := v.ActiveValidatorIndices(validators) - +func ShuffleValidatorsToCommittees( + seed [32]byte, + validators []*pb.ValidatorRecord, + crosslinkStartShard uint64, +) ([]*pb.ShardAndCommitteeArray, error) { + indices := ActiveValidatorIndices(validators) // split the shuffled list for slot. shuffledValidators, err := utils.ShuffleIndices(seed, indices) if err != nil { return nil, err } - return splitBySlotShard(shuffledValidators, crosslinkStartShard), nil } // InitialShardAndCommitteesForSlots initialises the committees for shards by shuffling the validators // and assigning them to specific shards. func InitialShardAndCommitteesForSlots(validators []*pb.ValidatorRecord) ([]*pb.ShardAndCommitteeArray, error) { - seed := make([]byte, 0, 32) - committees, err := ShuffleValidatorsToCommittees(common.BytesToHash(seed), validators, 1) + seed := [32]byte{} + committees, err := ShuffleValidatorsToCommittees(seed, validators, 1) if err != nil { return nil, err } @@ -43,7 +43,6 @@ func InitialShardAndCommitteesForSlots(validators []*pb.ValidatorRecord) ([]*pb. // to a single slot and shard. See getCommitteesPerSlot for more details. func splitBySlotShard(shuffledValidators []uint32, crosslinkStartShard uint64) []*pb.ShardAndCommitteeArray { committeesPerSlot := getCommitteesPerSlot(uint64(len(shuffledValidators))) - committeBySlotAndShard := []*pb.ShardAndCommitteeArray{} // split the validator indices by slot. @@ -65,7 +64,6 @@ func splitBySlotShard(shuffledValidators []uint32, crosslinkStartShard uint64) [ ArrayShardAndCommittee: shardCommittees, }) } - return committeBySlotAndShard } @@ -78,7 +76,6 @@ func getCommitteesPerSlot(numActiveValidators uint64) uint64 { cycleLength := params.BeaconConfig().CycleLength boundOnValidators := numActiveValidators/cycleLength/(params.BeaconConfig().TargetCommitteeSize*2) + 1 boundOnShardCount := params.BeaconConfig().ShardCount / cycleLength - // Ensure that comitteesPerSlot is at least 1. if boundOnShardCount == 0 { return 1 diff --git a/beacon-chain/casper/sharding_test.go b/beacon-chain/core/validators/committees_test.go similarity index 95% rename from beacon-chain/casper/sharding_test.go rename to beacon-chain/core/validators/committees_test.go index a0737d69635e..b8543ea1045d 100644 --- a/beacon-chain/casper/sharding_test.go +++ b/beacon-chain/core/validators/committees_test.go @@ -1,10 +1,9 @@ -package casper +package validators import ( "testing" "github.com/ethereum/go-ethereum/common" - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" ) @@ -22,17 +21,17 @@ func TestGetShardAndCommitteesForSlots(t *testing.T) { {Shard: 4, Committee: []uint32{5, 6, 7, 8, 9}}, }}, }} - if _, err := v.GetShardAndCommitteesForSlot(state.ShardAndCommitteesForSlots, state.LastStateRecalculationSlot, 1000); err == nil { + if _, err := GetShardAndCommitteesForSlot(state.ShardAndCommitteesForSlots, state.LastStateRecalculationSlot, 1000); err == nil { t.Error("getShardAndCommitteesForSlot should have failed with invalid slot") } - committee, err := v.GetShardAndCommitteesForSlot(state.ShardAndCommitteesForSlots, state.LastStateRecalculationSlot, 0) + committee, err := GetShardAndCommitteesForSlot(state.ShardAndCommitteesForSlots, state.LastStateRecalculationSlot, 0) if err != nil { t.Errorf("getShardAndCommitteesForSlot failed: %v", err) } if committee.ArrayShardAndCommittee[0].Shard != 1 { t.Errorf("getShardAndCommitteesForSlot returns Shard should be 1, got: %v", committee.ArrayShardAndCommittee[0].Shard) } - committee, _ = v.GetShardAndCommitteesForSlot(state.ShardAndCommitteesForSlots, state.LastStateRecalculationSlot, 1) + committee, _ = GetShardAndCommitteesForSlot(state.ShardAndCommitteesForSlots, state.LastStateRecalculationSlot, 1) if committee.ArrayShardAndCommittee[0].Shard != 3 { t.Errorf("getShardAndCommitteesForSlot returns Shard should be 3, got: %v", committee.ArrayShardAndCommittee[0].Shard) } diff --git a/beacon-chain/types/BUILD.bazel b/beacon-chain/types/BUILD.bazel index e8f48276ba0f..99277fc8e3ed 100644 --- a/beacon-chain/types/BUILD.bazel +++ b/beacon-chain/types/BUILD.bazel @@ -11,7 +11,8 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/types", visibility = ["//beacon-chain:__subpackages__"], deps = [ - "//beacon-chain/casper:go_default_library", + "//beacon-chain/core/incentives:go_default_library", + "//beacon-chain/core/state:go_default_library", "//beacon-chain/core/validators:go_default_library", "//beacon-chain/utils:go_default_library", "//proto/beacon/p2p/v1:go_default_library", @@ -35,9 +36,9 @@ go_test( "crystallized_state_test.go", ], embed = [":go_default_library"], - race = "off", # TODO(#604): fix issues with tests failing with race on. + race = "on", deps = [ - "//beacon-chain/casper:go_default_library", + "//beacon-chain/core/validators:go_default_library", "//beacon-chain/utils:go_default_library", "//proto/beacon/p2p/v1:go_default_library", "//shared/hashutil:go_default_library", diff --git a/beacon-chain/types/crystallized_state.go b/beacon-chain/types/crystallized_state.go index 1d08ebd4cd91..c47f2189aec8 100644 --- a/beacon-chain/types/crystallized_state.go +++ b/beacon-chain/types/crystallized_state.go @@ -4,7 +4,8 @@ import ( "fmt" "github.com/gogo/protobuf/proto" - "github.com/prysmaticlabs/prysm/beacon-chain/casper" + "github.com/prysmaticlabs/prysm/beacon-chain/core/incentives" + "github.com/prysmaticlabs/prysm/beacon-chain/core/state" v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/hashutil" @@ -34,7 +35,7 @@ func NewGenesisCrystallizedState(genesisValidators []*pb.ValidatorRecord) (*Crys } // Bootstrap attester indices for slots, each slot contains an array of attester indices. - shardAndCommitteesForSlots, err := casper.InitialShardAndCommitteesForSlots(genesisValidators) + shardAndCommitteesForSlots, err := v.InitialShardAndCommitteesForSlots(genesisValidators) if err != nil { return nil, err } @@ -301,10 +302,16 @@ func (c *CrystallizedState) NewStateRecalculations(aState *ActiveState, block *B slot := lastStateRecalculationSlotCycleBack + i blockHash := recentBlockHashes[i] - blockVoteBalance, newState.data.Validators = casper.TallyVoteBalances(blockHash, blockVoteCache, - newState.data.Validators, timeSinceFinality) + blockVoteBalance, newState.data.Validators = incentives.TallyVoteBalances( + blockHash, + blockVoteCache, + newState.data.Validators, + v.ActiveValidatorIndices(newState.data.Validators), + v.TotalActiveValidatorDeposit(newState.data.Validators), + timeSinceFinality, + ) - justifiedSlot, finalizedSlot, justifiedStreak = casper.FinalizeAndJustifySlots(slot, justifiedSlot, finalizedSlot, + justifiedSlot, finalizedSlot, justifiedStreak = state.FinalizeAndJustifySlots(slot, justifiedSlot, finalizedSlot, justifiedStreak, blockVoteBalance, c.TotalDeposits()) } @@ -319,7 +326,7 @@ func (c *CrystallizedState) NewStateRecalculations(aState *ActiveState, block *B newState.data.LastStateRecalculationSlot = newState.LastStateRecalculationSlot() + params.BeaconConfig().CycleLength // Process the pending special records gathered from last cycle. - newState.data.Validators, err = casper.ProcessSpecialRecords(block.SlotNumber(), newState.Validators(), aState.PendingSpecials()) + newState.data.Validators, err = state.ProcessSpecialRecords(block.SlotNumber(), newState.Validators(), aState.PendingSpecials()) if err != nil { return nil, err } @@ -364,7 +371,7 @@ func (c *CrystallizedState) newValidatorSetRecalculations(seed [32]byte) ([]*pb. crosslinkLastShard := c.ShardAndCommitteesForSlots()[lastSlot].ArrayShardAndCommittee[lastCommitteeFromLastSlot].Shard crosslinkNextShard := (crosslinkLastShard + 1) % uint64(shardCount) - newShardCommitteeArray, err := casper.ShuffleValidatorsToCommittees( + newShardCommitteeArray, err := v.ShuffleValidatorsToCommittees( seed, c.data.Validators, crosslinkNextShard, @@ -395,13 +402,21 @@ func (c *CrystallizedState) processCrosslinks(pendingAttestations []*pb.Aggregat return nil, err } - err = casper.ApplyCrosslinkRewardsAndPenalties(crosslinkRecords, currentSlot, indices, attestation, - validators, totalBalance, voteBalance) + err = incentives.ApplyCrosslinkRewardsAndPenalties( + crosslinkRecords, + currentSlot, + indices, + attestation, + validators, + v.TotalActiveValidatorDeposit(validators), + totalBalance, + voteBalance, + ) if err != nil { return nil, err } - crosslinkRecords = casper.ProcessCrosslink(slot, voteBalance, totalBalance, attestation, crosslinkRecords) + crosslinkRecords = state.ProcessCrosslink(slot, voteBalance, totalBalance, attestation, crosslinkRecords) } return crosslinkRecords, nil diff --git a/beacon-chain/types/crystallized_state_test.go b/beacon-chain/types/crystallized_state_test.go index a612dd1912ca..58c345969982 100644 --- a/beacon-chain/types/crystallized_state_test.go +++ b/beacon-chain/types/crystallized_state_test.go @@ -5,7 +5,7 @@ import ( "strconv" "testing" - "github.com/prysmaticlabs/prysm/beacon-chain/casper" + v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" "github.com/prysmaticlabs/prysm/beacon-chain/utils" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" @@ -283,7 +283,7 @@ func TestProcessCrosslinks(t *testing.T) { } // Process crosslinks happened at slot 50. - shardAndCommitteesForSlots, err := casper.InitialShardAndCommitteesForSlots(validators) + shardAndCommitteesForSlots, err := v.InitialShardAndCommitteesForSlots(validators) if err != nil { t.Fatalf("failed to initialize indices for slots: %v", err) }