mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-11 14:54:12 +00:00
refactor exit pool and gossipsub-subscribe to exit pool message types (#1733)
* refactor exit pool and gossipsub-subscribe to all exit pool message types * remove unused loop counter
This commit is contained in:
parent
6398a43cc1
commit
6cf7e837ce
@ -70,6 +70,13 @@ OK: 3/3 Fail: 0/3 Skip: 0/3
|
||||
+ parent sanity [Preset: mainnet] OK
|
||||
```
|
||||
OK: 2/2 Fail: 0/2 Skip: 0/2
|
||||
## Exit pool testing suite
|
||||
```diff
|
||||
+ addExitMessage/getAttesterSlashingMessage OK
|
||||
+ addExitMessage/getProposerSlashingMessage OK
|
||||
+ addExitMessage/getVoluntaryExitMessage OK
|
||||
```
|
||||
OK: 3/3 Fail: 0/3 Skip: 0/3
|
||||
## Fork Choice + Finality [Preset: mainnet]
|
||||
```diff
|
||||
+ fork_choice - testing finality #01 OK
|
||||
@ -179,11 +186,12 @@ OK: 52/60 Fail: 0/60 Skip: 8/60
|
||||
+ Peer lifetime test OK
|
||||
+ Safe/Clear test OK
|
||||
+ Score check test OK
|
||||
+ Space tests OK
|
||||
+ addPeer() test OK
|
||||
+ addPeerNoWait() test OK
|
||||
+ deletePeer() test OK
|
||||
```
|
||||
OK: 11/11 Fail: 0/11 Skip: 0/11
|
||||
OK: 12/12 Fail: 0/12 Skip: 0/12
|
||||
## SSZ dynamic navigator
|
||||
```diff
|
||||
+ navigating fields OK
|
||||
@ -271,4 +279,4 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
|
||||
OK: 1/1 Fail: 0/1 Skip: 0/1
|
||||
|
||||
---TOTAL---
|
||||
OK: 145/153 Fail: 0/153 Skip: 8/153
|
||||
OK: 149/157 Fail: 0/157 Skip: 8/157
|
||||
|
@ -415,6 +415,8 @@ proc addMessageHandlers(node: BeaconNode): Future[void] =
|
||||
# As a side-effect, this gets the attestation subnets too.
|
||||
node.network.subscribe(node.topicBeaconBlocks),
|
||||
node.network.subscribe(getAttesterSlashingsTopic(node.forkDigest)),
|
||||
node.network.subscribe(getProposerSlashingsTopic(node.forkDigest)),
|
||||
node.network.subscribe(getVoluntaryExitsTopic(node.forkDigest)),
|
||||
|
||||
node.getAttestationHandlers()
|
||||
)
|
||||
@ -838,8 +840,8 @@ proc installMessageValidators(node: BeaconNode) =
|
||||
|
||||
node.network.addValidator(
|
||||
getVoluntaryExitsTopic(node.forkDigest),
|
||||
proc (voluntaryExit: VoluntaryExit): ValidationResult =
|
||||
node.processor[].voluntaryExitValidator(voluntaryExit))
|
||||
proc (signedVoluntaryExit: SignedVoluntaryExit): ValidationResult =
|
||||
node.processor[].voluntaryExitValidator(signedVoluntaryExit))
|
||||
|
||||
proc stop*(node: BeaconNode) =
|
||||
status = BeaconNodeStatus.Stopping
|
||||
|
@ -1,7 +1,7 @@
|
||||
{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
std/[deques, tables, streams],
|
||||
std/[deques, sets, streams, tables],
|
||||
stew/endians2,
|
||||
spec/[datatypes, digest, crypto],
|
||||
block_pools/block_pools_types,
|
||||
@ -79,9 +79,18 @@ type
|
||||
proposer_slashings*: Deque[ProposerSlashing] ## \
|
||||
## Not a function of chain DAG branch; just used as a FIFO queue for blocks
|
||||
|
||||
voluntary_exits*: Deque[VoluntaryExit] ## \
|
||||
voluntary_exits*: Deque[SignedVoluntaryExit] ## \
|
||||
## Not a function of chain DAG branch; just used as a FIFO queue for blocks
|
||||
|
||||
prior_seen_attester_slashed_indices*: HashSet[ValidatorIndex] ##\
|
||||
## Records attester-slashed indices seen.
|
||||
|
||||
prior_seen_proposer_slashed_indices*: HashSet[ValidatorIndex] ##\
|
||||
## Records proposer-slashed indices seen.
|
||||
|
||||
prior_seen_voluntary_exit_indices*: HashSet[ValidatorIndex] ##\
|
||||
## Records voluntary exit indices seen.
|
||||
|
||||
chainDag*: ChainDAGRef
|
||||
quarantine*: QuarantineRef
|
||||
|
||||
|
@ -398,11 +398,12 @@ proc proposerSlashingValidator*(
|
||||
EVRESULT_ACCEPT
|
||||
|
||||
proc voluntaryExitValidator*(
|
||||
self: var Eth2Processor, voluntaryExit: VoluntaryExit): ValidationResult =
|
||||
self: var Eth2Processor, signedVoluntaryExit: SignedVoluntaryExit):
|
||||
ValidationResult =
|
||||
logScope:
|
||||
voluntaryExit = shortLog(voluntaryExit)
|
||||
signedVoluntaryExit = shortLog(signedVoluntaryExit)
|
||||
|
||||
let v = self.exitPool[].validateVoluntaryExit(voluntaryExit)
|
||||
let v = self.exitPool[].validateVoluntaryExit(signedVoluntaryExit)
|
||||
if v.isErr:
|
||||
debug "Dropping voluntary exit", err = v.error
|
||||
return v.error[0]
|
||||
|
@ -13,8 +13,8 @@ import
|
||||
# Status libraries
|
||||
chronicles, json_serialization/std/sets as jsonSets,
|
||||
# Internal
|
||||
./spec/[datatypes, crypto, state_transition_block],
|
||||
./block_pools/[chain_dag, clearance, quarantine, spec_cache],
|
||||
./spec/[crypto, datatypes, helpers, state_transition_block],
|
||||
./block_pools/[chain_dag, clearance, quarantine],
|
||||
./beacon_node_types
|
||||
|
||||
export beacon_node_types, sets
|
||||
@ -30,12 +30,12 @@ proc init*(
|
||||
proposer_slashings:
|
||||
initDeque[ProposerSlashing](initialSize = MAX_PROPOSER_SLASHINGS.int),
|
||||
voluntary_exits:
|
||||
initDeque[VoluntaryExit](initialSize = MAX_VOLUNTARY_EXITS.int),
|
||||
initDeque[SignedVoluntaryExit](initialSize = MAX_VOLUNTARY_EXITS.int),
|
||||
chainDag: chainDag,
|
||||
quarantine: quarantine
|
||||
)
|
||||
|
||||
func addExitMessage(subpool: var auto, exitMessage, bound: auto) =
|
||||
func addExitMessage*(subpool: var auto, exitMessage, bound: auto) =
|
||||
# Prefer newer to older exit message
|
||||
while subpool.lenu64 >= bound:
|
||||
discard subpool.popFirst()
|
||||
@ -64,120 +64,111 @@ func getProposerSlashingsForBlock*(pool: var ExitPool):
|
||||
pool.proposer_slashings, MAX_PROPOSER_SLASHINGS)
|
||||
|
||||
func getVoluntaryExitsForBlock*(pool: var ExitPool):
|
||||
seq[VoluntaryExit] =
|
||||
seq[SignedVoluntaryExit] =
|
||||
## Retrieve voluntary exits that may be added to a new block
|
||||
getExitMessagesForBlock[VoluntaryExit](
|
||||
getExitMessagesForBlock[SignedVoluntaryExit](
|
||||
pool.voluntary_exits, MAX_VOLUNTARY_EXITS)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/p2p-interface.md#attester_slashing
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/p2p-interface.md#attester_slashing
|
||||
proc validateAttesterSlashing*(
|
||||
pool: var ExitPool, attesterSlashing: AttesterSlashing):
|
||||
pool: var ExitPool, attester_slashing: AttesterSlashing):
|
||||
Result[bool, (ValidationResult, cstring)] =
|
||||
# [IGNORE] At least one index in the intersection of the attesting indices of
|
||||
# each attestation has not yet been seen in any prior attester_slashing (i.e.
|
||||
# attester_slashed_indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices),
|
||||
# verify if any(attester_slashed_indices.difference(prior_seen_attester_slashed_indices))).
|
||||
#
|
||||
# This is what the spec states, but even when a validators was slashed using
|
||||
# proposer slashing it's still pointless relaying an attester slashing for a
|
||||
# validator; process_attester_slashing() will note not that validator as not
|
||||
# slashable. Therefore, check whether it's slashed for any reason.
|
||||
# TODO check for upstream spec disposition on this
|
||||
let
|
||||
attestation_1 = attester_slashing.attestation_1
|
||||
attestation_2 = attester_slashing.attestation_2
|
||||
# TODO sequtils2 should be able to make this more reasonable, from asSeq on
|
||||
# down
|
||||
attesting_indices_1 =
|
||||
toHashSet(mapIt(attestation_1.attesting_indices.asSeq, it.ValidatorIndex))
|
||||
attesting_indices_2 =
|
||||
toHashSet(mapIt(attestation_1.attesting_indices.asSeq, it.ValidatorIndex))
|
||||
attester_slashed_indices = attesting_indices_1 * attesting_indices_2
|
||||
# TODO
|
||||
# TODO sequtils2 should be able to make this more reasonable, from asSeq on
|
||||
# down
|
||||
let attester_slashed_indices =
|
||||
toHashSet(mapIt(
|
||||
attester_slashing.attestation_1.attesting_indices.asSeq,
|
||||
it.ValidatorIndex)) *
|
||||
toHashSet(mapIt(
|
||||
attester_slashing.attestation_2.attesting_indices.asSeq,
|
||||
it.ValidatorIndex))
|
||||
|
||||
if not disjoint(
|
||||
attester_slashed_indices, pool.prior_seen_attester_slashed_indices):
|
||||
const err_str: cstring =
|
||||
"validateAttesterSlashing: attester-slashed index already attester-slashed"
|
||||
return err((EVRESULT_IGNORE, err_str))
|
||||
|
||||
# [REJECT] All of the conditions within process_attester_slashing pass
|
||||
# validation.
|
||||
# This is similar to process_attester_slashing, but both cut-down (it doesn't
|
||||
# have the loop over attesting indices) and using EpochRef caches, so there's
|
||||
# no real overlap in code terms with process_proposer_slashing().
|
||||
block:
|
||||
let tgtBlck_1 = pool.chainDag.getRef(attestation_1.data.target.root)
|
||||
if tgtBlck_1.isNil:
|
||||
pool.quarantine.addMissing(attestation_1.data.target.root)
|
||||
const err_str: cstring = "Attestation 1 target block unknown"
|
||||
return err((EVRESULT_IGNORE, err_str))
|
||||
|
||||
let tgtBlck_2 = pool.chainDag.getRef(attestation_2.data.target.root)
|
||||
if tgtBlck_2.isNil:
|
||||
pool.quarantine.addMissing(attestation_2.data.target.root)
|
||||
const err_str: cstring = "Attestation 2 target block unknown"
|
||||
return err((EVRESULT_IGNORE, err_str))
|
||||
|
||||
let
|
||||
epochRef_1 = pool.chainDag.getEpochRef(
|
||||
tgtBlck_1, attestation_1.data.target.epoch)
|
||||
epochRef_2 = pool.chainDag.getEpochRef(
|
||||
tgtBlck_2, attestation_2.data.target.epoch)
|
||||
fork = pool.chainDag.headState.data.data.fork
|
||||
genesis_validators_root =
|
||||
pool.chainDag.headState.data.data.genesis_validators_root
|
||||
|
||||
if not is_slashable_attestation_data(
|
||||
attestation_1.data, attestation_2.data):
|
||||
const err_str: cstring = "Attestation data not slashable"
|
||||
return err((EVRESULT_REJECT, err_str))
|
||||
block:
|
||||
let v = is_valid_indexed_attestation(
|
||||
fork, genesis_validators_root, epochRef_1, attestation_1, {})
|
||||
if v.isErr():
|
||||
return err((EVRESULT_REJECT, v.error))
|
||||
block:
|
||||
let v = is_valid_indexed_attestation(
|
||||
fork, genesis_validators_root, epochRef_2, attestation_2, {})
|
||||
if v.isErr():
|
||||
return err((EVRESULT_REJECT, v.error))
|
||||
var cache =
|
||||
getStateCache(pool.chainDag.head,
|
||||
pool.chainDag.headState.data.data.slot.compute_epoch_at_slot)
|
||||
let attester_slashing_validity =
|
||||
check_attester_slashing(
|
||||
pool.chainDag.headState.data.data, attester_slashing, {}, cache)
|
||||
if attester_slashing_validity.isErr:
|
||||
return err((EVRESULT_REJECT, attester_slashing_validity.error))
|
||||
|
||||
pool.prior_seen_attester_slashed_indices.incl attester_slashed_indices
|
||||
pool.attester_slashings.addExitMessage(
|
||||
attesterSlashing, MAX_ATTESTER_SLASHINGS)
|
||||
attester_slashing, MAX_ATTESTER_SLASHINGS)
|
||||
|
||||
ok(true)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/p2p-interface.md#proposer_slashing
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/p2p-interface.md#proposer_slashing
|
||||
proc validateProposerSlashing*(
|
||||
pool: var ExitPool, proposerSlashing: ProposerSlashing):
|
||||
pool: var ExitPool, proposer_slashing: ProposerSlashing):
|
||||
Result[bool, (ValidationResult, cstring)] =
|
||||
# [IGNORE] The proposer slashing is the first valid proposer slashing
|
||||
# received for the proposer with index
|
||||
# proposer_slashing.signed_header_1.message.proposer_index.
|
||||
#
|
||||
# This is what the spec states, but even when the validator was slashed from
|
||||
# attester slashing, it's still pointless to relay a proposer slashing for a
|
||||
# validator; process_proposer_slashing() will mark not that validator as not
|
||||
# slashable. Therefore, check whether it's slashed for any reason.
|
||||
# TODO check for upstream spec disposition on this
|
||||
if proposer_slashing.signed_header_1.message.proposer_index.ValidatorIndex in
|
||||
pool.prior_seen_proposer_slashed_indices:
|
||||
const err_str: cstring =
|
||||
"validateProposerSlashing: proposer-slashed index already proposer-slashed"
|
||||
return err((EVRESULT_IGNORE, err_str))
|
||||
|
||||
# [REJECT] All of the conditions within process_proposer_slashing pass validation.
|
||||
var cache =
|
||||
getStateCache(pool.chainDag.head,
|
||||
pool.chainDag.headState.data.data.slot.compute_epoch_at_slot)
|
||||
let proposer_slashing_validity =
|
||||
check_proposer_slashing(
|
||||
pool.chainDag.headState.data.data, proposer_slashing, {}, cache)
|
||||
if proposer_slashing_validity.isErr:
|
||||
return err((EVRESULT_REJECT, proposer_slashing_validity.error))
|
||||
|
||||
# TODO not called yet, so vacuousness is fine
|
||||
|
||||
pool.prior_seen_proposer_slashed_indices.incl(
|
||||
proposer_slashing.signed_header_1.message.proposer_index.ValidatorIndex)
|
||||
pool.proposer_slashings.addExitMessage(
|
||||
proposerSlashing, MAX_PROPOSER_SLASHINGS)
|
||||
proposer_slashing, MAX_PROPOSER_SLASHINGS)
|
||||
|
||||
ok(true)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/p2p-interface.md#voluntary_exit
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/p2p-interface.md#voluntary_exit
|
||||
proc validateVoluntaryExit*(
|
||||
pool: var ExitPool, voluntaryExit: VoluntaryExit):
|
||||
pool: var ExitPool, signed_voluntary_exit: SignedVoluntaryExit):
|
||||
Result[bool, (ValidationResult, cstring)] =
|
||||
# [IGNORE] The voluntary exit is the first valid voluntary exit received for
|
||||
# the validator with index signed_voluntary_exit.message.validator_index.
|
||||
if signed_voluntary_exit.message.validator_index >=
|
||||
pool.chainDag.headState.data.data.validators.lenu64:
|
||||
const err_str: cstring = "validateVoluntaryExit: validator index too high"
|
||||
return err((EVRESULT_IGNORE, err_str))
|
||||
if signed_voluntary_exit.message.validator_index.ValidatorIndex in
|
||||
pool.prior_seen_voluntary_exit_indices:
|
||||
const err_str: cstring = "validateVoluntaryExit: validator index already voluntarily exited"
|
||||
return err((EVRESULT_IGNORE, err_str))
|
||||
|
||||
# [REJECT] All of the conditions within process_voluntary_exit pass
|
||||
# validation.
|
||||
var cache =
|
||||
getStateCache(pool.chainDag.head,
|
||||
pool.chainDag.headState.data.data.slot.compute_epoch_at_slot)
|
||||
let voluntary_exit_validity =
|
||||
check_voluntary_exit(
|
||||
pool.chainDag.headState.data.data, signed_voluntary_exit, {}, cache)
|
||||
if voluntary_exit_validity.isErr:
|
||||
return err((EVRESULT_REJECT, voluntary_exit_validity.error))
|
||||
|
||||
# TODO not called yet, so vacuousness is fine
|
||||
|
||||
pool.prior_seen_voluntary_exit_indices.incl(
|
||||
signed_voluntary_exit.message.validator_index.ValidatorIndex)
|
||||
pool.voluntary_exits.addExitMessage(
|
||||
voluntaryExit, MAX_VOLUNTARY_EXITS)
|
||||
signed_voluntary_exit, MAX_VOLUNTARY_EXITS)
|
||||
|
||||
ok(true)
|
||||
|
@ -739,6 +739,12 @@ func shortLog*(v: VoluntaryExit): auto =
|
||||
validator_index: v.validator_index
|
||||
)
|
||||
|
||||
func shortLog*(v: SignedVoluntaryExit): auto =
|
||||
(
|
||||
message: shortLog(v.message),
|
||||
signature: shortLog(v.signature)
|
||||
)
|
||||
|
||||
chronicles.formatIt Slot: it.shortLog
|
||||
chronicles.formatIt Epoch: it.shortLog
|
||||
chronicles.formatIt BeaconBlock: it.shortLog
|
||||
|
@ -134,9 +134,9 @@ func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
|
||||
(epoch < validator.withdrawable_epoch)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#proposer-slashings
|
||||
proc process_proposer_slashing*(
|
||||
proc check_proposer_slashing*(
|
||||
state: var BeaconState, proposer_slashing: ProposerSlashing,
|
||||
flags: UpdateFlags, stateCache: var StateCache):
|
||||
flags: UpdateFlags, cache: var StateCache):
|
||||
Result[void, cstring] {.nbench.} =
|
||||
|
||||
let
|
||||
@ -145,36 +145,46 @@ proc process_proposer_slashing*(
|
||||
|
||||
# Not from spec
|
||||
if header_1.proposer_index >= state.validators.lenu64:
|
||||
return err("process_proposer_slashing: invalid proposer index")
|
||||
return err("check_proposer_slashing: invalid proposer index")
|
||||
|
||||
# Verify header slots match
|
||||
if not (header_1.slot == header_2.slot):
|
||||
return err("process_proposer_slashing: slot mismatch")
|
||||
return err("check_proposer_slashing: slot mismatch")
|
||||
|
||||
# Verify header proposer indices match
|
||||
if not (header_1.proposer_index == header_2.proposer_index):
|
||||
return err("process_proposer_slashing: proposer indices mismatch")
|
||||
return err("check_proposer_slashing: proposer indices mismatch")
|
||||
|
||||
# Verify the headers are different
|
||||
if not (header_1 != header_2):
|
||||
return err("process_proposer_slashing: headers not different")
|
||||
return err("check_proposer_slashing: headers not different")
|
||||
|
||||
# Verify the proposer is slashable
|
||||
let proposer = state.validators[header_1.proposer_index]
|
||||
if not is_slashable_validator(proposer, get_current_epoch(state)):
|
||||
return err("process_proposer_slashing: slashed proposer")
|
||||
return err("check_proposer_slashing: slashed proposer")
|
||||
|
||||
# Verify signatures
|
||||
if skipBlsValidation notin flags:
|
||||
for i, signed_header in [proposer_slashing.signed_header_1,
|
||||
for signed_header in [proposer_slashing.signed_header_1,
|
||||
proposer_slashing.signed_header_2]:
|
||||
if not verify_block_signature(
|
||||
state.fork, state.genesis_validators_root, signed_header.message.slot,
|
||||
signed_header.message, proposer.pubkey, signed_header.signature):
|
||||
return err("process_proposer_slashing: invalid signature")
|
||||
return err("check_proposer_slashing: invalid signature")
|
||||
|
||||
slash_validator(state, header_1.proposer_index.ValidatorIndex, stateCache)
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#proposer-slashings
|
||||
proc process_proposer_slashing*(
|
||||
state: var BeaconState, proposer_slashing: ProposerSlashing,
|
||||
flags: UpdateFlags, cache: var StateCache):
|
||||
Result[void, cstring] {.nbench.} =
|
||||
? check_proposer_slashing(state, proposer_slashing, flags, cache)
|
||||
slash_validator(
|
||||
state,
|
||||
proposer_slashing.signed_header_1.message.proposer_index.ValidatorIndex,
|
||||
cache)
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#is_slashable_attestation_data
|
||||
@ -190,12 +200,12 @@ func is_slashable_attestation_data*(
|
||||
data_2.target.epoch < data_1.target.epoch)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#attester-slashings
|
||||
proc process_attester_slashing*(
|
||||
proc check_attester_slashing*(
|
||||
state: var BeaconState,
|
||||
attester_slashing: AttesterSlashing,
|
||||
flags: UpdateFlags,
|
||||
stateCache: var StateCache
|
||||
): Result[void, cstring] {.nbench.}=
|
||||
cache: var StateCache
|
||||
): Result[seq[ValidatorIndex], cstring] {.nbench.} =
|
||||
let
|
||||
attestation_1 = attester_slashing.attestation_1
|
||||
attestation_2 = attester_slashing.attestation_2
|
||||
@ -210,21 +220,39 @@ proc process_attester_slashing*(
|
||||
if not is_valid_indexed_attestation(state, attestation_2, flags).isOk():
|
||||
return err("Attester slashing: invalid attestation 2")
|
||||
|
||||
var slashed_any = false
|
||||
var slashed_indices: seq[ValidatorIndex]
|
||||
|
||||
for index in sorted(toSeq(intersection(
|
||||
toHashSet(attestation_1.attesting_indices.asSeq),
|
||||
toHashSet(attestation_2.attesting_indices.asSeq)).items), system.cmp):
|
||||
if is_slashable_validator(
|
||||
state.validators[index], get_current_epoch(state)):
|
||||
slash_validator(state, index.ValidatorIndex, stateCache)
|
||||
slashed_any = true
|
||||
if not slashed_any:
|
||||
slashed_indices.add index.ValidatorIndex
|
||||
if slashed_indices.len == 0:
|
||||
return err("Attester slashing: Trying to slash participant(s) twice")
|
||||
|
||||
ok slashed_indices
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#attester-slashings
|
||||
proc process_attester_slashing*(
|
||||
state: var BeaconState,
|
||||
attester_slashing: AttesterSlashing,
|
||||
flags: UpdateFlags,
|
||||
cache: var StateCache
|
||||
): Result[void, cstring] {.nbench.} =
|
||||
let attester_slashing_validity =
|
||||
check_attester_slashing(state, attester_slashing, flags, cache)
|
||||
|
||||
if attester_slashing_validity.isErr:
|
||||
return err(attester_slashing_validity.error)
|
||||
|
||||
for index in attester_slashing_validity.value:
|
||||
slash_validator(state, index, cache)
|
||||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#voluntary-exits
|
||||
proc process_voluntary_exit*(
|
||||
proc check_voluntary_exit*(
|
||||
state: var BeaconState,
|
||||
signed_voluntary_exit: SignedVoluntaryExit,
|
||||
flags: UpdateFlags,
|
||||
@ -264,7 +292,7 @@ proc process_voluntary_exit*(
|
||||
return err("Exit: invalid signature")
|
||||
|
||||
# Initiate exit
|
||||
debug "Exit: processing voluntary exit (validator_leaving)",
|
||||
debug "Exit: checking voluntary exit (validator_leaving)",
|
||||
index = voluntary_exit.validator_index,
|
||||
num_validators = state.validators.len,
|
||||
epoch = voluntary_exit.epoch,
|
||||
@ -273,11 +301,20 @@ proc process_voluntary_exit*(
|
||||
validator_withdrawable_epoch = validator.withdrawable_epoch,
|
||||
validator_exit_epoch = validator.exit_epoch,
|
||||
validator_effective_balance = validator.effective_balance
|
||||
initiate_validator_exit(
|
||||
state, voluntary_exit.validator_index.ValidatorIndex, cache)
|
||||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/beacon-chain.md#voluntary-exits
|
||||
proc process_voluntary_exit*(
|
||||
state: var BeaconState,
|
||||
signed_voluntary_exit: SignedVoluntaryExit,
|
||||
flags: UpdateFlags,
|
||||
cache: var StateCache): Result[void, cstring] {.nbench.} =
|
||||
? check_voluntary_exit(state, signed_voluntary_exit, flags, cache)
|
||||
initiate_validator_exit(
|
||||
state, signed_voluntary_exit.message.validator_index.ValidatorIndex, cache)
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#operations
|
||||
proc process_operations(preset: RuntimePreset,
|
||||
state: var BeaconState,
|
||||
|
@ -26,6 +26,7 @@ import # Unit test
|
||||
./test_state_transition,
|
||||
./test_sync_protocol,
|
||||
./test_zero_signature,
|
||||
./test_exit_pool,
|
||||
./test_peer_pool,
|
||||
./test_sync_manager,
|
||||
./test_honest_validator,
|
||||
|
52
tests/test_exit_pool.nim
Normal file
52
tests/test_exit_pool.nim
Normal file
@ -0,0 +1,52 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2020 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
import std/unittest
|
||||
import chronicles, chronos, testutil
|
||||
import ../beacon_chain/spec/[datatypes, presets]
|
||||
import ../beacon_chain/exit_pool
|
||||
import ../beacon_chain/block_pools/chain_dag
|
||||
|
||||
proc getExitPool(): auto =
|
||||
let chainDag =
|
||||
init(ChainDAGRef, defaultRuntimePreset, makeTestDB(SLOTS_PER_EPOCH * 3))
|
||||
newClone(ExitPool.init(chainDag, QuarantineRef()))
|
||||
|
||||
suiteReport "Exit pool testing suite":
|
||||
setup:
|
||||
let pool = getExitPool()
|
||||
timedTest "addExitMessage/getProposerSlashingMessage":
|
||||
for i in 0'u64 .. MAX_PROPOSER_SLASHINGS + 5:
|
||||
for j in 0'u64 .. i:
|
||||
pool.proposer_slashings.addExitMessage(
|
||||
ProposerSlashing(), MAX_PROPOSER_SLASHINGS)
|
||||
check:
|
||||
pool[].getProposerSlashingsForBlock().lenu64 ==
|
||||
min(i + 1, MAX_PROPOSER_SLASHINGS)
|
||||
pool[].getProposerSlashingsForBlock().len == 0
|
||||
|
||||
timedTest "addExitMessage/getAttesterSlashingMessage":
|
||||
for i in 0'u64 .. MAX_ATTESTER_SLASHINGS + 5:
|
||||
for j in 0'u64 .. i:
|
||||
pool.attester_slashings.addExitMessage(
|
||||
AttesterSlashing(), MAX_ATTESTER_SLASHINGS)
|
||||
check:
|
||||
pool[].getAttesterSlashingsForBlock().lenu64 ==
|
||||
min(i + 1, MAX_ATTESTER_SLASHINGS)
|
||||
pool[].getAttesterSlashingsForBlock().len == 0
|
||||
|
||||
timedTest "addExitMessage/getVoluntaryExitMessage":
|
||||
for i in 0'u64 .. MAX_VOLUNTARY_EXITS + 5:
|
||||
for j in 0'u64 .. i:
|
||||
pool.voluntary_exits.addExitMessage(
|
||||
SignedVoluntaryExit(), MAX_VOLUNTARY_EXITS)
|
||||
check:
|
||||
pool[].getVoluntaryExitsForBlock().lenu64 ==
|
||||
min(i + 1, MAX_VOLUNTARY_EXITS)
|
||||
pool[].getProposerSlashingsForBlock().len == 0
|
Loading…
x
Reference in New Issue
Block a user