Skip to content

Commit

Permalink
Merge pull request #1 from ethereum/align-to-beacon-api
Browse files Browse the repository at this point in the history
Align to beacon-APIs
  • Loading branch information
adiasg authored Nov 22, 2021
2 parents b58211f + 70667f7 commit 2a097a4
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 97 deletions.
96 changes: 79 additions & 17 deletions eth2_node.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,94 @@
from typing import List
from eth2spec.phase0.mainnet import (
Container,
Slot,
AttestationData,
Attestation,
ValidatorIndex,
Container, SignedBeaconBlock, uint64, Bytes32,
BLSPubkey, BLSSignature,
Slot, Epoch,
ValidatorIndex, CommitteeIndex,
AttestationData, Attestation,
BeaconBlock, SignedBeaconBlock,
)

class AttestationDuty(Container):
# TODO: Update schema to include committee_index etc. as defined
# in https://ethereum.github.io/beacon-APIs/#/
pubkey: BLSPubkey
validator_index: ValidatorIndex
committee_index: CommitteeIndex
committee_length: uint64
committees_at_slot: uint64
validator_committee_index: ValidatorIndex # TODO: Is this the correct datatype?
slot: Slot
validator_index: ValidatorIndex

class ProposerDuty(Container):
pubkey: BLSPubkey
validator_index: ValidatorIndex
slot: Slot


# Beacon Node Interface

# Beacon Node
def bn_get_next_attestation_duty() -> AttestationDuty:
def bn_get_attestation_duties_for_epoch(validator_indices: List[ValidatorIndex], epoch: Epoch) -> List[AttestationDuty]:
# TODO: Define typing here:
# What's the size of validator_indices & the returned attestation_duties?
"""Fetch attestation duties for the validator indices in the epoch.
Uses https://ethereum.github.io/beacon-APIs/#/ValidatorRequiredApi/getAttesterDuties
"""
pass

def bn_broadcast_attestation(attestation: Attestation) -> None:
def bn_get_attestation_data(slot: Slot, committee_index: CommitteeIndex) -> AttestationData:
"""Produces attestation data for the given slot & committee index.
Uses https://ethereum.github.io/beacon-APIs/#/ValidatorRequiredApi/produceAttestationData
"""
pass

# Validator Client
def vc_is_slashable(attestation_data: AttestationData, validator_index: ValidatorIndex) -> bool:
# TODO: Should we use validator index or pubkey?

def bn_submit_attestation(attestation: Attestation) -> None:
"""Submit attestation to BN for p2p gossip.
Uses https://ethereum.github.io/beacon-APIs/#/Beacon/submitPoolAttestations
"""
pass

def bn_get_proposer_duties_for_epoch(epoch: Epoch) -> List[ProposerDuty]:
"""Fetch proposer duties for all proposers in the epoch.
Uses https://ethereum.github.io/beacon-APIs/#/ValidatorRequiredApi/getProposerDuties
"""
pass

def bn_produce_block(slot: Slot, randao_reveal: BLSSignature, graffiti: Bytes32) -> BeaconBlock:
"""Produces valid block for given slot using provided data
Uses https://ethereum.github.io/beacon-APIs/#/ValidatorRequiredApi/produceBlockV2
"""
pass

# TODO: What object does the VC sign?
# Is it the same object that the BN accepts for broadcast?
def vc_sign_attestation(attestation_data: AttestationData, validator_index: ValidatorIndex) -> AttestationData:
def bn_submit_block(block: SignedBeaconBlock) -> None:
"""Submit block to BN for p2p gossip.
Uses https://ethereum.github.io/beacon-APIs/#/ValidatorRequiredApi/publishBlock
"""
pass


# Validator Client Interface

def vc_is_slashable_attestation_data(attestation_data: AttestationData, validator_pubkey: BLSPubkey) -> bool:
"""Checks whether the attestation data is slashable according to the anti-slashing database.
This endpoint does not exist in beacon-APIs.
"""
pass

def vc_sign_attestation(attestation_data: AttestationData, attestation_duty: AttestationDuty) -> Attestation:
"""Returns a signed attestations that is constructed using the given attestation data & attestation duty.
This endpoint does not exist in beacon-APIs.
"""
# See note about attestation construction here:
# https://github.com/ethereum/beacon-APIs/blame/05c1bc142e1a3fb2a63c79098743776241341d08/validator-flow.md#L35-L37
pass

def vc_is_slashable_block(block: BeaconBlock, validator_pubkey: BLSPubkey) -> bool:
"""Checks whether the block is slashable according to the anti-slashing database.
This endpoint does not exist in beacon-APIs.
"""
pass

