parent
0d775eefcb
commit
0141c84fe5
|
@ -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)
|
||||
|
||||
|
|
|
@ -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*(
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue