diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index cf9908d55..8b9cdeceb 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -202,7 +202,7 @@ proc makeAttestation(node: BeaconNode, beacon_block_root: node.headBlockRoot, epoch_boundary_root: Eth2Digest(), # TODO shard_block_root: Eth2Digest(), # TODO - latest_crosslink: Crosslink(), # TODO + latest_crosslink: Crosslink(epoch: state.latest_crosslinks[shard].epoch), justified_epoch: state.justified_epoch, justified_block_root: justifiedBlockRoot) diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index e04ce1347..5d3fc2f7f 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -204,11 +204,14 @@ func get_genesis_beacon_state*( latest_eth1_data: latest_eth1_data, # Recent state - # TODO properly initialize latest_crosslinks # latest_block_roots, latest_active_index_roots, latest_slashed_balances, # latest_attestations, and batched_block_roots automatically initialized. ) + for i in 0 ..< SHARD_COUNT: + state.latest_crosslinks[i] = Crosslink( + epoch: GENESIS_EPOCH, shard_block_root: ZERO_HASH) + # Process initial deposits for deposit in initial_validator_deposits: process_deposit( @@ -398,7 +401,12 @@ proc checkAttestation*( Crosslink( shard_block_root: attestation.data.shard_block_root, epoch: slot_to_epoch(attestation.data.slot))]): - warn("Unexpected crosslink shard") + warn("Unexpected crosslink shard", + state_latest_crosslinks_attestation_data_shard = + state.latest_crosslinks[attestation.data.shard], + attestation_data_latest_crosslink = attestation.data.latest_crosslink, + epoch = humaneEpochNum(slot_to_epoch(attestation.data.slot)), + shard_block_root = attestation.data.shard_block_root) return assert allIt(attestation.custody_bitfield, it == 0) #TO BE REMOVED IN PHASE 1 diff --git a/beacon_chain/state_transition.nim b/beacon_chain/state_transition.nim index f40fd5784..28d6325c1 100644 --- a/beacon_chain/state_transition.nim +++ b/beacon_chain/state_transition.nim @@ -405,16 +405,15 @@ proc processTransfers(state: var BeaconState, blck: BeaconBlock, true -proc process_ejections(state: var BeaconState) = +# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#ejections +func process_ejections(state: var BeaconState) = ## Iterate through the validator registry and eject active validators with ## balance below ``EJECTION_BALANCE`` - ## - ## https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#ejections - - for index, validator in state.validator_registry: - if is_active_validator(validator, state.slot) and - state.validator_balances[index] < EJECTION_BALANCE: - exit_validator(state, index.ValidatorIndex) + for index in get_active_validator_indices( + # TODO minor 0.3.0 bug: it says just current_epoch(state) + state.validator_registry, get_current_epoch(state)): + if state.validator_balances[index] < EJECTION_BALANCE: + exit_validator(state, index) # https://github.com/ethereum/eth2.0-specs/blob/v0.2.0/specs/core/0_beacon-chain.md#per-slot-processing func processSlot(state: var BeaconState, previous_block_root: Eth2Digest) = @@ -519,7 +518,6 @@ func lowerThan(candidate, current: Eth2Digest): bool = if v > candidate.data[i]: return true false - # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data func process_slashings(state: var BeaconState) = ## Process the slashings. @@ -583,8 +581,8 @@ func process_exit_queue(state: var BeaconState) = break prepare_validator_for_withdrawal(state, index) +# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#per-epoch-processing func processEpoch(state: var BeaconState) = - # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#per-epoch-processing if (state.slot + 1) mod SLOTS_PER_EPOCH != 0: return @@ -716,18 +714,18 @@ func processEpoch(state: var BeaconState) = func total_balance_sac(crosslink_committee: CrosslinkCommittee): uint64 = get_total_balance(statePtr[], crosslink_committee.committee) - # https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#eth1-data-1 - block: # Eth1 data - if state.slot mod EPOCHS_PER_ETH1_VOTING_PERIOD == 0: + # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#eth1-data-1 + block: + if next_epoch mod EPOCHS_PER_ETH1_VOTING_PERIOD == 0: for x in state.eth1_data_votes: - if x.vote_count * 2 >= EPOCHS_PER_ETH1_VOTING_PERIOD: + if x.vote_count * 2 >= EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH: + # more than half the votes in this voting period were for that value state.latest_eth1_data = x.eth1_data break state.eth1_data_votes = @[] - block: # Justification - # https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#justification - + # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#justification + block: # First, update the justification bitfield var new_justified_epoch = state.justified_epoch state.justification_bitfield = state.justification_bitfield shl 1 @@ -752,47 +750,50 @@ func processEpoch(state: var BeaconState) = state.previous_justified_epoch = state.justified_epoch state.justified_epoch = new_justified_epoch - block: # Crosslinks - # https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks + # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#crosslinks + block: for slot in get_epoch_start_slot(previous_epoch) ..< get_epoch_start_slot(next_epoch): let crosslink_committees_at_slot = get_crosslink_committees_at_slot(state, slot) - # - #for crosslink_committee, shard in crosslink_committees_at_slot.items: - # if 3 * total_attesting_balance(crosslink_committee) >= 2 * total_balance(crosslink_committee): - # state.latest_crosslinks[shard] = Crosslink( - # slot=state.slot, shard_block_root=winning_root(crosslink_committee)) - # Rewards and penalties helpers - # https://github.com/ethereum/eth2.0-specs/blob/dev/specs/core/0_beacon-chain.md#rewards-and-penalties - let - base_reward_quotient = - integer_squareroot(previous_total_balance) div BASE_REWARD_QUOTIENT + for crosslink_committee in crosslink_committees_at_slot: + if 3'u64 * total_attesting_balance(crosslink_committee) >= + 2'u64 * get_total_balance(state, crosslink_committee.committee): + state.latest_crosslinks[crosslink_committee.shard] = Crosslink( + epoch: slot_to_epoch(slot), + shard_block_root: winning_root(crosslink_committee)) + + # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#rewards-and-penalties + ## First, we define some additional helpers + ## Note: When applying penalties in the following balance recalculations + ## implementers should make sure the uint64 does not underflow + let base_reward_quotient = + integer_squareroot(previous_total_balance) div BASE_REWARD_QUOTIENT func base_reward(state: BeaconState, index: ValidatorIndex): uint64 = - get_effective_balance(state, index) div base_reward_quotient.uint64 div 4 + get_effective_balance(state, index) div base_reward_quotient.uint64 div 5 func inactivity_penalty( state: BeaconState, index: ValidatorIndex, epochs_since_finality: uint64): uint64 = base_reward(state, index) + - get_effective_balance(state, index) * - epochs_since_finality div INACTIVITY_PENALTY_QUOTIENT div 2 + get_effective_balance(state, index) * epochs_since_finality div + INACTIVITY_PENALTY_QUOTIENT div 2 + # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#justification-and-finalization func inclusion_slot(state: BeaconState, v: ValidatorIndex): uint64 = for a in previous_epoch_attestations: if v in get_attestation_participants(state, a.data, a.aggregation_bitfield): return a.inclusion_slot - doAssert false # shouldn't happen.. + doAssert false func inclusion_distance(state: BeaconState, v: ValidatorIndex): uint64 = for a in previous_epoch_attestations: if v in get_attestation_participants(state, a.data, a.aggregation_bitfield): return a.inclusion_slot - a.data.slot - doAssert false # shouldn't happen.. + doAssert false let active_validator_indices = get_active_validator_indices(state.validator_registry, state.slot) - # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#justification-and-finalization block: # Justification and finalization let epochs_since_finality = next_epoch - state.finalized_epoch @@ -867,16 +868,16 @@ func processEpoch(state: var BeaconState) = # TODO underflows? state.validator_balances[index] -= base_reward(state, index) - block: # Ejections - process_ejections(state) + # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#ejections + process_ejections(state) - block: # Validator registry and shuffling seed data - # https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data + # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data + block: state.previous_shuffling_epoch = state.current_shuffling_epoch state.previous_shuffling_start_shard = state.current_shuffling_start_shard state.previous_shuffling_seed = state.current_shuffling_seed - #TODO state.latest_index_roots[next_epoch mod LATEST_ACTIVE_INDEX_ROOTS_LENGTH] = hash_tree_root_final(get_active_validator_indices(state.validator_registry, next_epoch)) + # TODO verify this shard list if state.finalized_epoch > state.validator_registry_update_epoch and allIt( 0 ..< get_current_epoch_committee_count(state).int * SLOTS_PER_EPOCH, @@ -884,8 +885,11 @@ func processEpoch(state: var BeaconState) = update_validator_registry(state) state.current_shuffling_epoch = next_epoch - state.current_shuffling_start_shard = (state.current_shuffling_start_shard + get_current_epoch_committee_count(state) * SLOTS_PER_EPOCH) mod SHARD_COUNT - state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch) + state.current_shuffling_start_shard = + (state.current_shuffling_start_shard + + get_current_epoch_committee_count(state)) mod SHARD_COUNT + state.current_shuffling_seed = generate_seed( + state, state.current_shuffling_epoch) else: # If a validator registry change does NOT happen let epochs_since_last_registry_change = current_epoch - state.validator_registry_update_epoch @@ -893,7 +897,6 @@ func processEpoch(state: var BeaconState) = state.current_shuffling_epoch = next_epoch state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch) # /Note/ that state.current_shuffling_start_shard is left unchanged - # TODO run process_penalties_and_exits ## Regardless of whether or not a validator set change happens run ## process_slashings(state) and process_exit_queue(state) diff --git a/tests/testutil.nim b/tests/testutil.nim index 966f35767..a22aa4a65 100644 --- a/tests/testutil.nim +++ b/tests/testutil.nim @@ -1,5 +1,5 @@ # beacon_chain -# Copyright (c) 2018 Status Research & Development GmbH +# Copyright (c) 2018-2019 Status Research & Development GmbH # Licensed and distributed under either of # * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). # * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). @@ -81,6 +81,11 @@ proc addBlock*( let proposer_index = get_beacon_proposer_index(state, state.slot) state.slot -= 1 + # Ferret out remaining GENESIS_EPOCH == 0 assumptions in test code + doAssert allIt( + body.attestations, + it.data.latest_crosslink.epoch >= GENESIS_EPOCH) + let # Index from the new state, but registry from the old state.. hmm... proposer = state.validator_registry[proposer_index] @@ -168,7 +173,7 @@ proc makeAttestation*( shard: sac.shard, beacon_block_root: beacon_block_root, epoch_boundary_root: Eth2Digest(), # TODO - latest_crosslink: Crosslink(), # TODO + latest_crosslink: Crosslink(epoch: state.latest_crosslinks[sac.shard].epoch), # TODO shard_block_root: Eth2Digest(), # TODO justified_epoch: state.justified_epoch, justified_block_root: get_block_root(state, get_epoch_start_slot(state.justified_epoch)),