Skip to content

Commit

Permalink
add Electra attester slashing pool (#6579)
Browse files Browse the repository at this point in the history
  • Loading branch information
tersec committed Sep 24, 2024
1 parent 841904b commit d4e441e
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 43 deletions.
7 changes: 4 additions & 3 deletions AllTests-mainnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -1008,14 +1008,15 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
OK: 14/14 Fail: 0/14 Skip: 0/14
## Validator change pool testing suite
```diff
+ addValidatorChangeMessage/getAttesterSlashingMessage OK
+ addValidatorChangeMessage/getAttesterSlashingMessage (Electra) OK
+ addValidatorChangeMessage/getAttesterSlashingMessage (Phase 0) OK
+ addValidatorChangeMessage/getBlsToExecutionChange (post-capella) OK
+ addValidatorChangeMessage/getBlsToExecutionChange (pre-capella) OK
+ addValidatorChangeMessage/getProposerSlashingMessage OK
+ addValidatorChangeMessage/getVoluntaryExitMessage OK
+ pre-pre-fork voluntary exit OK
```
OK: 6/6 Fail: 0/6 Skip: 0/6
OK: 7/7 Fail: 0/7 Skip: 0/7
## Validator pool
```diff
+ Doppelganger for genesis validator OK
Expand Down Expand Up @@ -1125,4 +1126,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
OK: 9/9 Fail: 0/9 Skip: 0/9

---TOTAL---
OK: 762/767 Fail: 0/767 Skip: 5/767
OK: 763/768 Fail: 0/768 Skip: 5/768
57 changes: 45 additions & 12 deletions beacon_chain/consensus_object_pools/validator_change_pool.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,20 @@ type
proc(data: SignedBLSToExecutionChange) {.gcsafe, raises: [].}
OnProposerSlashingCallback =
proc(data: ProposerSlashing) {.gcsafe, raises: [].}
OnAttesterSlashingCallback =
OnPhase0AttesterSlashingCallback =
proc(data: phase0.AttesterSlashing) {.gcsafe, raises: [].}
OnElectraAttesterSlashingCallback =
proc(data: electra.AttesterSlashing) {.gcsafe, raises: [].}

ValidatorChangePool* = object
## The validator change pool tracks attester slashings, proposer slashings,
## voluntary exits, and BLS to execution changes that could be added to a
## proposed block.

attester_slashings*: Deque[phase0.AttesterSlashing] ## \
phase0_attester_slashings*: Deque[phase0.AttesterSlashing] ## \
## Not a function of chain DAG branch; just used as a FIFO queue for blocks

electra_attester_slashings*: Deque[electra.AttesterSlashing] ## \
## Not a function of chain DAG branch; just used as a FIFO queue for blocks

proposer_slashings*: Deque[ProposerSlashing] ## \
Expand All @@ -58,7 +63,8 @@ type
## Not a function of chain DAG branch; just used as a FIFO queue for blocks

prior_seen_attester_slashed_indices: HashSet[uint64] ## \
## Records attester-slashed indices seen.
## Records attester-slashed indices seen. Share these across attester
## slashing types.

prior_seen_proposer_slashed_indices: HashSet[uint64] ## \
## Records proposer-slashed indices seen.
Expand All @@ -74,20 +80,26 @@ type
onVoluntaryExitReceived*: OnVoluntaryExitCallback
onBLSToExecutionChangeReceived*: OnBLSToExecutionChangeCallback
onProposerSlashingReceived*: OnProposerSlashingCallback
onAttesterSlashingReceived*: OnAttesterSlashingCallback
onPhase0AttesterSlashingReceived*: OnPhase0AttesterSlashingCallback
onElectraAttesterSlashingReceived*: OnElectraAttesterSlashingCallback

func init*(T: type ValidatorChangePool, dag: ChainDAGRef,
attestationPool: ref AttestationPool = nil,
onVoluntaryExit: OnVoluntaryExitCallback = nil,
onBLSToExecutionChange: OnBLSToExecutionChangeCallback = nil,
onProposerSlashing: OnProposerSlashingCallback = nil,
onAttesterSlashing: OnAttesterSlashingCallback = nil): T =
onPhase0AttesterSlashing: OnPhase0AttesterSlashingCallback = nil,
onElectraAttesterSlashing: OnElectraAttesterSlashingCallback = nil):
T =
## Initialize an ValidatorChangePool from the dag `headState`
T(
# Allow filtering some validator change messages during block production
attester_slashings:
phase0_attester_slashings:
initDeque[phase0.AttesterSlashing](
initialSize = ATTESTER_SLASHINGS_BOUND.int),
electra_attester_slashings:
initDeque[electra.AttesterSlashing](
initialSize = ATTESTER_SLASHINGS_BOUND.int),
proposer_slashings:
initDeque[ProposerSlashing](initialSize = PROPOSER_SLASHINGS_BOUND.int),
voluntary_exits:
Expand All @@ -107,7 +119,8 @@ func init*(T: type ValidatorChangePool, dag: ChainDAGRef,
onVoluntaryExitReceived: onVoluntaryExit,
onBLSToExecutionChangeReceived: onBLSToExecutionChange,
onProposerSlashingReceived: onProposerSlashing,
onAttesterSlashingReceived: onAttesterSlashing)
onPhase0AttesterSlashingReceived: onPhase0AttesterSlashing,
onElectraAttesterSlashingReceived: onElectraAttesterSlashing)

func addValidatorChangeMessage(
subpool: var auto, seenpool: var auto, validatorChangeMessage: auto,
Expand All @@ -133,7 +146,9 @@ iterator getValidatorIndices(
bls_to_execution_change: SignedBLSToExecutionChange): uint64 =
yield bls_to_execution_change.message.validator_index

func isSeen*(pool: ValidatorChangePool, msg: phase0.AttesterSlashing): bool =
func isSeen*(
pool: ValidatorChangePool,
msg: phase0.AttesterSlashing | electra.AttesterSlashing): bool =
for idx in getValidatorIndices(msg):
# One index is enough!
if idx notin pool.prior_seen_attester_slashed_indices:
Expand All @@ -154,12 +169,23 @@ func isSeen*(pool: ValidatorChangePool, msg: SignedBLSToExecutionChange): bool =
func addMessage*(pool: var ValidatorChangePool, msg: phase0.AttesterSlashing) =
for idx in getValidatorIndices(msg):
pool.prior_seen_attester_slashed_indices.incl idx
if pool.attestationPool != nil:
if not pool.attestationPool.isNil:
let i = ValidatorIndex.init(idx).valueOr:
continue
pool.attestationPool.forkChoice.process_equivocation(i)

pool.phase0_attester_slashings.addValidatorChangeMessage(
pool.prior_seen_attester_slashed_indices, msg, ATTESTER_SLASHINGS_BOUND)

func addMessage*(pool: var ValidatorChangePool, msg: electra.AttesterSlashing) =
for idx in getValidatorIndices(msg):
pool.prior_seen_attester_slashed_indices.incl idx
if not pool.attestationPool.isNil:
let i = ValidatorIndex.init(idx).valueOr:
continue
pool.attestationPool.forkChoice.process_equivocation(i)

pool.attester_slashings.addValidatorChangeMessage(
pool.electra_attester_slashings.addValidatorChangeMessage(
pool.prior_seen_attester_slashed_indices, msg, ATTESTER_SLASHINGS_BOUND)

func addMessage*(pool: var ValidatorChangePool, msg: ProposerSlashing) =
Expand Down Expand Up @@ -193,7 +219,7 @@ proc validateValidatorChangeMessage(
check_proposer_slashing(state, msg, {}).isOk
proc validateValidatorChangeMessage(
cfg: RuntimeConfig, state: ForkyBeaconState, msg:
phase0.AttesterSlashing): bool =
phase0.AttesterSlashing | electra.AttesterSlashing): bool =
check_attester_slashing(state, msg, {}).isOk
proc validateValidatorChangeMessage(
cfg: RuntimeConfig, state: ForkyBeaconState, msg: SignedVoluntaryExit):
Expand Down Expand Up @@ -252,11 +278,13 @@ proc getBeaconBlockValidatorChanges*(
res: BeaconBlockValidatorChanges

getValidatorChangeMessagesForBlock(
pool.attester_slashings, cfg, state, indices, res.attester_slashings)
pool.phase0_attester_slashings, cfg, state, indices,
res.phase0_attester_slashings)
getValidatorChangeMessagesForBlock(
pool.proposer_slashings, cfg, state, indices, res.proposer_slashings)
getValidatorChangeMessagesForBlock(
pool.voluntary_exits, cfg, state, indices, res.voluntary_exits)

when typeof(state).kind >= ConsensusFork.Capella:
# Prioritize these
getValidatorChangeMessagesForBlock(
Expand All @@ -267,4 +295,9 @@ proc getBeaconBlockValidatorChanges*(
pool.bls_to_execution_changes_gossip, cfg, state, indices,
res.bls_to_execution_changes)

when typeof(state).kind >= ConsensusFork.Electra:
getValidatorChangeMessagesForBlock(
pool.electra_attester_slashings, cfg, state, indices,
res.electra_attester_slashings)

res
6 changes: 4 additions & 2 deletions beacon_chain/gossip_processing/gossip_validation.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1246,8 +1246,10 @@ proc validateAttesterSlashing*(
return pool.checkedReject(attester_slashing_validity.error)

# Send notification about new attester slashing via callback
if not(isNil(pool.onAttesterSlashingReceived)):
pool.onAttesterSlashingReceived(attester_slashing)
if not(isNil(pool.onPhase0AttesterSlashingReceived)):
pool.onPhase0AttesterSlashingReceived(attester_slashing)

debugComment "apparently there's no gopssip validation in place for electra attslashings"

ok()

Expand Down
8 changes: 6 additions & 2 deletions beacon_chain/nimbus_beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,11 @@ proc initFullNode(
node.eventBus.blsToExecQueue.emit(data)
proc onProposerSlashingAdded(data: ProposerSlashing) =
node.eventBus.propSlashQueue.emit(data)
proc onAttesterSlashingAdded(data: phase0.AttesterSlashing) =
proc onPhase0AttesterSlashingAdded(data: phase0.AttesterSlashing) =
node.eventBus.attSlashQueue.emit(data)
proc onElectraAttesterSlashingAdded(data: electra.AttesterSlashing) =
debugComment "electra att slasher queue"
discard
proc onBlobSidecarAdded(data: BlobSidecarInfoObject) =
node.eventBus.blobSidecarQueue.emit(data)
proc onBlockAdded(data: ForkedTrustedSignedBeaconBlock) =
Expand Down Expand Up @@ -392,7 +395,8 @@ proc initFullNode(
LightClientPool())
validatorChangePool = newClone(ValidatorChangePool.init(
dag, attestationPool, onVoluntaryExitAdded, onBLSToExecutionChangeAdded,
onProposerSlashingAdded, onAttesterSlashingAdded))
onProposerSlashingAdded, onPhase0AttesterSlashingAdded,
onElectraAttesterSlashingAdded))
blobQuarantine = newClone(BlobQuarantine.init(onBlobSidecarAdded))
consensusManager = ConsensusManager.new(
dag, attestationPool, quarantine, node.elManager,
Expand Down
2 changes: 1 addition & 1 deletion beacon_chain/rpc/rest_beacon_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
router.api2(MethodGet, "/eth/v1/beacon/pool/attester_slashings") do (
) -> RestApiResponse:
RestApiResponse.jsonResponse(
toSeq(node.validatorChangePool.attester_slashings))
toSeq(node.validatorChangePool.phase0_attester_slashings))

# https://ethereum.github.io/beacon-APIs/#/Beacon/submitPoolAttesterSlashings
router.api(MethodPost, "/eth/v1/beacon/pool/attester_slashings") do (
Expand Down
9 changes: 0 additions & 9 deletions beacon_chain/spec/datatypes/capella.nim
Original file line number Diff line number Diff line change
Expand Up @@ -498,15 +498,6 @@ type
SigVerifiedBeaconBlockBody |
TrustedBeaconBlockBody

BeaconBlockValidatorChanges* = object
# Collection of exits that are suitable for block production
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
attester_slashings*:
List[phase0.AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
bls_to_execution_changes*:
List[SignedBLSToExecutionChange, Limit MAX_BLS_TO_EXECUTION_CHANGES]

BeaconStateDiffPreSnapshot* = object
eth1_data_votes_recent*: seq[Eth1Data]
eth1_data_votes_len*: int
Expand Down
15 changes: 13 additions & 2 deletions beacon_chain/spec/datatypes/electra.nim
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ from ./altair import
TrustedSyncAggregate, num_active_participants
from ./bellatrix import BloomLogs, ExecutionAddress, Transaction
from ./capella import
ExecutionBranch, HistoricalSummary, SignedBLSToExecutionChangeList,
Withdrawal, EXECUTION_PAYLOAD_GINDEX
ExecutionBranch, HistoricalSummary, SignedBLSToExecutionChange,
SignedBLSToExecutionChangeList, Withdrawal, EXECUTION_PAYLOAD_GINDEX
from ./deneb import Blobs, BlobsBundle, KzgCommitments, KzgProofs

export json_serialization, base, kzg4844
Expand Down Expand Up @@ -630,6 +630,17 @@ type
kzg_proofs*: KzgProofs
blobs*: Blobs

BeaconBlockValidatorChanges* = object
# Collection of exits that are suitable for block production
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
phase0_attester_slashings*:
List[phase0.AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
electra_attester_slashings*:
List[electra.AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS_ELECTRA]
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
bls_to_execution_changes*:
List[SignedBLSToExecutionChange, Limit MAX_BLS_TO_EXECUTION_CHANGES]

# TODO: There should be only a single generic HashedBeaconState definition
func initHashedBeaconState*(s: BeaconState): HashedBeaconState =
HashedBeaconState(data: s)
Expand Down
6 changes: 3 additions & 3 deletions beacon_chain/spec/state_transition.nim
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func partialBeaconBlock*(
eth1_data: eth1_data,
graffiti: graffiti,
proposer_slashings: validator_changes.proposer_slashings,
attester_slashings: validator_changes.attester_slashings,
attester_slashings: validator_changes.phase0_attester_slashings,
attestations:
List[phase0.Attestation, Limit MAX_ATTESTATIONS](attestations),
deposits: List[Deposit, Limit MAX_DEPOSITS](deposits),
Expand Down Expand Up @@ -500,7 +500,7 @@ proc makeBeaconBlockWithRewards*(
hash_tree_root(eth1_data),
hash_tree_root(graffiti),
hash_tree_root(validator_changes.proposer_slashings),
hash_tree_root(validator_changes.attester_slashings),
hash_tree_root(validator_changes.phase0_attester_slashings),
hash_tree_root(
List[phase0.Attestation, Limit MAX_ATTESTATIONS](
attestations)),
Expand All @@ -524,7 +524,7 @@ proc makeBeaconBlockWithRewards*(
hash_tree_root(eth1_data),
hash_tree_root(graffiti),
hash_tree_root(validator_changes.proposer_slashings),
hash_tree_root(validator_changes.attester_slashings),
hash_tree_root(validator_changes.electra_attester_slashings),
hash_tree_root(
List[electra.Attestation, Limit MAX_ATTESTATIONS](
attestations)),
Expand Down
Loading

0 comments on commit d4e441e

Please sign in to comment.