Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Freeze Spec Bug Fixes #2890

Merged
merged 5 commits into from
Jul 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions beacon-chain/core/blocks/block_operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -868,8 +868,8 @@ func verifyExit(beaconState *pb.BeaconState, exit *pb.VoluntaryExit, verifySigna
// """
// Process ``Transfer`` operation.
// """
// # Verify the amount and fee are not individually too big (for anti-overflow purposes)
// assert state.balances[transfer.sender] >= max(transfer.amount, transfer.fee)
// # Verify the balance the covers amount and fee (with overflow protection)
// assert state.balances[transfer.sender] >= max(transfer.amount + transfer.fee, transfer.amount, transfer.fee)
// # A transfer is valid in only one slot
// assert state.slot == transfer.slot
// # Sender must satisfy at least one of the following conditions in the parenthesis:
Expand Down Expand Up @@ -939,9 +939,12 @@ func verifyTransfer(beaconState *pb.BeaconState, transfer *pb.Transfer, verifySi
if transfer.Amount > maxVal {
maxVal = transfer.Amount
}
if transfer.Amount+transfer.Fee > maxVal {
maxVal = transfer.Amount + transfer.Fee
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel good about this. Where's the test?

Why would we allow sender to initiate a transfer that exceeds the max val anyway? Shouldn't this be rejected?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont allow a sender to initiate a transfer that exceeds maxVal, see L938 that's where we assert

this maxVal variable is used to check for over flow condition, we are not using it anywhere else

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for this check specifically?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, added!

}
sender := beaconState.Validators[transfer.Sender]
senderBalance := beaconState.Balances[transfer.Sender]
// Verify the amount and fee are not individually too big (for anti-overflow purposes).
// Verify the balance the covers amount and fee (with overflow protection).
if senderBalance < maxVal {
return fmt.Errorf("expected sender balance %d >= %d", senderBalance, maxVal)
}
Expand Down
37 changes: 37 additions & 0 deletions beacon-chain/core/blocks/block_operations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,42 @@ func TestProcessVolundaryExits_AppliesCorrectStatus(t *testing.T) {
}
}

func TestProcessBeaconTransfers_NotEnoughSenderBalance(t *testing.T) {
registry := []*pb.Validator{
{
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
},
}
balances := []uint64{params.BeaconConfig().MaxEffectiveBalance}
state := &pb.BeaconState{
Validators: registry,
Balances: balances,
}
transfers := []*pb.Transfer{
{
Fee: params.BeaconConfig().MaxEffectiveBalance,
Amount: params.BeaconConfig().MaxEffectiveBalance,
},
}
block := &pb.BeaconBlock{
Body: &pb.BeaconBlockBody{
Transfers: transfers,
},
}
want := fmt.Sprintf(
"expected sender balance %d >= %d",
balances[0],
transfers[0].Fee+transfers[0].Amount,
)
if _, err := blocks.ProcessTransfers(
state,
block.Body,
false,
); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}

func TestProcessBeaconTransfers_FailsVerification(t *testing.T) {
testConfig := params.BeaconConfig()
testConfig.MaxTransfers = 1
Expand Down Expand Up @@ -1700,6 +1736,7 @@ func TestProcessBeaconTransfers_FailsVerification(t *testing.T) {

state.Validators[0].WithdrawableEpoch = params.BeaconConfig().FarFutureEpoch
state.Validators[0].ActivationEligibilityEpoch = 0
state.Balances[0] = params.BeaconConfig().MinDepositAmount + params.BeaconConfig().MaxEffectiveBalance
block.Body.Transfers = []*pb.Transfer{
{
Fee: params.BeaconConfig().MinDepositAmount,
Expand Down
49 changes: 31 additions & 18 deletions beacon-chain/core/epoch/epoch_processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,13 +709,13 @@ func baseReward(state *pb.BeaconState, index uint64) (uint64, error) {
// to repeat the same calculation for every validator versus just doing it once.
//
// Spec pseudocode definition:
// def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
// 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 = [0 for _ in range(len(state.validator_registry))]
// penalties = [0 for _ in range(len(state.validator_registry))]
// rewards = [Gwei(0) for _ in range(len(state.validators))]
// penalties = [Gwei(0) for _ in range(len(state.validators))]
// eligible_validator_indices = [
// index for index, v in enumerate(state.validator_registry)
// 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)
// ]
//
Expand All @@ -725,7 +725,7 @@ func baseReward(state *pb.BeaconState, index uint64) (uint64, error) {
// 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_attesting_balance(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
Expand All @@ -734,20 +734,31 @@ func baseReward(state *pb.BeaconState, index uint64) (uint64, error) {
//
// # 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 attestations if index in get_attesting_indices(state, a.data, a.aggregation_bitfield)
// 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)
// rewards[attestation.proposer_index] += get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT
// rewards[index] += get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // attestation.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
// * (SLOTS_PER_EPOCH + MIN_ATTESTATION_INCLUSION_DELAY - attestation.inclusion_delay)
// // SLOTS_PER_EPOCH
// )
//
// # Inactivity penalty
// finality_delay = previous_epoch - state.finalized_epoch
// 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:
// penalties[index] += BASE_REWARDS_PER_EPOCH * get_base_reward(state, index)
// 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] += state.validator_registry[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
// penalties[index] += Gwei(
// state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
// )
//
// return rewards, penalties
func attestationDelta(state *pb.BeaconState) ([]uint64, []uint64, error) {
Expand Down Expand Up @@ -834,15 +845,17 @@ func attestationDelta(state *pb.BeaconState) ([]uint64, []uint64, error) {
}

for i, a := range attestersVotedSoruce {
base, err := baseReward(state, i)
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch

baseReward, err := baseReward(state, i)
if err != nil {
return nil, nil, fmt.Errorf("could not get base reward: %v", err)
return nil, nil, fmt.Errorf("could not get proposer reward: %v", err)
}
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
maxAttesterReward := base - proposerReward
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
attesterFactor := slotsPerEpoch + params.BeaconConfig().MinAttestationInclusionDelay - a.InclusionDelay
rewards[i] += maxAttesterReward * attesterFactor / slotsPerEpoch
proposerReward := baseReward / params.BeaconConfig().ProposerRewardQuotient
rewards[a.ProposerIndex] += proposerReward
attesterReward := baseReward - proposerReward
attesterRewardFactor := (slotsPerEpoch + params.BeaconConfig().MinAttestationInclusionDelay - a.InclusionDelay) / slotsPerEpoch
rewards[i] += attesterReward * attesterRewardFactor
}

// Apply penalties for quadratic leaks.
Expand Down
3 changes: 1 addition & 2 deletions beacon-chain/core/epoch/epoch_processing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1242,8 +1242,7 @@ func TestProcessRewardsAndPenalties_SomeAttested(t *testing.T) {
if err != nil {
t.Fatal(err)
}
t.Log(state.Balances)
wanted := uint64(31999797616)
wanted := uint64(31999949392)
if state.Balances[0] != wanted {
t.Errorf("wanted balance: %d, got: %d",
wanted, state.Balances[0])
Expand Down
10 changes: 6 additions & 4 deletions beacon-chain/core/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ import (
// process_deposit(state, deposit)
//
// # Process genesis activations
// for validator in state.validator_registry:
// if validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
// validator.activation_eligibility_epoch = GENESIS_EPOCH
// validator.activation_epoch = GENESIS_EPOCH
// for index, validator in enumerate(state.validators):
// if state.balances[index] >= MAX_EFFECTIVE_BALANCE:
// balance = state.balances[index]
// validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
// if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
//
// genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH))
// for index in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
Expand Down Expand Up @@ -140,6 +141,7 @@ func GenesisBeaconState(deposits []*pb.Deposit, genesisTime uint64, eth1Data *pb
return nil, fmt.Errorf("could not process validator deposit: %v", err)
}
}

for i := 0; i < len(state.Validators); i++ {
if state.Validators[i].EffectiveBalance >=
params.BeaconConfig().MaxEffectiveBalance {
Expand Down