render get_beacon_proposer_index(...) return value an option and remove overly aggressive assertion formerly causing crashes when missing validators (#617)
* render get_beacon_proposer_index(...) return value an option and remove overly aggressive assertion formerly causing crashes when missing validators * follow addBlock(...) after refactoring * [skip ci] fix typo
This commit is contained in:
parent
6b56e19572
commit
c762c0232d
|
@ -645,9 +645,12 @@ proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
|
|||
# revisit this - we should be able to advance behind
|
||||
var cache = get_empty_per_epoch_cache()
|
||||
node.blockPool.withState(node.stateCache, BlockSlot(blck: head, slot: slot)):
|
||||
let
|
||||
proposerIdx = get_beacon_proposer_index(state, cache)
|
||||
validator = node.getAttachedValidator(state, proposerIdx)
|
||||
let proposerIdx = get_beacon_proposer_index(state, cache)
|
||||
if proposerIdx.isNone:
|
||||
debug "Missing proposer index"
|
||||
return head
|
||||
|
||||
let validator = node.getAttachedValidator(state, proposerIdx.get)
|
||||
|
||||
if validator != nil:
|
||||
return await proposeBlock(node, validator, head, slot)
|
||||
|
@ -655,7 +658,7 @@ proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
|
|||
trace "Expecting block proposal",
|
||||
headRoot = shortLog(head.root),
|
||||
slot = shortLog(slot),
|
||||
proposer = shortLog(state.validators[proposerIdx].pubKey),
|
||||
proposer = shortLog(state.validators[proposerIdx.get].pubKey),
|
||||
cat = "consensus",
|
||||
pcs = "wait_for_proposal"
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
tables, algorithm, math, sequtils,
|
||||
tables, algorithm, math, sequtils, options,
|
||||
json_serialization/std/sets, chronicles, stew/bitseqs,
|
||||
../extras, ../ssz,
|
||||
./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
||||
|
@ -171,14 +171,19 @@ proc slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
|
|||
decrease_balance(state, slashed_index,
|
||||
validator.effective_balance div MIN_SLASHING_PENALTY_QUOTIENT)
|
||||
|
||||
# The rest doesn't make sense without there being any proposer index, so skip
|
||||
let proposer_index = get_beacon_proposer_index(state, stateCache)
|
||||
if proposer_index.isNone:
|
||||
debug "No beacon proposer index and probably no active validators"
|
||||
return
|
||||
|
||||
let
|
||||
proposer_index = get_beacon_proposer_index(state, stateCache)
|
||||
# Spec has whistleblower_index as optional param, but it's never used.
|
||||
whistleblower_index = proposer_index
|
||||
whistleblower_index = proposer_index.get
|
||||
whistleblowing_reward =
|
||||
(validator.effective_balance div WHISTLEBLOWER_REWARD_QUOTIENT).Gwei
|
||||
proposer_reward = whistleblowing_reward div PROPOSER_REWARD_QUOTIENT
|
||||
increase_balance(state, proposer_index, proposer_reward)
|
||||
increase_balance(state, proposer_index.get, proposer_reward)
|
||||
# TODO: evaluate if spec bug / underflow can be triggered
|
||||
doAssert(whistleblowing_reward >= proposer_reward, "Spec bug: underflow in slash_validator")
|
||||
increase_balance(
|
||||
|
@ -492,6 +497,12 @@ proc process_attestation*(
|
|||
# reused when looking for suitable blocks to include in attestations.
|
||||
# TODO don't log warnings when looking for attestations (return
|
||||
# Result[void, cstring] instead of logging in check_attestation?)
|
||||
|
||||
let proposer_index = get_beacon_proposer_index(state, stateCache)
|
||||
if proposer_index.isNone:
|
||||
debug "No beacon proposer index and probably no active validators"
|
||||
return false
|
||||
|
||||
if check_attestation(state, attestation, flags, stateCache):
|
||||
let
|
||||
attestation_slot = attestation.data.slot
|
||||
|
@ -499,7 +510,7 @@ proc process_attestation*(
|
|||
data: attestation.data,
|
||||
aggregation_bits: attestation.aggregation_bits,
|
||||
inclusion_delay: state.slot - attestation_slot,
|
||||
proposer_index: get_beacon_proposer_index(state, stateCache).uint64,
|
||||
proposer_index: proposer_index.get.uint64,
|
||||
)
|
||||
|
||||
if attestation.data.target.epoch == get_current_epoch(state):
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
# improvements to be made - other than that, keep things similar to spec for
|
||||
# now.
|
||||
|
||||
import # TODO - cleanup imports
|
||||
algorithm, collections/sets, chronicles, sequtils, sets, tables,
|
||||
import
|
||||
algorithm, collections/sets, chronicles, options, sequtils, sets, tables,
|
||||
../extras, ../ssz, metrics,
|
||||
beaconstate, crypto, datatypes, digest, helpers, validator
|
||||
|
||||
|
@ -76,10 +76,13 @@ proc process_block_header*(
|
|||
signature: BlsValue[Signature](kind: OpaqueBlob)
|
||||
)
|
||||
|
||||
|
||||
# Verify proposer is not slashed
|
||||
let proposer =
|
||||
state.validators[get_beacon_proposer_index(state, stateCache)]
|
||||
let proposer_index = get_beacon_proposer_index(state, stateCache)
|
||||
if proposer_index.isNone:
|
||||
debug "Block header: proposer missing"
|
||||
return false
|
||||
|
||||
let proposer = state.validators[proposer_index.get]
|
||||
if proposer.slashed:
|
||||
notice "Block header: proposer slashed"
|
||||
return false
|
||||
|
@ -105,7 +108,12 @@ proc process_randao(
|
|||
let
|
||||
epoch = state.get_current_epoch()
|
||||
proposer_index = get_beacon_proposer_index(state, stateCache)
|
||||
proposer = addr state.validators[proposer_index]
|
||||
|
||||
if proposer_index.isNone:
|
||||
debug "Proposer index missing, probably along with any active validators"
|
||||
return false
|
||||
|
||||
let proposer = addr state.validators[proposer_index.get]
|
||||
|
||||
# Verify that the provided randao value is valid
|
||||
if skipValidation notin flags:
|
||||
|
|
|
@ -148,11 +148,12 @@ func get_empty_per_epoch_cache*(): StateCache =
|
|||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#compute_proposer_index
|
||||
func compute_proposer_index(state: BeaconState, indices: seq[ValidatorIndex],
|
||||
seed: Eth2Digest, stateCache: var StateCache): ValidatorIndex =
|
||||
seed: Eth2Digest, stateCache: var StateCache): Option[ValidatorIndex] =
|
||||
# Return from ``indices`` a random index sampled by effective balance.
|
||||
const MAX_RANDOM_BYTE = 255
|
||||
|
||||
doAssert len(indices) > 0
|
||||
if len(indices) == 0:
|
||||
return none(ValidatorIndex)
|
||||
|
||||
# TODO fixme; should only be run once per slot and cached
|
||||
# There's exactly one beacon proposer per slot.
|
||||
|
@ -175,12 +176,12 @@ func compute_proposer_index(state: BeaconState, indices: seq[ValidatorIndex],
|
|||
state.validators[candidate_index].effective_balance
|
||||
if effective_balance * MAX_RANDOM_BYTE >=
|
||||
MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
return candidate_index
|
||||
return some(candidate_index)
|
||||
i += 1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#get_beacon_proposer_index
|
||||
func get_beacon_proposer_index*(state: BeaconState, stateCache: var StateCache):
|
||||
ValidatorIndex =
|
||||
Option[ValidatorIndex] =
|
||||
# Return the beacon proposer index at the current slot.
|
||||
let epoch = get_current_epoch(state)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
options,
|
||||
# Specs
|
||||
../../beacon_chain/spec/[datatypes, crypto, helpers, validator],
|
||||
# Internals
|
||||
|
@ -60,20 +61,21 @@ proc signMockBlock*(
|
|||
blck: var BeaconBlock
|
||||
) =
|
||||
|
||||
var proposer_index: ValidatorIndex
|
||||
var emptyCache = get_empty_per_epoch_cache()
|
||||
if blck.slot == state.slot:
|
||||
proposer_index = get_beacon_proposer_index(state, emptyCache)
|
||||
else:
|
||||
# Stub to get proposer index of future slot
|
||||
# Note: this relies on ``let`` deep-copying the state
|
||||
# i.e. BeaconState should have value semantics
|
||||
# and not contain ref objects or pointers
|
||||
var stubState = state
|
||||
process_slots(stub_state, blck.slot)
|
||||
proposer_index = get_beacon_proposer_index(stub_state, emptyCache)
|
||||
let proposer_index =
|
||||
if blck.slot == state.slot:
|
||||
get_beacon_proposer_index(state, emptyCache)
|
||||
else:
|
||||
# Stub to get proposer index of future slot
|
||||
# Note: this relies on ``let`` deep-copying the state
|
||||
# i.e. BeaconState should have value semantics
|
||||
# and not contain ref objects or pointers
|
||||
var stubState = state
|
||||
process_slots(stub_state, blck.slot)
|
||||
get_beacon_proposer_index(stub_state, emptyCache)
|
||||
|
||||
signMockBlockImpl(state, blck, proposer_index)
|
||||
# In tests, just let this throw if appropriate
|
||||
signMockBlockImpl(state, blck, proposer_index.get)
|
||||
|
||||
proc mockBlock*(
|
||||
state: BeaconState,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
stew/endians2,
|
||||
options, stew/endians2,
|
||||
chronicles, eth/trie/[db],
|
||||
../beacon_chain/[beacon_chain_db, block_pool, extras, ssz, state_transition,
|
||||
validator_pool],
|
||||
|
@ -87,7 +87,8 @@ proc addBlock*(
|
|||
|
||||
let
|
||||
# Index from the new state, but registry from the old state.. hmm...
|
||||
proposer = state.validators[proposer_index]
|
||||
# In tests, let this throw
|
||||
proposer = state.validators[proposer_index.get]
|
||||
privKey = hackPrivKey(proposer)
|
||||
|
||||
# TODO ugly hack; API needs rethinking
|
||||
|
|
Loading…
Reference in New Issue