data type updates from spec (#25)

* data type updates from spec
This commit is contained in:
tersec 2018-12-03 17:46:22 +00:00 committed by Jacek Sieka
parent 0d775eefcb
commit 0141c84fe5
9 changed files with 66 additions and 61 deletions

View File

@ -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)

View File

@ -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*(

View File

@ -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:

View File

@ -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

View File

@ -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).

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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..<n:
result.add InitialValidator(
pubkey: makeValidatorPubKey(i)