mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-09 22:06:21 +00:00
initial new get_beacon_proposer_index and dependencies (get_shuffled_index, get_shard_delta, get_epoch_start_shard, get_crosslink_committee) (#266)
* initial new get_beacon_proposer_index and dependencies (get_shuffled_index, get_shard_delta, get_epoch_start_shard, get_crosslink_committee) * more 0.6.1 updates * clean up debugEchos and fix validator keygen to create correct indices
This commit is contained in:
parent
2a4c4df7c3
commit
46cfce652d
@ -497,7 +497,8 @@ proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
|
|||||||
# revisit this - we should be able to advance behind
|
# revisit this - we should be able to advance behind
|
||||||
node.blockPool.withState(node.stateCache, BlockSlot(blck: head, slot: slot)):
|
node.blockPool.withState(node.stateCache, BlockSlot(blck: head, slot: slot)):
|
||||||
let
|
let
|
||||||
proposerIdx = get_beacon_proposer_index(state, slot)
|
# TODO this probably isn't correct, check re blob/v0.5.1
|
||||||
|
proposerIdx = get_beacon_proposer_index(state)
|
||||||
validator = node.getAttachedValidator(state, proposerIdx)
|
validator = node.getAttachedValidator(state, proposerIdx)
|
||||||
|
|
||||||
if validator != nil:
|
if validator != nil:
|
||||||
|
@ -178,7 +178,7 @@ func slash_validator*(state: var BeaconState, index: ValidatorIndex) =
|
|||||||
] += get_effective_balance(state, index)
|
] += get_effective_balance(state, index)
|
||||||
|
|
||||||
let
|
let
|
||||||
whistleblower_index = get_beacon_proposer_index(state, state.slot)
|
whistleblower_index = get_beacon_proposer_index(state)
|
||||||
whistleblower_reward = get_effective_balance(state, index) div
|
whistleblower_reward = get_effective_balance(state, index) div
|
||||||
WHISTLEBLOWER_REWARD_QUOTIENT
|
WHISTLEBLOWER_REWARD_QUOTIENT
|
||||||
|
|
||||||
|
@ -391,6 +391,7 @@ type
|
|||||||
|
|
||||||
# Randomness and committees
|
# Randomness and committees
|
||||||
latest_randao_mixes*: array[LATEST_RANDAO_MIXES_LENGTH, Eth2Digest]
|
latest_randao_mixes*: array[LATEST_RANDAO_MIXES_LENGTH, Eth2Digest]
|
||||||
|
latest_start_shard*: Shard
|
||||||
previous_shuffling_start_shard*: uint64
|
previous_shuffling_start_shard*: uint64
|
||||||
current_shuffling_start_shard*: uint64
|
current_shuffling_start_shard*: uint64
|
||||||
previous_shuffling_epoch*: Epoch
|
previous_shuffling_epoch*: Epoch
|
||||||
|
@ -146,29 +146,20 @@ func get_current_epoch*(state: BeaconState): Epoch =
|
|||||||
doAssert state.slot >= GENESIS_SLOT, $state.slot
|
doAssert state.slot >= GENESIS_SLOT, $state.slot
|
||||||
slot_to_epoch(state.slot)
|
slot_to_epoch(state.slot)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.0/specs/core/0_beacon-chain.md#get_randao_mix
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_randao_mix
|
||||||
func get_randao_mix*(state: BeaconState,
|
func get_randao_mix*(state: BeaconState,
|
||||||
epoch: Epoch): Eth2Digest =
|
epoch: Epoch): Eth2Digest =
|
||||||
## Returns the randao mix at a recent ``epoch``.
|
## Returns the randao mix at a recent ``epoch``.
|
||||||
|
## ``epoch`` expected to be between
|
||||||
# Cannot underflow, since GENESIS_EPOCH > LATEST_RANDAO_MIXES_LENGTH
|
## (current_epoch - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY,
|
||||||
doAssert get_current_epoch(state) - LATEST_RANDAO_MIXES_LENGTH < epoch
|
## current_epoch + ACTIVATION_EXIT_DELAY].
|
||||||
doAssert epoch <= get_current_epoch(state)
|
|
||||||
|
|
||||||
state.latest_randao_mixes[epoch mod LATEST_RANDAO_MIXES_LENGTH]
|
state.latest_randao_mixes[epoch mod LATEST_RANDAO_MIXES_LENGTH]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_active_index_root
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_active_index_root
|
||||||
func get_active_index_root(state: BeaconState, epoch: Epoch): Eth2Digest =
|
func get_active_index_root(state: BeaconState, epoch: Epoch): Eth2Digest =
|
||||||
# Returns the index root at a recent ``epoch``.
|
# Returns the index root at a recent ``epoch``.
|
||||||
|
## ``epoch`` expected to be between
|
||||||
## Cannot underflow, since GENESIS_EPOCH > LATEST_RANDAO_MIXES_LENGTH
|
## (current_epoch - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY].
|
||||||
## and ACTIVATION_EXIT_DELAY > 0.
|
|
||||||
doAssert GENESIS_EPOCH > LATEST_RANDAO_MIXES_LENGTH
|
|
||||||
doAssert ACTIVATION_EXIT_DELAY > 0
|
|
||||||
|
|
||||||
doAssert get_current_epoch(state) - LATEST_ACTIVE_INDEX_ROOTS_LENGTH +
|
|
||||||
ACTIVATION_EXIT_DELAY < epoch
|
|
||||||
doAssert epoch <= get_current_epoch(state) + ACTIVATION_EXIT_DELAY
|
|
||||||
state.latest_active_index_roots[epoch mod LATEST_ACTIVE_INDEX_ROOTS_LENGTH]
|
state.latest_active_index_roots[epoch mod LATEST_ACTIVE_INDEX_ROOTS_LENGTH]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.2.0/specs/core/0_beacon-chain.md#bytes_to_int
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.2.0/specs/core/0_beacon-chain.md#bytes_to_int
|
||||||
@ -235,9 +226,9 @@ func generate_seed*(state: BeaconState, epoch: Epoch): Eth2Digest =
|
|||||||
|
|
||||||
var seed_input : array[32*3, byte]
|
var seed_input : array[32*3, byte]
|
||||||
|
|
||||||
doAssert GENESIS_EPOCH > MIN_SEED_LOOKAHEAD
|
seed_input[0..31] =
|
||||||
|
get_randao_mix(state,
|
||||||
seed_input[0..31] = get_randao_mix(state, epoch - MIN_SEED_LOOKAHEAD).data
|
epoch + LATEST_RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD).data
|
||||||
seed_input[32..63] = get_active_index_root(state, epoch).data
|
seed_input[32..63] = get_active_index_root(state, epoch).data
|
||||||
seed_input[64..95] = int_to_bytes32(epoch)
|
seed_input[64..95] = int_to_bytes32(epoch)
|
||||||
eth2hash(seed_input)
|
eth2hash(seed_input)
|
||||||
|
@ -80,6 +80,44 @@ func get_shuffled_seq*(seed: Eth2Digest,
|
|||||||
|
|
||||||
result = shuffled_active_validator_indices
|
result = shuffled_active_validator_indices
|
||||||
|
|
||||||
|
func get_shuffled_index(index: ValidatorIndex, index_count: uint64, seed: Eth2Digest): uint64 =
|
||||||
|
## Return the shuffled validator index corresponding to ``seed`` (and
|
||||||
|
## ``index_count``).
|
||||||
|
## https://github.com/status-im/nim-beacon-chain/blob/f77016af6818ad2c853f6c9e2751b17548e0222e/beacon_chain/spec/validator.nim#L15
|
||||||
|
|
||||||
|
doAssert index.uint64 < index_count
|
||||||
|
doAssert index_count <= 2'u64^40
|
||||||
|
|
||||||
|
result = index
|
||||||
|
var pivot_buffer: array[(32+1), byte]
|
||||||
|
var source_buffer: array[(32+1+4), byte]
|
||||||
|
|
||||||
|
# Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
|
||||||
|
# See the 'generalized domain' algorithm on page 3
|
||||||
|
for round in 0 ..< SHUFFLE_ROUND_COUNT:
|
||||||
|
pivot_buffer[0..31] = seed.data
|
||||||
|
let round_bytes1 = int_to_bytes1(round)[0]
|
||||||
|
pivot_buffer[32] = round_bytes1
|
||||||
|
|
||||||
|
let
|
||||||
|
pivot = bytes_to_int(eth2hash(pivot_buffer).data[0..7]) mod index_count
|
||||||
|
flip = (pivot - index) mod index_count
|
||||||
|
position = max(index.uint64, flip)
|
||||||
|
|
||||||
|
## Tradeoff between slicing (if reusing one larger buffer) and additional
|
||||||
|
## copies here of seed and `int_to_bytes1(round)`.
|
||||||
|
source_buffer[0..31] = seed.data
|
||||||
|
source_buffer[32] = round_bytes1
|
||||||
|
source_buffer[33..36] = int_to_bytes4(position div 256)
|
||||||
|
|
||||||
|
let
|
||||||
|
source = eth2hash(source_buffer).data
|
||||||
|
byte_value = source[(position mod 256) div 8]
|
||||||
|
bit = (byte_value shr (position mod 8)) mod 2
|
||||||
|
|
||||||
|
if bit != 0:
|
||||||
|
result = flip
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#get_shuffling
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#get_shuffling
|
||||||
func get_shuffling*(seed: Eth2Digest,
|
func get_shuffling*(seed: Eth2Digest,
|
||||||
validators: openArray[Validator],
|
validators: openArray[Validator],
|
||||||
@ -212,36 +250,76 @@ iterator get_crosslink_committees_at_slot_cached*(
|
|||||||
cache.crosslink_committee_cache[key] = result
|
cache.crosslink_committee_cache[key] = result
|
||||||
for v in result: yield v
|
for v in result: yield v
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_beacon_proposer_index
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_shard_delta
|
||||||
# TODO remove/merge these back together once 0.5.1 callers removed
|
func get_shard_delta(state: BeaconState, epoch: Epoch): uint64 =
|
||||||
func get_beacon_proposer_index*(state: BeaconState, slot: Slot): ValidatorIndex =
|
## Return the number of shards to increment ``state.latest_start_shard``
|
||||||
## From Casper RPJ mini-spec:
|
## during ``epoch``.
|
||||||
## When slot i begins, validator Vidx is expected
|
min(get_epoch_committee_count(state, epoch),
|
||||||
## to create ("propose") a block, which contains a pointer to some parent block
|
(SHARD_COUNT - SHARD_COUNT div SLOTS_PER_EPOCH).uint64)
|
||||||
## that they perceive as the "head of the chain",
|
|
||||||
## and includes all of the **attestations** that they know about
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_epoch_start_shard
|
||||||
## that have not yet been included into that chain.
|
func get_epoch_start_shard(state: BeaconState, epoch: Epoch): Shard =
|
||||||
##
|
doAssert epoch <= get_current_epoch(state) + 1
|
||||||
## idx in Vidx == p(i mod N), pi being a random permutation of validators indices (i.e. a committee)
|
var
|
||||||
## Returns the beacon proposer index for the ``slot``.
|
check_epoch = get_current_epoch(state) + 1
|
||||||
# TODO this index is invalid outside of the block state transition function
|
shard =
|
||||||
# because presently, `state.slot += 1` happens before this function
|
(state.latest_start_shard +
|
||||||
# is called - see also testutil.getNextBeaconProposerIndex
|
get_shard_delta(state, get_current_epoch(state))) mod SHARD_COUNT
|
||||||
# TODO is the above still true? the shuffling has changed since it was written
|
while check_epoch > epoch:
|
||||||
|
check_epoch -= 1
|
||||||
|
shard = (shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) mod
|
||||||
|
SHARD_COUNT
|
||||||
|
return shard
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#compute_committee
|
||||||
|
func compute_committee(indices: seq[ValidatorIndex], seed: Eth2Digest,
|
||||||
|
index: uint64, count: uint64): seq[ValidatorIndex] =
|
||||||
let
|
let
|
||||||
epoch = slot_to_epoch(slot)
|
start = (len(indices).uint64 * index) div count
|
||||||
current_epoch = get_current_epoch(state)
|
endIdx = (len(indices).uint64 * (index + 1)) div count
|
||||||
previous_epoch = get_previous_epoch(state)
|
doAssert endIdx.int - start.int > 0
|
||||||
next_epoch = current_epoch + 1
|
mapIt(
|
||||||
|
start.int .. (endIdx.int-1),
|
||||||
|
indices[
|
||||||
|
get_shuffled_index(it.ValidatorIndex, len(indices).uint64, seed).int])
|
||||||
|
|
||||||
doAssert previous_epoch <= epoch
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_crosslink_committee
|
||||||
doAssert epoch <= next_epoch
|
func get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard):
|
||||||
|
seq[ValidatorIndex] =
|
||||||
let (first_committee, _) = get_crosslink_committees_at_slot(state, slot)[0]
|
compute_committee(
|
||||||
let idx = int(slot mod uint64(first_committee.len))
|
get_active_validator_indices(state, epoch),
|
||||||
first_committee[idx]
|
generate_seed(state, epoch),
|
||||||
|
(shard + SHARD_COUNT - get_epoch_start_shard(state, epoch)) mod SHARD_COUNT,
|
||||||
|
get_epoch_committee_count(state, epoch),
|
||||||
|
)
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#get_beacon_proposer_index
|
||||||
func get_beacon_proposer_index*(state: BeaconState): ValidatorIndex =
|
func get_beacon_proposer_index*(state: BeaconState): ValidatorIndex =
|
||||||
# Return the beacon proposer index at ``state.slot``.
|
# Return the current beacon proposer index.
|
||||||
# TODO there are some other changes here
|
const
|
||||||
get_beacon_proposer_index(state, state.slot)
|
MAX_RANDOM_BYTE = 255
|
||||||
|
|
||||||
|
let
|
||||||
|
epoch = get_current_epoch(state)
|
||||||
|
committees_per_slot =
|
||||||
|
get_epoch_committee_count(state, epoch) div SLOTS_PER_EPOCH
|
||||||
|
offset = committees_per_slot * (state.slot mod SLOTS_PER_EPOCH)
|
||||||
|
shard = (get_epoch_start_shard(state, epoch) + offset) mod SHARD_COUNT
|
||||||
|
first_committee = get_crosslink_committee(state, epoch, shard)
|
||||||
|
seed = generate_seed(state, epoch)
|
||||||
|
|
||||||
|
var
|
||||||
|
i = 0
|
||||||
|
buffer: array[(32+8), byte]
|
||||||
|
buffer[0..31] = seed.data
|
||||||
|
while true:
|
||||||
|
buffer[32..39] = int_to_bytes8(i.uint64 div 32)
|
||||||
|
let
|
||||||
|
candidate_index = first_committee[((epoch + i.uint64) mod
|
||||||
|
len(first_committee).uint64).int]
|
||||||
|
random_byte = (eth2hash(buffer).data)[i mod 32]
|
||||||
|
effective_balance =
|
||||||
|
state.validator_registry[candidate_index].effective_balance
|
||||||
|
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||||
|
return candidate_index
|
||||||
|
i += 1
|
||||||
|
@ -57,7 +57,7 @@ proc processBlockHeader(
|
|||||||
state.latest_block_header = get_temporary_block_header(blck)
|
state.latest_block_header = get_temporary_block_header(blck)
|
||||||
|
|
||||||
let proposer =
|
let proposer =
|
||||||
state.validator_registry[get_beacon_proposer_index(state, state.slot)]
|
state.validator_registry[get_beacon_proposer_index(state)]
|
||||||
if skipValidation notin flags and not bls_verify(
|
if skipValidation notin flags and not bls_verify(
|
||||||
proposer.pubkey,
|
proposer.pubkey,
|
||||||
signing_root(blck).data,
|
signing_root(blck).data,
|
||||||
@ -75,7 +75,7 @@ proc processBlockHeader(
|
|||||||
proc processRandao(
|
proc processRandao(
|
||||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
||||||
let
|
let
|
||||||
proposer_index = get_beacon_proposer_index(state, state.slot)
|
proposer_index = get_beacon_proposer_index(state)
|
||||||
proposer = addr state.validator_registry[proposer_index]
|
proposer = addr state.validator_registry[proposer_index]
|
||||||
|
|
||||||
if skipValidation notin flags:
|
if skipValidation notin flags:
|
||||||
@ -849,7 +849,7 @@ func compute_normal_justification_and_finalization_deltas(state: BeaconState):
|
|||||||
# Proposer bonus
|
# Proposer bonus
|
||||||
if index in previous_epoch_attestation_indices:
|
if index in previous_epoch_attestation_indices:
|
||||||
let proposer_index =
|
let proposer_index =
|
||||||
get_beacon_proposer_index(state, inclusion_slot[index])
|
get_beacon_proposer_index(state)
|
||||||
deltas[0][proposer_index] +=
|
deltas[0][proposer_index] +=
|
||||||
get_base_reward(state, index) div PROPOSER_REWARD_QUOTIENT
|
get_base_reward(state, index) div PROPOSER_REWARD_QUOTIENT
|
||||||
deltas
|
deltas
|
||||||
|
@ -39,7 +39,8 @@ cli do (totalValidators: int = 125000,
|
|||||||
data: DepositData(
|
data: DepositData(
|
||||||
amount: MAX_EFFECTIVE_BALANCE,
|
amount: MAX_EFFECTIVE_BALANCE,
|
||||||
pubkey: pubKey,
|
pubkey: pubKey,
|
||||||
withdrawal_credentials: withdrawalCredentials))
|
withdrawal_credentials: withdrawalCredentials),
|
||||||
|
index: i.uint64)
|
||||||
|
|
||||||
deposit.data.signature =
|
deposit.data.signature =
|
||||||
bls_sign(privkey, signing_root(deposit.data).data,
|
bls_sign(privkey, signing_root(deposit.data).data,
|
||||||
|
@ -63,7 +63,7 @@ func getNextBeaconProposerIndex*(state: BeaconState): ValidatorIndex =
|
|||||||
# see get_shard_committees_index
|
# see get_shard_committees_index
|
||||||
var next_state = state
|
var next_state = state
|
||||||
next_state.slot += 1
|
next_state.slot += 1
|
||||||
get_beacon_proposer_index(next_state, next_state.slot)
|
get_beacon_proposer_index(next_state)
|
||||||
|
|
||||||
proc addBlock*(
|
proc addBlock*(
|
||||||
state: var BeaconState, previous_block_root: Eth2Digest,
|
state: var BeaconState, previous_block_root: Eth2Digest,
|
||||||
@ -74,7 +74,7 @@ proc addBlock*(
|
|||||||
# but avoids some slow block copies
|
# but avoids some slow block copies
|
||||||
|
|
||||||
state.slot += 1
|
state.slot += 1
|
||||||
let proposer_index = get_beacon_proposer_index(state, state.slot)
|
let proposer_index = get_beacon_proposer_index(state)
|
||||||
state.slot -= 1
|
state.slot -= 1
|
||||||
|
|
||||||
# Ferret out remaining GENESIS_EPOCH == 0 assumptions in test code
|
# Ferret out remaining GENESIS_EPOCH == 0 assumptions in test code
|
||||||
|
Loading…
x
Reference in New Issue
Block a user