From 0141c84fe5dfbb5d81dce06816cdabf288491ee4 Mon Sep 17 00:00:00 2001 From: tersec Date: Mon, 3 Dec 2018 17:46:22 +0000 Subject: [PATCH] data type updates from spec (#25) * data type updates from spec --- beacon_chain/beacon_node.nim | 4 +- beacon_chain/spec/beaconstate.nim | 14 +++---- beacon_chain/spec/datatypes.nim | 63 +++++++++++++++++-------------- beacon_chain/spec/validator.nim | 24 ++++++------ beacon_chain/state_transition.nim | 4 +- beacon_chain/sync_protocol.nim | 6 +-- tests/test_beaconstate.nim | 4 +- tests/test_validator.nim | 6 +-- tests/testhelpers.nim | 2 +- 9 files changed, 66 insertions(+), 61 deletions(-) diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index db6a9154b..abd97dde9 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -131,7 +131,7 @@ proc scheduleCycleActions(node: BeaconNode) = ## attestations from our attached validators. let cycleStart = node.beaconState.last_state_recalculation_slot.int - for i in 0 ..< CYCLE_LENGTH: + for i in 0 ..< EPOCH_LENGTH: # Schedule block proposals let slot = cycleStart + i @@ -170,7 +170,7 @@ proc processBlocks*(node: BeaconNode) {.async.} = # 3. Peform block processing / state recalculation / etc # - if b.slot mod CYCLE_LENGTH == 0: + if b.slot mod EPOCH_LENGTH == 0: node.scheduleCycleActions() node.attestations.discardHistoryToSlot(b.slot) diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 5d11d36dc..c440cf875 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -26,11 +26,11 @@ func on_startup*(initial_validator_entries: openArray[InitialValidator], ## must be calculated before creating the genesis block. # # Induct validators - # Not in spec: the system doesn't work unless there are at least CYCLE_LENGTH + # Not in spec: the system doesn't work unless there are at least EPOCH_LENGTH # validators - there needs to be at least one member in each committee - # good to know for testing, though arguably the system is not that useful at # at that point :) - assert initial_validator_entries.len >= CYCLE_LENGTH + assert initial_validator_entries.len >= EPOCH_LENGTH var validators: seq[ValidatorRecord] @@ -55,10 +55,10 @@ func on_startup*(initial_validator_entries: openArray[InitialValidator], x = get_new_shuffling(Eth2Digest(), validators, 0) # x + x in spec, but more ugly - var tmp: array[2 * CYCLE_LENGTH, seq[ShardAndCommittee]] + var tmp: array[2 * EPOCH_LENGTH, seq[ShardAndCommittee]] for i, n in x: tmp[i] = n - tmp[CYCLE_LENGTH + i] = n + tmp[EPOCH_LENGTH + i] = n # The spec says to use validators, but it's actually indices.. let validator_indices = get_active_validator_indices(validators) @@ -77,13 +77,13 @@ func on_startup*(initial_validator_entries: openArray[InitialValidator], func get_shards_and_committees_index*(state: BeaconState, slot: uint64): uint64 = # TODO spec unsigned-unsafe here let earliest_slot_in_array = - if state.last_state_recalculation_slot > CYCLE_LENGTH.uint64: - state.last_state_recalculation_slot - CYCLE_LENGTH + if state.last_state_recalculation_slot > EPOCH_LENGTH.uint64: + state.last_state_recalculation_slot - EPOCH_LENGTH else: 0 doAssert earliest_slot_in_array <= slot and - slot < earliest_slot_in_array + CYCLE_LENGTH * 2 + slot < earliest_slot_in_array + EPOCH_LENGTH * 2 slot - earliest_slot_in_array proc get_shards_and_committees_for_slot*( diff --git a/beacon_chain/spec/datatypes.nim b/beacon_chain/spec/datatypes.nim index 85f215be0..d724d72af 100644 --- a/beacon_chain/spec/datatypes.nim +++ b/beacon_chain/spec/datatypes.nim @@ -16,7 +16,7 @@ # https://github.com/ethereum/eth2.0-specs/blob/master/specs/beacon-chain.md # # How wrong the code is: -# https://github.com/ethereum/eth2.0-specs/compare/126a7abfa86448091a0e037f52966b6a9531a857...master +# https://github.com/ethereum/eth2.0-specs/compare/2983e68f0305551083fac7fcf9330c1fc9da3411...master # # These datatypes are used as specifications for serialization - thus should not # be altered outside of what the spec says. Likewise, they should not be made @@ -29,36 +29,41 @@ import const SHARD_COUNT* = 1024 # a constant referring to the number of shards - DEPOSIT_SIZE* = 2^5 # You need to deposit 32 ETH to be a validator in Casper - MIN_TOPUP_SIZE* = 1 # ETH - MIN_ONLINE_DEPOSIT_SIZE* = 2^4 # ETH - GWEI_PER_ETH* = 10^9 # Gwei/ETH - DEPOSITS_FOR_CHAIN_START* = 2^14 # deposits TARGET_COMMITTEE_SIZE* = 2^8 # validators - SLOT_DURATION* = 6 # seconds - CYCLE_LENGTH* = 64 # slots (~ 6 minutes) - MIN_VALIDATOR_SET_CHANGE_INTERVAL* = 2^8 # slots (~25 minutes) - SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD* = 2^17 # slots (~9 days) - MIN_ATTESTATION_INCLUSION_DELAY* = 4 # slots (~25 minutes) - SQRT_E_DROP_TIME* = 2^9 # slots (~9 days); amount of time it takes for the - # quadratic leak to cut deposits of non-participating - # validators by ~39.4% + MAX_ATTESTATIONS_PER_BLOCK* = 2^7 # attestations + MAX_DEPOSIT* = 2^5 # ETH + MIN_BALANCE* = 2^4 # ETH + POW_CONTRACT_MERKLE_TREE_DEPTH* = 2^5 # + INITIAL_FORK_VERSION* = 0 # + INITIAL_SLOT_NUMBER* = 0 # + GWEI_PER_ETH* = 10^9 # Gwei/ETH + BEACON_CHAIN_SHARD_NUMBER* = not 0'u64 WITHDRAWALS_PER_CYCLE* = 2^2 # validators (5.2m ETH in ~6 months) MIN_WITHDRAWAL_PERIOD* = 2^13 # slots (~14 hours) - DELETION_PERIOD* = 2^22 # slots (~290 days) - COLLECTIVE_PENALTY_CALCULATION_PERIOD* = 2^20 # slots (~2.4 months) + + # Time constants + SLOT_DURATION* = 6 # seconds + MIN_ATTESTATION_INCLUSION_DELAY* = 4 # slots (~25 minutes) + EPOCH_LENGTH* = 64 # slots (~6.4 minutes) + MIN_VALIDATOR_SET_CHANGE_INTERVAL* = 2^8 # slots (~25.6 minutes) POW_RECEIPT_ROOT_VOTING_PERIOD* = 2^10 # slots (~1.7 hours) - SLASHING_WHISTLEBLOWER_REWARD_DENOMINATOR* = 2^9 # ? + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD* = 2^17 # slots (~9 days) + SQRT_E_DROP_TIME* = 2^17 # slots (~9 days); amount of time it takes for the + # quadratic leak to cut deposits of non-participating + # validators by ~39.4% + COLLECTIVE_PENALTY_CALCULATION_PERIOD* = 2^20 # slots (~2.4 months) + DELETION_PERIOD* = 2^22 # slots (~290 days) + + # Quotients BASE_REWARD_QUOTIENT* = 2^11 # per-cycle interest rate assuming all validators are # participating, assuming total deposits of 1 ETH. It # corresponds to ~2.57% annual interest assuming 10 # million participating ETH. - MAX_VALIDATOR_CHURN_QUOTIENT* = 2^5 # At most `1/MAX_VALIDATOR_CHURN_QUOTIENT` of the + WHISTLEBLOWER_REWARD_QUOTIENT* = 2^9 # ? + INCLUDER_REWARD_QUOTIENT* = 2^3 # + MAX_CHURN_QUOTIENT* = 2^5 # At most `1/MAX_VALIDATOR_CHURN_QUOTIENT` of the # validators can change during each validator set # change. - POW_CONTRACT_MERKLE_TREE_DEPTH* = 2^5 # - MAX_ATTESTATION_COUNT* = 2^7 # - INITIAL_FORK_VERSION* = 0 # type Uint24* = range[0'u32 .. 0xFFFFFF'u32] # TODO: wrap-around @@ -110,7 +115,7 @@ type justification_source*: uint64 # Justification source prev_cycle_justification_source*: uint64 # justified_slot_bitfield*: uint64 # Recent justified slot bitmask - shard_and_committee_for_slots*: array[2 * CYCLE_LENGTH, seq[ShardAndCommittee]] ## \ + shard_and_committee_for_slots*: array[2 * EPOCH_LENGTH, seq[ShardAndCommittee]] ## \ ## Committee members and their assigned shard, per slot, covers 2 cycles ## worth of assignments persistent_committees*: seq[seq[Uint24]] # Persistent shard committees @@ -167,20 +172,20 @@ type slot_included*: uint64 # Slot in which it was included ValidatorStatusCodes* {.pure.} = enum - PendingActivation = 0 - Active = 1 - PendingExit = 2 - PendingWithdraw = 3 - Withdrawn = 4 - Penalized = 127 + PENDING_ACITVATION = 0 + ACTIVE = 1 + EXITED_WITHOUT_PENALTY = 2 + EXITED_WITH_PENALTY = 3 + PENDING_EXIT = 29 # https://github.com/ethereum/eth2.0-specs/issues/216 SpecialRecordType* {.pure.} = enum Logout = 0 CasperSlashing = 1 RandaoChange = 2 + DepositProof = 3 ValidatorSetDeltaFlags* {.pure.} = enum - Entry = 0 + Activation = 0 Exit = 1 # Note: diff --git a/beacon_chain/spec/validator.nim b/beacon_chain/spec/validator.nim index 26917c4e1..17f5b20d5 100644 --- a/beacon_chain/spec/validator.nim +++ b/beacon_chain/spec/validator.nim @@ -11,15 +11,15 @@ import eth_common, ./crypto, ./datatypes, ./digest, ./helpers -func min_empty_validator(validators: seq[ValidatorRecord], current_slot: uint64): Option[int] = +func min_empty_validator_index(validators: seq[ValidatorRecord], current_slot: uint64): Option[int] = for i, v in validators: - if v.status == WITHDRAWN and v.last_status_change_slot + DELETION_PERIOD.uint64 <= current_slot: + if v.balance == 0 and v.last_status_change_slot + DELETION_PERIOD.uint64 <= current_slot: return some(i) func get_new_validators*(current_validators: seq[ValidatorRecord], fork_data: ForkData, pubkey: ValidatorPubKey, - deposit_size: uint64, + deposit: uint64, proof_of_possession: seq[byte], withdrawal_credentials: Eth2Digest, randao_commitment: Eth2Digest, @@ -47,7 +47,7 @@ func get_new_validators*(current_validators: seq[ValidatorRecord], # assert val.status != WITHDRAWN # assert val.withdrawal_credentials == withdrawal_credentials - val.balance.inc(deposit_size.int) + val.balance.inc(deposit.int) return (new_validators, index) # new validator @@ -57,13 +57,13 @@ func get_new_validators*(current_validators: seq[ValidatorRecord], withdrawal_credentials: withdrawal_credentials, randao_commitment: randao_commitment, randao_skips: 0, - balance: DEPOSIT_SIZE * GWEI_PER_ETH, + balance: deposit, status: status, last_status_change_slot: current_slot, exit_seq: 0 ) - let index = min_empty_validator(new_validators, current_slot) + let index = min_empty_validator_index(new_validators, current_slot) if index.isNone: new_validators.add(rec) (new_validators, len(new_validators) - 1) @@ -74,13 +74,13 @@ func get_new_validators*(current_validators: seq[ValidatorRecord], func get_active_validator_indices*(validators: openArray[ValidatorRecord]): seq[Uint24] = ## Select the active validators for idx, val in validators: - if val.status == ACTIVE: + if val.status == ACTIVE or val.status == PENDING_EXIT: result.add idx.Uint24 func get_new_shuffling*(seed: Eth2Digest, validators: openArray[ValidatorRecord], crosslinking_start_shard: int - ): array[CYCLE_LENGTH, seq[ShardAndCommittee]] = + ): array[EPOCH_LENGTH, seq[ShardAndCommittee]] = ## Split up validators into groups at the start of every epoch, ## determining at what height they can make attestations and what shard they are making crosslinks for ## Implementation should do the following: http://vitalik.ca/files/ShuffleAndAssign.png @@ -88,14 +88,14 @@ func get_new_shuffling*(seed: Eth2Digest, let active_validators = get_active_validator_indices(validators) committees_per_slot = clamp( - len(active_validators) div CYCLE_LENGTH div TARGET_COMMITTEE_SIZE, - 1, SHARD_COUNT div CYCLE_LENGTH) + len(active_validators) div EPOCH_LENGTH div TARGET_COMMITTEE_SIZE, + 1, SHARD_COUNT div EPOCH_LENGTH) # Shuffle with seed shuffled_active_validator_indices = shuffle(active_validators, seed) # Split the shuffled list into cycle_length pieces - validators_per_slot = split(shuffled_active_validator_indices, CYCLE_LENGTH) + validators_per_slot = split(shuffled_active_validator_indices, EPOCH_LENGTH) - assert validators_per_slot.len() == CYCLE_LENGTH # what split should do.. + assert validators_per_slot.len() == EPOCH_LENGTH # what split should do.. for slot, slot_indices in validators_per_slot: let diff --git a/beacon_chain/state_transition.nim b/beacon_chain/state_transition.nim index b05a6b6a5..ee5c62774 100644 --- a/beacon_chain/state_transition.nim +++ b/beacon_chain/state_transition.nim @@ -26,14 +26,14 @@ func checkAttestations(state: BeaconState, blck: BeaconBlock, parent_slot: uint64): Option[seq[ProcessedAttestation]] = # TODO perf improvement potential.. - if blck.attestations.len > MAX_ATTESTATION_COUNT: + if blck.attestations.len > MAX_ATTESTATIONS_PER_BLOCK: return var res: seq[ProcessedAttestation] for attestation in blck.attestations: if attestation.data.slot <= blck.slot - MIN_ATTESTATION_INCLUSION_DELAY: return - if attestation.data.slot >= max(parent_slot - CYCLE_LENGTH + 1, 0): + if attestation.data.slot >= max(parent_slot - EPOCH_LENGTH + 1, 0): return #doAssert attestation.data.justified_slot == justification_source if attestation.data.slot >= state.last_state_recalculation_slot else prev_cycle_justification_source # doAssert attestation.data.justified_block_hash == get_block_hash(state, block, attestation.data.justified_slot). diff --git a/beacon_chain/sync_protocol.nim b/beacon_chain/sync_protocol.nim index d146d5823..6d2c71847 100644 --- a/beacon_chain/sync_protocol.nim +++ b/beacon_chain/sync_protocol.nim @@ -6,7 +6,7 @@ import type ValidatorChangeLogEntry* = object case kind*: ValidatorSetDeltaFlags - of Entry: + of Activation: pubkey: ValidatorPubKey else: index: uint32 @@ -55,7 +55,7 @@ iterator changes*(log: ChangeLog): ChangeLogEntry = for i in 0 ..< bits: yield if log.order.getBit(i): - ChangeLogEntry(kind: Entry, pubkey: nextItem(added)) + ChangeLogEntry(kind: Activation, pubkey: nextItem(added)) else: ChangeLogEntry(kind: Exit, index: nextItem(removed)) @@ -86,7 +86,7 @@ proc applyValidatorChangeLog*(log: ChangeLog, # outBeaconState.last_finalized_slot = - log.signedBlock.slot div CYCLE_LENGTH + log.signedBlock.slot div EPOCH_LENGTH outBeaconState.validator_set_delta_hash_chain = log.beaconState.validator_set_delta_hash_chain diff --git a/tests/test_beaconstate.nim b/tests/test_beaconstate.nim index 75bc69755..5bb28c276 100644 --- a/tests/test_beaconstate.nim +++ b/tests/test_beaconstate.nim @@ -15,5 +15,5 @@ suite "Beacon state": # Smoke test test "Smoke on_startup": - let state = on_startup(makeInitialValidators(CYCLE_LENGTH), 0, Eth2Digest()) - check: state.validators.len == CYCLE_LENGTH + let state = on_startup(makeInitialValidators(EPOCH_LENGTH), 0, Eth2Digest()) + check: state.validators.len == EPOCH_LENGTH diff --git a/tests/test_validator.nim b/tests/test_validator.nim index 5bd60be66..cc2a13cde 100644 --- a/tests/test_validator.nim +++ b/tests/test_validator.nim @@ -27,9 +27,9 @@ suite "Validators": # TODO the shuffling looks really odd, probably buggy let s = get_new_shuffling(Eth2Digest(), validators, 0) check: - s.len == CYCLE_LENGTH + s.len == EPOCH_LENGTH # 32k validators means 2 shards validated per slot - the aim is to get # TARGET_COMMITTEE_SIZE validators in each shard and there are - # CYCLE_LENGTH slots which each will crosslink a different shard - s[0].len == 32 * 1024 div (TARGET_COMMITTEE_SIZE * CYCLE_LENGTH) + # EPOCH_LENGTH slots which each will crosslink a different shard + s[0].len == 32 * 1024 div (TARGET_COMMITTEE_SIZE * EPOCH_LENGTH) sumCommittees(s) == validators.len() # all validators accounted for diff --git a/tests/testhelpers.nim b/tests/testhelpers.nim index 7b46cf1cc..e6d39f7d9 100644 --- a/tests/testhelpers.nim +++ b/tests/testhelpers.nim @@ -12,7 +12,7 @@ import func makeValidatorPubKey(n: int): ValidatorPubKey = result.point.x.a.g[0] = n -func makeInitialValidators*(n = CYCLE_LENGTH): seq[InitialValidator] = +func makeInitialValidators*(n = EPOCH_LENGTH): seq[InitialValidator] = for i in 0..