diff --git a/setup.py b/setup.py index 818428aed..4d88e709a 100644 --- a/setup.py +++ b/setup.py @@ -701,7 +701,7 @@ ignored_dependencies = [ 'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256', 'bytes', 'byte', 'ByteList', 'ByteVector', 'Dict', 'dict', 'field', 'ceillog2', 'floorlog2', 'Set', - 'Optional', + 'Optional', 'Sequence', ] @@ -896,6 +896,7 @@ class PySpecCommand(Command): self.md_doc_paths += """ specs/capella/beacon-chain.md specs/capella/fork.md + specs/capella/fork-choice.md specs/capella/validator.md specs/capella/p2p-interface.md """ diff --git a/specs/capella/fork-choice.md b/specs/capella/fork-choice.md new file mode 100644 index 000000000..10f034e1d --- /dev/null +++ b/specs/capella/fork-choice.md @@ -0,0 +1,53 @@ +# Capella -- Fork Choice + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + + + +## Introduction + +This is the modification of the fork choice according to the Capella upgrade. + +Unless stated explicitly, all prior functionality from [Bellatrix](../bellatrix/fork-choice.md) is inherited. + +## Custom types + +## Protocols + +### `ExecutionEngine` + +*Note*: The `notify_forkchoice_updated` function is modified in the `ExecutionEngine` protocol at the Capella upgrade. + +#### `notify_forkchoice_updated` + +The only change made is to the `PayloadAttributes` container through the addition of `withdrawals`. +Otherwise, `notify_forkchoice_updated` inherits all prior functionality. + +```python +def notify_forkchoice_updated(self: ExecutionEngine, + head_block_hash: Hash32, + finalized_block_hash: Hash32, + payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]: + ... +``` + +## Helpers + +### Extended `PayloadAttributes` + +`PayloadAttributes` is extended with the `withdrawals` field. + +```python +@dataclass +class PayloadAttributes(object): + timestamp: uint64 + prev_randao: Bytes32 + suggested_fee_recipient: ExecutionAddress + withdrawals: Sequence[Withdrawal] +``` diff --git a/specs/capella/validator.md b/specs/capella/validator.md index e69de29bb..edf5d72bd 100644 --- a/specs/capella/validator.md +++ b/specs/capella/validator.md @@ -0,0 +1,91 @@ +# Capella -- Honest Validator + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + + + + +## Introduction + +This document represents the changes to be made in the code of an "honest validator" to implement the Capella upgrade. + +## Prerequisites + +This document is an extension of the [Bellatrix -- Honest Validator](../bellatrix/validator.md) guide. +All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden. + +All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [Capella](./beacon-chain.md) are requisite for this document and used throughout. +Please see related Beacon Chain doc before continuing and use them as a reference throughout. + +## Helpers + +## Protocols + +### `ExecutionEngine` + +#### `get_payload` + +`get_payload` returns the upgraded Capella `ExecutionPayload` type. + +## Beacon chain responsibilities + +All validator responsibilities remain unchanged other than those noted below. + +### Block proposal + +#### Constructing the `BeaconBlockBody` + +##### ExecutionPayload + +`ExecutionPayload`s are constructed as they were in Bellatrix, except that the +expected withdrawals for the slot must be gathered from the `state` (utilizing the +helper `get_expected_withdrawals`) and passed into the `ExecutionEngine` within `prepare_execution_payload`. + + +```python +def get_expected_withdrawals(state: BeaconState) -> Sequence[Withdrawal]: + num_withdrawals = min(MAX_WITHDRAWALS_PER_PAYLOAD, len(state.withdrawals_queue)) + return state.withdrawals_queue[:num_withdrawals] +``` + +*Note*: The only change made to `prepare_execution_payload` is to call +`get_expected_withdrawals()` to set the new `withdrawals` field of `PayloadAttributes`. + +```python +def prepare_execution_payload(state: BeaconState, + pow_chain: Dict[Hash32, PowBlock], + finalized_block_hash: Hash32, + suggested_fee_recipient: ExecutionAddress, + execution_engine: ExecutionEngine) -> Optional[PayloadId]: + if not is_merge_transition_complete(state): + is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32() + is_activation_epoch_reached = get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH + if is_terminal_block_hash_set and not is_activation_epoch_reached: + # Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed + return None + + terminal_pow_block = get_terminal_pow_block(pow_chain) + if terminal_pow_block is None: + # Pre-merge, no prepare payload call is needed + return None + # Signify merge via producing on top of the terminal PoW block + parent_hash = terminal_pow_block.block_hash + else: + # Post-merge, normal payload + parent_hash = state.latest_execution_payload_header.block_hash + + # Set the forkchoice head and initiate the payload build process + payload_attributes = PayloadAttributes( + timestamp=compute_timestamp_at_slot(state, state.slot), + prev_randao=get_randao_mix(state, get_current_epoch(state)), + suggested_fee_recipient=suggested_fee_recipient, + withdrawals=get_expected_withdrawals(state), # [New in Capella] + ) + return execution_engine.notify_forkchoice_updated(parent_hash, finalized_block_hash, payload_attributes) +```