mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-24 12:27:18 +00:00
Removed process epoch (#4251)
This commit is contained in:
parent
812311f6f7
commit
6d2c37caf1
@ -111,145 +111,6 @@ func AttestingBalance(state *pb.BeaconState, atts []*pb.PendingAttestation) (uin
|
||||
return helpers.TotalBalance(state, indices), nil
|
||||
}
|
||||
|
||||
// ProcessJustificationAndFinalization processes justification and finalization during
|
||||
// epoch processing. This is where a beacon node can justify and finalize a new epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_justification_and_finalization(state: BeaconState) -> None:
|
||||
// if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
||||
// return
|
||||
//
|
||||
// previous_epoch = get_previous_epoch(state)
|
||||
// current_epoch = get_current_epoch(state)
|
||||
// old_previous_justified_checkpoint = state.previous_justified_checkpoint
|
||||
// old_current_justified_checkpoint = state.current_justified_checkpoint
|
||||
//
|
||||
// # Process justifications
|
||||
// state.previous_justified_checkpoint = state.current_justified_checkpoint
|
||||
// state.justification_bits[1:] = state.justification_bits[:-1]
|
||||
// state.justification_bits[0] = 0b0
|
||||
// matching_target_attestations = get_matching_target_attestations(state, previous_epoch) # Previous epoch
|
||||
// if get_attesting_balance(state, matching_target_attestations) * 3 >= get_total_active_balance(state) * 2:
|
||||
// state.current_justified_checkpoint = Checkpoint(epoch=previous_epoch,
|
||||
// root=get_block_root(state, previous_epoch))
|
||||
// state.justification_bits[1] = 0b1
|
||||
// matching_target_attestations = get_matching_target_attestations(state, current_epoch) # Current epoch
|
||||
// if get_attesting_balance(state, matching_target_attestations) * 3 >= get_total_active_balance(state) * 2:
|
||||
// state.current_justified_checkpoint = Checkpoint(epoch=current_epoch,
|
||||
// root=get_block_root(state, current_epoch))
|
||||
// state.justification_bits[0] = 0b1
|
||||
//
|
||||
// # Process finalizations
|
||||
// bits = state.justification_bits
|
||||
// # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source
|
||||
// if all(bits[1:4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch:
|
||||
// state.finalized_checkpoint = old_previous_justified_checkpoint
|
||||
// # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source
|
||||
// if all(bits[1:3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch:
|
||||
// state.finalized_checkpoint = old_previous_justified_checkpoint
|
||||
// # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source
|
||||
// if all(bits[0:3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch:
|
||||
// state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
// # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
|
||||
// if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
||||
// state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
func ProcessJustificationAndFinalization(state *pb.BeaconState, prevAttestedBal uint64, currAttestedBal uint64) (*pb.BeaconState, error) {
|
||||
if state.Slot <= helpers.StartSlot(2) {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
oldPrevJustifiedCheckpoint := state.PreviousJustifiedCheckpoint
|
||||
oldCurrJustifiedCheckpoint := state.CurrentJustifiedCheckpoint
|
||||
|
||||
totalBal, err := helpers.TotalActiveBalance(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get total balance")
|
||||
}
|
||||
|
||||
// Process justifications
|
||||
state.PreviousJustifiedCheckpoint = state.CurrentJustifiedCheckpoint
|
||||
state.JustificationBits.Shift(1)
|
||||
|
||||
// Note: the spec refers to the bit index position starting at 1 instead of starting at zero.
|
||||
// We will use that paradigm here for consistency with the godoc spec definition.
|
||||
|
||||
// If 2/3 or more of total balance attested in the previous epoch.
|
||||
if 3*prevAttestedBal >= 2*totalBal {
|
||||
blockRoot, err := helpers.BlockRoot(state, prevEpoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get block root for previous epoch %d", prevEpoch)
|
||||
}
|
||||
state.CurrentJustifiedCheckpoint = ðpb.Checkpoint{Epoch: prevEpoch, Root: blockRoot}
|
||||
state.JustificationBits.SetBitAt(1, true)
|
||||
}
|
||||
|
||||
// If 2/3 or more of the total balance attested in the current epoch.
|
||||
if 3*currAttestedBal >= 2*totalBal {
|
||||
blockRoot, err := helpers.BlockRoot(state, currentEpoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get block root for current epoch %d", prevEpoch)
|
||||
}
|
||||
state.CurrentJustifiedCheckpoint = ðpb.Checkpoint{Epoch: currentEpoch, Root: blockRoot}
|
||||
state.JustificationBits.SetBitAt(0, true)
|
||||
}
|
||||
|
||||
// Process finalization according to ETH2.0 specifications.
|
||||
justification := state.JustificationBits.Bytes()[0]
|
||||
|
||||
// 2nd/3rd/4th (0b1110) most recent epochs are justified, the 2nd using the 4th as source.
|
||||
if justification&0x0E == 0x0E && (oldPrevJustifiedCheckpoint.Epoch+3) == currentEpoch {
|
||||
state.FinalizedCheckpoint = oldPrevJustifiedCheckpoint
|
||||
}
|
||||
|
||||
// 2nd/3rd (0b0110) most recent epochs are justified, the 2nd using the 3rd as source.
|
||||
if justification&0x06 == 0x06 && (oldPrevJustifiedCheckpoint.Epoch+2) == currentEpoch {
|
||||
state.FinalizedCheckpoint = oldPrevJustifiedCheckpoint
|
||||
}
|
||||
|
||||
// 1st/2nd/3rd (0b0111) most recent epochs are justified, the 1st using the 3rd as source.
|
||||
if justification&0x07 == 0x07 && (oldCurrJustifiedCheckpoint.Epoch+2) == currentEpoch {
|
||||
state.FinalizedCheckpoint = oldCurrJustifiedCheckpoint
|
||||
}
|
||||
|
||||
// The 1st/2nd (0b0011) most recent epochs are justified, the 1st using the 2nd as source
|
||||
if justification&0x03 == 0x03 && (oldCurrJustifiedCheckpoint.Epoch+1) == currentEpoch {
|
||||
state.FinalizedCheckpoint = oldCurrJustifiedCheckpoint
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ProcessRewardsAndPenalties processes the rewards and penalties of individual validator.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_rewards_and_penalties(state: BeaconState) -> None:
|
||||
// if get_current_epoch(state) == GENESIS_EPOCH:
|
||||
// return
|
||||
//
|
||||
// rewards1, penalties1 = get_attestation_deltas(state)
|
||||
// rewards2, penalties2 = get_crosslink_deltas(state)
|
||||
// for i in range(len(state.validator_registry)):
|
||||
// increase_balance(state, i, rewards1[i] + rewards2[i])
|
||||
// decrease_balance(state, i, penalties1[i] + penalties2[i])
|
||||
func ProcessRewardsAndPenalties(state *pb.BeaconState) (*pb.BeaconState, error) {
|
||||
// Can't process rewards and penalties in genesis epoch.
|
||||
if helpers.CurrentEpoch(state) == 0 {
|
||||
return state, nil
|
||||
}
|
||||
attsRewards, attsPenalties, err := attestationDelta(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get attestation delta")
|
||||
}
|
||||
|
||||
for i := 0; i < len(state.Validators); i++ {
|
||||
state = helpers.IncreaseBalance(state, uint64(i), attsRewards[i])
|
||||
state = helpers.DecreaseBalance(state, uint64(i), attsPenalties[i])
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ProcessRegistryUpdates rotates validators in and out of active pool.
|
||||
// the amount to rotate is determined churn limit.
|
||||
//
|
||||
@ -526,183 +387,3 @@ func BaseReward(state *pb.BeaconState, index uint64) (uint64, error) {
|
||||
mathutil.IntegerSquareRoot(totalBalance) / params.BeaconConfig().BaseRewardsPerEpoch
|
||||
return baseReward, nil
|
||||
}
|
||||
|
||||
// attestationDelta calculates the rewards and penalties of individual
|
||||
// validator for voting the correct FFG source, FFG target, and head. It
|
||||
// also calculates proposer delay inclusion and inactivity rewards
|
||||
// and penalties. Individual rewards and penalties are returned in list.
|
||||
//
|
||||
// Note: we calculated adjusted quotient outside of base reward because it's too inefficient
|
||||
// to repeat the same calculation for every validator versus just doing it once.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
|
||||
// previous_epoch = get_previous_epoch(state)
|
||||
// total_balance = get_total_active_balance(state)
|
||||
// rewards = [Gwei(0) for _ in range(len(state.validators))]
|
||||
// penalties = [Gwei(0) for _ in range(len(state.validators))]
|
||||
// eligible_validator_indices = [
|
||||
// ValidatorIndex(index) for index, v in enumerate(state.validators)
|
||||
// if is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)
|
||||
// ]
|
||||
//
|
||||
// # Micro-incentives for matching FFG source, FFG target, and head
|
||||
// matching_source_attestations = get_matching_source_attestations(state, previous_epoch)
|
||||
// matching_target_attestations = get_matching_target_attestations(state, previous_epoch)
|
||||
// matching_head_attestations = get_matching_head_attestations(state, previous_epoch)
|
||||
// for attestations in (matching_source_attestations, matching_target_attestations, matching_head_attestations):
|
||||
// unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations)
|
||||
// attesting_balance = get_total_balance(state, unslashed_attesting_indices)
|
||||
// for index in eligible_validator_indices:
|
||||
// if index in unslashed_attesting_indices:
|
||||
// rewards[index] += get_base_reward(state, index) * attesting_balance // total_balance
|
||||
// else:
|
||||
// penalties[index] += get_base_reward(state, index)
|
||||
//
|
||||
// # Proposer and inclusion delay micro-rewards
|
||||
// for index in get_unslashed_attesting_indices(state, matching_source_attestations):
|
||||
// index = ValidatorIndex(index)
|
||||
// attestation = min([
|
||||
// a for a in matching_source_attestations
|
||||
// if index in get_attesting_indices(state, a.data, a.aggregation_bits)
|
||||
// ], key=lambda a: a.inclusion_delay)
|
||||
// proposer_reward = Gwei(get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT)
|
||||
// rewards[attestation.proposer_index] += proposer_reward
|
||||
// max_attester_reward = get_base_reward(state, index) - proposer_reward
|
||||
// rewards[index] += Gwei(max_attester_reward // attestation.inclusion_delay)
|
||||
//
|
||||
// # Inactivity penalty
|
||||
// finality_delay = previous_epoch - state.finalized_checkpoint.epoch
|
||||
// if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY:
|
||||
// matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations)
|
||||
// for index in eligible_validator_indices:
|
||||
// index = ValidatorIndex(index)
|
||||
// penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index))
|
||||
// if index not in matching_target_attesting_indices:
|
||||
// penalties[index] += Gwei(
|
||||
// state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
|
||||
// )
|
||||
//
|
||||
// return rewards, penalties
|
||||
func attestationDelta(state *pb.BeaconState) ([]uint64, []uint64, error) {
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
totalBalance, err := helpers.TotalActiveBalance(state)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get total active balance")
|
||||
}
|
||||
|
||||
rewards := make([]uint64, len(state.Validators))
|
||||
penalties := make([]uint64, len(state.Validators))
|
||||
|
||||
// Filter out the list of eligible validator indices. The eligible validator
|
||||
// has to be active or slashed but before withdrawn.
|
||||
var eligible []uint64
|
||||
for i, v := range state.Validators {
|
||||
isActive := helpers.IsActiveValidator(v, prevEpoch)
|
||||
isSlashed := v.Slashed && (prevEpoch+1 < v.WithdrawableEpoch)
|
||||
if isActive || isSlashed {
|
||||
eligible = append(eligible, uint64(i))
|
||||
}
|
||||
}
|
||||
|
||||
// Apply rewards and penalties for voting correct source target and head.
|
||||
// Construct a attestations list contains source, target and head attestations.
|
||||
atts, err := MatchAttestations(state, prevEpoch)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get source, target and head attestations")
|
||||
}
|
||||
var attsPackage [][]*pb.PendingAttestation
|
||||
attsPackage = append(attsPackage, atts.source)
|
||||
attsPackage = append(attsPackage, atts.Target)
|
||||
attsPackage = append(attsPackage, atts.head)
|
||||
|
||||
// Cache the validators who voted correctly for source in a map
|
||||
// to calculate earliest attestation rewards later.
|
||||
attestersVotedSource := make(map[uint64]*pb.PendingAttestation)
|
||||
// Compute rewards / penalties for each attestation in the list and update
|
||||
// the rewards and penalties lists.
|
||||
for i, matchAtt := range attsPackage {
|
||||
indices, err := unslashedAttestingIndices(state, matchAtt)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get attestation indices")
|
||||
}
|
||||
|
||||
attested := make(map[uint64]bool)
|
||||
// Construct a map to look up validators that voted for source, target or head.
|
||||
for _, index := range indices {
|
||||
if i == 0 {
|
||||
attestersVotedSource[index] = &pb.PendingAttestation{InclusionDelay: params.BeaconConfig().FarFutureEpoch}
|
||||
}
|
||||
attested[index] = true
|
||||
}
|
||||
attestedBalance := helpers.TotalBalance(state, indices)
|
||||
|
||||
// Update rewards and penalties to each eligible validator index.
|
||||
for _, index := range eligible {
|
||||
base, err := BaseReward(state, index)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get base reward")
|
||||
}
|
||||
if _, ok := attested[index]; ok {
|
||||
rewards[index] += base * attestedBalance / totalBalance
|
||||
} else {
|
||||
penalties[index] += base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For every index, filter the matching source attestation that correspond to the index,
|
||||
// sort by inclusion delay and get the one that was included on chain first.
|
||||
for _, att := range atts.source {
|
||||
indices, err := helpers.AttestingIndices(state, att.Data, att.AggregationBits)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get attester indices")
|
||||
}
|
||||
for _, i := range indices {
|
||||
if _, ok := attestersVotedSource[i]; ok {
|
||||
if attestersVotedSource[i].InclusionDelay > att.InclusionDelay {
|
||||
attestersVotedSource[i] = att
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i, a := range attestersVotedSource {
|
||||
baseReward, err := BaseReward(state, i)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get proposer reward")
|
||||
}
|
||||
proposerReward := baseReward / params.BeaconConfig().ProposerRewardQuotient
|
||||
rewards[a.ProposerIndex] += proposerReward
|
||||
attesterReward := baseReward - proposerReward
|
||||
rewards[i] += attesterReward / a.InclusionDelay
|
||||
}
|
||||
|
||||
// Apply penalties for quadratic leaks.
|
||||
// When epoch since finality exceeds inactivity penalty constant, the penalty gets increased
|
||||
// based on the finality delay.
|
||||
finalityDelay := prevEpoch - state.FinalizedCheckpoint.Epoch
|
||||
if finalityDelay > params.BeaconConfig().MinEpochsToInactivityPenalty {
|
||||
targetIndices, err := unslashedAttestingIndices(state, atts.Target)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get attestation indices")
|
||||
}
|
||||
attestedTarget := make(map[uint64]bool)
|
||||
for _, index := range targetIndices {
|
||||
attestedTarget[index] = true
|
||||
}
|
||||
for _, index := range eligible {
|
||||
base, err := BaseReward(state, index)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not get base reward")
|
||||
}
|
||||
penalties[index] += params.BeaconConfig().BaseRewardsPerEpoch * base
|
||||
if _, ok := attestedTarget[index]; !ok {
|
||||
penalties[index] += state.Validators[index].EffectiveBalance * finalityDelay /
|
||||
params.BeaconConfig().InactivityPenaltyQuotient
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rewards, penalties, nil
|
||||
}
|
||||
|
@ -332,211 +332,6 @@ func TestBaseReward_AccurateRewards(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationAndFinalization_CantJustifyFinalize(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxEffectiveBalance
|
||||
state := &pb.BeaconState{
|
||||
JustificationBits: []byte{0x00},
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch * 2,
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e, EffectiveBalance: a}, {ExitEpoch: e, EffectiveBalance: a},
|
||||
{ExitEpoch: e, EffectiveBalance: a}, {ExitEpoch: e, EffectiveBalance: a}},
|
||||
}
|
||||
// Since Attested balances are less than total balances, nothing happened.
|
||||
newState, err := ProcessJustificationAndFinalization(state, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(state, newState) {
|
||||
t.Error("Did not get the original state")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationAndFinalization_NoBlockRootCurrentEpoch(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxEffectiveBalance
|
||||
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerEpoch*2+1)
|
||||
for i := 0; i < len(blockRoots); i++ {
|
||||
blockRoots[i] = []byte{byte(i)}
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch * 3,
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
JustificationBits: []byte{0x03}, // 0b0011
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots,
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
_, err := ProcessJustificationAndFinalization(state, 0, attestedBalance)
|
||||
want := "could not get block root for current epoch"
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Fatal("Did not receive correct error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationAndFinalization_ConsecutiveEpochs(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxEffectiveBalance
|
||||
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerEpoch*2+1)
|
||||
for i := 0; i < len(blockRoots); i++ {
|
||||
blockRoots[i] = []byte{byte(i)}
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch*2 + 1,
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
JustificationBits: bitfield.Bitvector4{0x0F}, // 0b1111
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots,
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
newState, err := ProcessJustificationAndFinalization(state, 0, attestedBalance)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(newState.CurrentJustifiedCheckpoint.Root, []byte{byte(64)}) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(64)}, newState.CurrentJustifiedCheckpoint.Root)
|
||||
}
|
||||
if newState.CurrentJustifiedCheckpoint.Epoch != 2 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
2, newState.CurrentJustifiedCheckpoint.Epoch)
|
||||
}
|
||||
if newState.PreviousJustifiedCheckpoint.Epoch != 0 {
|
||||
t.Errorf("Wanted previous justified epoch: %d, got: %d",
|
||||
0, newState.PreviousJustifiedCheckpoint.Epoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedCheckpoint.Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedCheckpoint.Root)
|
||||
}
|
||||
if newState.FinalizedCheckpoint.Epoch != 0 {
|
||||
t.Errorf("Wanted finalized epoch: 0, got: %d", newState.FinalizedCheckpoint.Epoch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationAndFinalization_JustifyCurrentEpoch(t *testing.T) {
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxEffectiveBalance
|
||||
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerEpoch*2+1)
|
||||
for i := 0; i < len(blockRoots); i++ {
|
||||
blockRoots[i] = []byte{byte(i)}
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch*2 + 1,
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
JustificationBits: bitfield.Bitvector4{0x03}, // 0b0011
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots,
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
newState, err := ProcessJustificationAndFinalization(state, 0, attestedBalance)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(newState.CurrentJustifiedCheckpoint.Root, []byte{byte(64)}) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(64)}, newState.CurrentJustifiedCheckpoint.Root)
|
||||
}
|
||||
if newState.CurrentJustifiedCheckpoint.Epoch != 2 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
2, newState.CurrentJustifiedCheckpoint.Epoch)
|
||||
}
|
||||
if newState.PreviousJustifiedCheckpoint.Epoch != 0 {
|
||||
t.Errorf("Wanted previous justified epoch: %d, got: %d",
|
||||
0, newState.PreviousJustifiedCheckpoint.Epoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedCheckpoint.Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedCheckpoint.Root)
|
||||
}
|
||||
if newState.FinalizedCheckpoint.Epoch != 0 {
|
||||
t.Errorf("Wanted finalized epoch: 0, got: %d", newState.FinalizedCheckpoint.Epoch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessJustificationAndFinalization_JustifyPrevEpoch(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
a := params.BeaconConfig().MaxEffectiveBalance
|
||||
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerEpoch*2+1)
|
||||
for i := 0; i < len(blockRoots); i++ {
|
||||
blockRoots[i] = []byte{byte(i)}
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch*2 + 1,
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
JustificationBits: bitfield.Bitvector4{0x03}, // 0b0011
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots, FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
newState, err := ProcessJustificationAndFinalization(state, attestedBalance, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(newState.CurrentJustifiedCheckpoint.Root, []byte{byte(64)}) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(64)}, newState.CurrentJustifiedCheckpoint.Root)
|
||||
}
|
||||
if newState.PreviousJustifiedCheckpoint.Epoch != 0 {
|
||||
t.Errorf("Wanted previous justified epoch: %d, got: %d",
|
||||
0, newState.PreviousJustifiedCheckpoint.Epoch)
|
||||
}
|
||||
if newState.CurrentJustifiedCheckpoint.Epoch != 2 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
2, newState.CurrentJustifiedCheckpoint.Epoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedCheckpoint.Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedCheckpoint.Root)
|
||||
}
|
||||
if newState.FinalizedCheckpoint.Epoch != 0 {
|
||||
t.Errorf("Wanted finalized epoch: 0, got: %d", newState.FinalizedCheckpoint.Epoch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessSlashings_NotSlashed(t *testing.T) {
|
||||
s := &pb.BeaconState{
|
||||
Slot: 0,
|
||||
@ -709,212 +504,6 @@ func TestProcessRegistryUpdates_NoRotation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDelta_CantGetBlockRoot(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
|
||||
state := buildState(2*e, 1)
|
||||
state.Slot = 0
|
||||
|
||||
_, _, err := attestationDelta(state)
|
||||
wanted := "could not get block root for epoch"
|
||||
if !strings.Contains(err.Error(), wanted) {
|
||||
t.Fatalf("Got: %v, want: %v", err.Error(), wanted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDelta_CantGetAttestation(t *testing.T) {
|
||||
state := buildState(0, 1)
|
||||
|
||||
_, _, err := attestationDelta(state)
|
||||
wanted := "could not get source, target and head attestations"
|
||||
if !strings.Contains(err.Error(), wanted) {
|
||||
t.Fatalf("Got: %v, want: %v", err.Error(), wanted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDelta_NoOneAttested(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := params.BeaconConfig().MinGenesisActiveValidatorCount / 32
|
||||
state := buildState(e+2, validatorCount)
|
||||
//startShard := uint64(960)
|
||||
atts := make([]*pb.PendingAttestation, 2)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
},
|
||||
InclusionDelay: uint64(i + 100),
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0x01},
|
||||
}
|
||||
}
|
||||
|
||||
rewards, penalties, err := attestationDelta(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := uint64(0); i < validatorCount; i++ {
|
||||
// Since no one attested, all the validators should gain 0 reward
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted reward balance 0, got %d", rewards[i])
|
||||
}
|
||||
// Since no one attested, all the validators should get penalized the same
|
||||
// it's 3 times the penalized amount because source, target and head.
|
||||
base, err := BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
wanted := 3 * base
|
||||
if penalties[i] != wanted {
|
||||
t.Errorf("Wanted penalty balance %d, got %d",
|
||||
wanted, penalties[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDelta_SomeAttested(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := params.BeaconConfig().MinGenesisActiveValidatorCount / 8
|
||||
state := buildState(e+2, validatorCount)
|
||||
atts := make([]*pb.PendingAttestation, 3)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
}
|
||||
}
|
||||
state.PreviousEpochAttestations = atts
|
||||
|
||||
rewards, penalties, err := attestationDelta(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
attestedBalance, err := AttestingBalance(state, atts)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
totalBalance, err := helpers.TotalActiveBalance(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
attestedIndices := []uint64{100, 106, 196, 641, 654, 1606}
|
||||
for _, i := range attestedIndices {
|
||||
base, err := BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
|
||||
// Base rewards for getting source right
|
||||
wanted := 3 * (base * attestedBalance / totalBalance)
|
||||
// Base rewards for proposer and attesters working together getting attestation
|
||||
// on chain in the fastest manner
|
||||
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
|
||||
wanted += (base - proposerReward) / params.BeaconConfig().MinAttestationInclusionDelay
|
||||
|
||||
if rewards[i] != wanted {
|
||||
t.Errorf("Wanted reward balance %d, got %d", wanted, rewards[i])
|
||||
}
|
||||
// Since all these validators attested, they shouldn't get penalized.
|
||||
if penalties[i] != 0 {
|
||||
t.Errorf("Wanted penalty balance 0, got %d", penalties[i])
|
||||
}
|
||||
}
|
||||
|
||||
nonAttestedIndices := []uint64{12, 23, 45, 79}
|
||||
for _, i := range nonAttestedIndices {
|
||||
base, err := BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
wanted := 3 * base
|
||||
// Since all these validators did not attest, they shouldn't get rewarded.
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted reward balance 0, got %d", rewards[i])
|
||||
}
|
||||
// Base penalties for not attesting.
|
||||
if penalties[i] != wanted {
|
||||
t.Errorf("Wanted penalty balance %d, got %d", wanted, penalties[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDelta_SomeAttestedFinalityDelay(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := params.BeaconConfig().MinGenesisActiveValidatorCount / 8
|
||||
state := buildState(e+4, validatorCount)
|
||||
atts := make([]*pb.PendingAttestation, 3)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
}
|
||||
}
|
||||
state.PreviousEpochAttestations = atts
|
||||
state.FinalizedCheckpoint.Epoch = 0
|
||||
|
||||
rewards, penalties, err := attestationDelta(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
attestedBalance, err := AttestingBalance(state, atts)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
totalBalance, err := helpers.TotalActiveBalance(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
attestedIndices := []uint64{100, 106, 196, 641, 654, 1606}
|
||||
for _, i := range attestedIndices {
|
||||
base, err := BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
// Base rewards for getting source right
|
||||
wanted := 3 * (base * attestedBalance / totalBalance)
|
||||
// Base rewards for proposer and attesters working together getting attestation
|
||||
// on chain in the fatest manner
|
||||
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
|
||||
wanted += (base - proposerReward) * params.BeaconConfig().MinAttestationInclusionDelay
|
||||
if rewards[i] != wanted {
|
||||
t.Errorf("Wanted reward balance %d, got %d", wanted, rewards[i])
|
||||
}
|
||||
// Since all these validators attested, they shouldn't get penalized.
|
||||
if penalties[i] != 0 {
|
||||
t.Errorf("Wanted penalty balance 0, got %d", penalties[i])
|
||||
}
|
||||
}
|
||||
|
||||
nonAttestedIndices := []uint64{12, 23, 45, 79}
|
||||
for _, i := range nonAttestedIndices {
|
||||
base, err := BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
wanted := 3 * base
|
||||
// Since all these validators did not attest, they shouldn't get rewarded.
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted reward balance 0, got %d", rewards[i])
|
||||
}
|
||||
// Base penalties for not attesting.
|
||||
if penalties[i] != wanted {
|
||||
t.Errorf("Wanted penalty balance %d, got %d", wanted, penalties[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
|
||||
state := &pb.BeaconState{
|
||||
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
|
||||
@ -1033,51 +622,6 @@ func TestProcessRegistryUpdates_CanExits(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenalties_GenesisEpoch(t *testing.T) {
|
||||
state := &pb.BeaconState{Slot: params.BeaconConfig().SlotsPerEpoch - 1}
|
||||
newState, err := ProcessRewardsAndPenalties(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(state, newState) {
|
||||
t.Error("genesis state mutated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenalties_SomeAttested(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := params.BeaconConfig().MinGenesisActiveValidatorCount / 8
|
||||
state := buildState(e+2, validatorCount)
|
||||
atts := make([]*pb.PendingAttestation, 3)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
}
|
||||
}
|
||||
state.PreviousEpochAttestations = atts
|
||||
|
||||
state, err := ProcessRewardsAndPenalties(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wanted := uint64(31999873505)
|
||||
if state.Balances[0] != wanted {
|
||||
t.Errorf("wanted balance: %d, got: %d",
|
||||
wanted, state.Balances[0])
|
||||
}
|
||||
wanted = uint64(31999810265)
|
||||
if state.Balances[4] != wanted {
|
||||
t.Errorf("wanted balance: %d, got: %d",
|
||||
wanted, state.Balances[1])
|
||||
}
|
||||
}
|
||||
|
||||
func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
|
@ -1,15 +1,11 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@ -25,40 +21,11 @@ func runJustificationAndFinalizationTests(t *testing.T, config string) {
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
testutil.RunEpochOperationTest(t, folderPath, processJustificationAndFinalizationWrapper)
|
||||
testutil.RunEpochOperationTest(t, folderPath, processJustificationAndFinalizationPrecomputeWrapper)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// This is a subset of state.ProcessEpoch. The spec test defines input data for
|
||||
// `justification_and_finalization` only.
|
||||
func processJustificationAndFinalizationWrapper(t *testing.T, state *pb.BeaconState) (*pb.BeaconState, error) {
|
||||
prevEpochAtts, err := targetAtts(state, helpers.PrevEpoch(state))
|
||||
if err != nil {
|
||||
t.Fatalf("could not get target atts prev epoch %d: %v", helpers.PrevEpoch(state), err)
|
||||
}
|
||||
currentEpochAtts, err := targetAtts(state, helpers.CurrentEpoch(state))
|
||||
if err != nil {
|
||||
t.Fatalf("could not get target atts current epoch %d: %v", helpers.CurrentEpoch(state), err)
|
||||
}
|
||||
prevEpochAttestedBalance, err := epoch.AttestingBalance(state, prevEpochAtts)
|
||||
if err != nil {
|
||||
t.Fatalf("could not get attesting balance prev epoch: %v", err)
|
||||
}
|
||||
currentEpochAttestedBalance, err := epoch.AttestingBalance(state, currentEpochAtts)
|
||||
if err != nil {
|
||||
t.Fatalf("could not get attesting balance current epoch: %v", err)
|
||||
}
|
||||
|
||||
state, err = epoch.ProcessJustificationAndFinalization(state, prevEpochAttestedBalance, currentEpochAttestedBalance)
|
||||
if err != nil {
|
||||
t.Fatalf("could not process justification: %v", err)
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func processJustificationAndFinalizationPrecomputeWrapper(t *testing.T, state *pb.BeaconState) (*pb.BeaconState, error) {
|
||||
ctx := context.Background()
|
||||
vp, bp := precompute.New(ctx, state)
|
||||
@ -74,36 +41,3 @@ func processJustificationAndFinalizationPrecomputeWrapper(t *testing.T, state *p
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func targetAtts(state *pb.BeaconState, epoch uint64) ([]*pb.PendingAttestation, error) {
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
previousEpoch := helpers.PrevEpoch(state)
|
||||
|
||||
// Input epoch for matching the source attestations has to be within range
|
||||
// of current epoch & previous epoch.
|
||||
if epoch != currentEpoch && epoch != previousEpoch {
|
||||
return nil, fmt.Errorf("input epoch: %d != current epoch: %d or previous epoch: %d",
|
||||
epoch, currentEpoch, previousEpoch)
|
||||
}
|
||||
|
||||
// Decide if the source attestations are coming from current or previous epoch.
|
||||
var srcAtts []*pb.PendingAttestation
|
||||
if epoch == currentEpoch {
|
||||
srcAtts = state.CurrentEpochAttestations
|
||||
} else {
|
||||
srcAtts = state.PreviousEpochAttestations
|
||||
}
|
||||
targetRoot, err := helpers.BlockRoot(state, epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tgtAtts := make([]*pb.PendingAttestation, 0, len(srcAtts))
|
||||
for _, srcAtt := range srcAtts {
|
||||
if bytes.Equal(srcAtt.Data.Target.Root, targetRoot) {
|
||||
tgtAtts = append(tgtAtts, srcAtt)
|
||||
}
|
||||
}
|
||||
|
||||
return tgtAtts, nil
|
||||
}
|
||||
|
@ -599,72 +599,6 @@ func CanProcessEpoch(state *pb.BeaconState) bool {
|
||||
return (state.Slot+1)%params.BeaconConfig().SlotsPerEpoch == 0
|
||||
}
|
||||
|
||||
// ProcessEpoch describes the per epoch operations that are performed on the
|
||||
// beacon state. It focuses on the validator registry, adjusting balances, and finalizing slots.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
//
|
||||
// def process_epoch(state: BeaconState) -> None:
|
||||
// process_justification_and_finalization(state)
|
||||
// process_crosslinks(state)
|
||||
// process_rewards_and_penalties(state)
|
||||
// process_registry_updates(state)
|
||||
// # @process_reveal_deadlines
|
||||
// # @process_challenge_deadlines
|
||||
// process_slashings(state)
|
||||
// process_final_updates(state)
|
||||
// # @after_process_final_updates
|
||||
func ProcessEpoch(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessEpoch")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("epoch", int64(helpers.SlotToEpoch(state.Slot))))
|
||||
|
||||
prevEpochAtts, err := e.MatchAttestations(state, helpers.PrevEpoch(state))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get target atts prev epoch %d: %v",
|
||||
helpers.PrevEpoch(state), err)
|
||||
}
|
||||
currentEpochAtts, err := e.MatchAttestations(state, helpers.CurrentEpoch(state))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get target atts current epoch %d: %v",
|
||||
helpers.CurrentEpoch(state), err)
|
||||
}
|
||||
prevEpochAttestedBalance, err := e.AttestingBalance(state, prevEpochAtts.Target)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get attesting balance prev epoch")
|
||||
}
|
||||
currentEpochAttestedBalance, err := e.AttestingBalance(state, currentEpochAtts.Target)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get attesting balance current epoch")
|
||||
}
|
||||
|
||||
state, err = e.ProcessJustificationAndFinalization(state, prevEpochAttestedBalance, currentEpochAttestedBalance)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process justification")
|
||||
}
|
||||
|
||||
state, err = e.ProcessRewardsAndPenalties(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process rewards and penalties")
|
||||
}
|
||||
|
||||
state, err = e.ProcessRegistryUpdates(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process registry updates")
|
||||
}
|
||||
|
||||
state, err = e.ProcessSlashings(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process slashings")
|
||||
}
|
||||
|
||||
state, err = e.ProcessFinalUpdates(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process final updates")
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ProcessEpochPrecompute describes the per epoch operations that are performed on the beacon state.
|
||||
// It's optimized by pre computing validator attested info and epoch total/attested balances upfront.
|
||||
func ProcessEpochPrecompute(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, error) {
|
||||
|
@ -474,53 +474,6 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessEpoch_CantGetTgtAttsPrevEpoch(t *testing.T) {
|
||||
atts := []*pb.PendingAttestation{{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Epoch: 1}}}}
|
||||
_, err := state.ProcessEpoch(context.Background(), &pb.BeaconState{CurrentEpochAttestations: atts})
|
||||
if !strings.Contains(err.Error(), "could not get target atts prev epoch") {
|
||||
t.Fatal("Did not receive wanted error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessEpoch_CantGetTgtAttsCurrEpoch(t *testing.T) {
|
||||
epoch := uint64(1)
|
||||
|
||||
atts := []*pb.PendingAttestation{{Data: ðpb.AttestationData{}}}
|
||||
_, err := state.ProcessEpoch(context.Background(), &pb.BeaconState{
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
BlockRoots: make([][]byte, 128),
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
CurrentEpochAttestations: atts})
|
||||
if !strings.Contains(err.Error(), "could not get target atts current epoch") {
|
||||
t.Fatal("Did not receive wanted error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessEpoch_CanProcess(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
epoch := uint64(1)
|
||||
|
||||
atts := []*pb.PendingAttestation{{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{}}}}
|
||||
newState, err := state.ProcessEpoch(context.Background(), &pb.BeaconState{
|
||||
Slot: epoch*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
BlockRoots: make([][]byte, 128),
|
||||
Slashings: []uint64{0, 1e9, 1e9},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
CurrentEpochAttestations: atts,
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
JustificationBits: bitfield.Bitvector4{0x00},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wanted := uint64(0)
|
||||
if newState.Slashings[2] != wanted {
|
||||
t.Errorf("Wanted slashed balance: %d, got: %d", wanted, newState.Slashings[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessEpochPrecompute_CanProcess(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
epoch := uint64(1)
|
||||
@ -546,72 +499,6 @@ func TestProcessEpochPrecompute_CanProcess(t *testing.T) {
|
||||
t.Errorf("Wanted slashed balance: %d, got: %d", wanted, newState.Slashings[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessEpoch_NotPanicOnEmptyActiveValidatorIndices(t *testing.T) {
|
||||
newState := &pb.BeaconState{
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().SlotsPerEpoch),
|
||||
}
|
||||
|
||||
state.ProcessEpoch(context.Background(), newState)
|
||||
}
|
||||
|
||||
func BenchmarkProcessEpoch65536Validators(b *testing.B) {
|
||||
logrus.SetLevel(logrus.PanicLevel)
|
||||
|
||||
helpers.ClearAllCaches()
|
||||
epoch := uint64(1)
|
||||
|
||||
validatorCount := params.BeaconConfig().MinGenesisActiveValidatorCount * 4
|
||||
comitteeCount := validatorCount / params.BeaconConfig().TargetCommitteeSize
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
balances := make([]uint64, validatorCount)
|
||||
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
}
|
||||
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
}
|
||||
|
||||
var atts []*pb.PendingAttestation
|
||||
for i := uint64(0); i < comitteeCount; i++ {
|
||||
atts = append(atts, &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{},
|
||||
AggregationBits: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
||||
InclusionDelay: 1,
|
||||
})
|
||||
}
|
||||
|
||||
s := &pb.BeaconState{
|
||||
Slot: epoch*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
Validators: validators,
|
||||
Balances: balances,
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
BlockRoots: make([][]byte, 254),
|
||||
Slashings: []uint64{0, 1e9, 0},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
PreviousEpochAttestations: atts,
|
||||
}
|
||||
|
||||
// Precache the shuffled indices
|
||||
for i := uint64(0); i < comitteeCount; i++ {
|
||||
if _, err := helpers.BeaconCommittee(s, 0, i); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
_, err := state.ProcessEpoch(context.Background(), s)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkProcessBlk_65536Validators_FullBlock(b *testing.B) {
|
||||
logrus.SetLevel(logrus.PanicLevel)
|
||||
helpers.ClearAllCaches()
|
||||
|
Loading…
Reference in New Issue
Block a user