def vc_sign_block(block: BeaconBlock, proposer_duty: ProposerDuty) -> SignedBeaconBlock:
"""Returns a signed beacon block using the validator index given in the proposer duty.
This endpoint does not exist in beacon-APIs.
"""
pass
120 changes: 93 additions & 27 deletions spec.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,105 @@
from test import (
get_current_time,
bn_get_next_attestation_duty,
bn_broadcast_attestation,
from eth2_node import (
AttestationDuty, ProposerDuty,
AttestationData, BeaconBlock,
bn_get_attestation_duties_for_epoch,
bn_get_attestation_data,
bn_submit_attestation,
bn_get_proposer_duties_for_epoch,
bn_produce_block,
bn_submit_block,
vc_is_slashable_attestation_data,
vc_sign_attestation,
calculate_attestation_time,
consensus,
)
from eth2spec.phase0.mainnet import (
Attestation,
vc_is_slashable_block,
vc_sign_block,
)

def attestation_duty_loop():
# run in a loop forever
attestation_duty = bn_get_next_attestation_duty()
while get_current_time() < calculate_attestation_time(attestation_duty.slot):
pass

# Obtain lock on consensus process here - only a single consensus instance
# should be running at any given time
attestation_data = consensus(attestation_duty.slot)
"""
Consensus Specification
"""

def consensus_is_valid_attestation_data(attestation_data: AttestationData, attestation_duty: AttestationDuty) -> bool:
"""Determines if the given attestation is valid for the attestation duty.
"""
assert attestation_data.slot == attestation_duty.slot
assert attestation_data.committee_index == attestation_duty.committee_index
assert not vc_is_slashable_attestation_data(attestation_data, attestation_duty.pubkey)

def consensus_on_attestation(attestation_duty: AttestationDuty) -> AttestationData:
"""Consensus protocol between distributed validator nodes for attestation values.
Returns the decided value.
The consensus protocol must use `consensus_is_valid_attestation_data` to determine
validity of the proposed attestation value.
"""
pass

def consensus_is_valid_block(block: BeaconBlock, proposer_duty: ProposerDuty) -> bool:
"""Determines if the given block is valid for the proposer duty.
"""
assert block.slot == proposer_duty.slot
# TODO: Assert correct block.proposer_index
assert not vc_is_slashable_block(block, proposer_duty.pubkey)

def consensus_on_block(proposer_duty: ProposerDuty) -> AttestationData:
"""Consensus protocol between distributed validator nodes for block values.
Returns the decided value.
The consensus protocol must use `consensus_is_valid_block` to determine
validity of the proposed block value.
"""
pass


"""
Attestation Production Process:
1. At the start of every epoch, get attestation duties for epoch+1 by running
bn_get_attestation_duties_for_epoch(validator_indices, epoch+1)
2. For each attestation_duty recevied in Step 1, schedule
serve_attestation_duty(attestation_duty) at 1/3rd way through the slot
attestation_duty.slot
See notes here:
https://github.com/ethereum/beacon-APIs/blob/05c1bc142e1a3fb2a63c79098743776241341d08/validator-flow.md#attestation
"""

def serve_attestation_duty(attestation_duty):
# Obtain lock on consensus_on_attestation here.
# Only a single consensus_on_attestation instance should be
# running at any given time
attestation_data = consensus_on_attestation(attestation_duty)

# 1. Threshold sign attestation from local VC
threshold_signed_attestation_data = vc_sign_attestation(attestation_data, attestation_duty.validator_index)
threshold_signed_attestation = vc_sign_attestation(attestation_data, attestation_duty)
# 2. Broadcast threshold signed attestation
# TODO
# 3. Reconstruct complete signed attestation by combining threshold signed attestations
complete_signed_attestation_data = threshold_signed_attestation_data
complete_signed_attestation = Attestation(data=complete_signed_attestation_data)
complete_signed_attestation = threshold_signed_attestation
# 4. Send complete signed attestation to BN for broadcast
bn_broadcast_attestation(complete_signed_attestation)
bn_submit_attestation(complete_signed_attestation)

# Release lock on consensus_on_attestation here.

"""
Block Production Process:
1. At the start of every epoch, get proposer duties for epoch+1 by running
bn_get_proposer_duties_for_epoch(epoch+1)
2. For each proposer_duty recevied in Step 1 for our validators, schedule
serve_proposer_duty(proposer_duty) at beginning of slot proposer_duty.slot
See notes here:
https://github.com/ethereum/beacon-APIs/blob/05c1bc142e1a3fb2a63c79098743776241341d08/validator-flow.md#block-proposing
"""

# Release lock on consensus process here
def serve_proposer_duty(proposer_duty):
# Obtain lock on consensus_on_block here.
# Only a single consensus_on_block instance should be
# running at any given time
block = consensus_on_block(proposer_duty)

print(
f"Duty Slot: {attestation_duty.slot}, Attestation Slot: {attestation_data.slot}")
# 1. Threshold sign block from local VC
threshold_signed_block = vc_sign_block(block, proposer_duty)
# 2. Broadcast threshold signed block
# 3. Reconstruct complete signed block by combining threshold signed blocks
complete_signed_block = threshold_signed_block
# 4. Send complete signed block to BN for broadcast
bn_submit_block(complete_signed_block)

while True:
attestation_duty_loop()
# Release lock on consensus_on_block here.
Loading

0 comments on commit 2a097a4

Please sign in to comment.