prysm-pulse/beacon-chain/casper/state_transition.go

131 lines
4.5 KiB
Go

package casper
import (
"encoding/binary"
"github.com/prysmaticlabs/prysm/beacon-chain/params"
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bitutil"
)
// 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,
slot uint64,
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
validators = CalculateRewards(slot, voterIndices, validators,
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.GetConfig().CycleLength
if 3*blockVoteBalance >= 2*totalDeposits {
if slot > justifiedSlot {
justifiedSlot = slot
}
justifiedStreak++
} else {
justifiedStreak = 0
}
newFinalizedSlot := slot - cycleLength - 1
if slot > cycleLength && justifiedStreak >= cycleLength+1 && newFinalizedSlot > finalizedSlot {
finalizedSlot = newFinalizedSlot
}
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 {
rewardQuotient := RewardQuotient(validators)
for _, attesterIndex := range attesterIndices {
timeSinceLastConfirmation := slot - crosslinkRecords[attestation.Shard].GetSlot()
if !crosslinkRecords[attestation.Shard].GetRecentlyChanged() {
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
}
// 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
if voteMajority && !crosslinkRecords[attestation.Shard].RecentlyChanged {
crosslinkRecords[attestation.Shard] = &pb.CrosslinkRecord{
RecentlyChanged: true,
ShardBlockHash: attestation.ShardBlockHash,
Slot: slot,
}
}
return crosslinkRecords
}
// 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) {
// 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 := 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))
}
// Covers RANDAO updates for all the validators from last cycle.
if specialRecord.Kind == uint32(params.RandaoChange) {
validatorIndex := binary.BigEndian.Uint64(specialRecord.Data[0])
validators[validatorIndex].RandaoCommitment = specialRecord.Data[1]
}
}
return validators, nil
}