diff --git a/specs/_features/eipxxxx/beacon-chain.md b/specs/_features/eipxxxx/beacon-chain.md index b4d25e8a7..88075df5a 100644 --- a/specs/_features/eipxxxx/beacon-chain.md +++ b/specs/_features/eipxxxx/beacon-chain.md @@ -80,20 +80,20 @@ At any given slot, the status of the blockchain's head may be either | Name | Value | | - | - | -| `PTC_SIZE` | `uint64(2**9)` (=512) # (New in EIP-XXXX) | +| `PTC_SIZE` | `uint64(2**9)` (=512) # (New in EIP-XXXX) | ### Domain types | Name | Value | | - | - | -| `DOMAIN_BEACON_BUILDER` | `DomainType('0x1B000000')` # (New in EIP-XXXX)| -| `DOMAIN_PTC_ATTESTER` | `DomainType('0x0C000000')` # (New in EIP-XXXX)| +| `DOMAIN_BEACON_BUILDER` | `DomainType('0x1B000000')` # (New in EIP-XXXX)| +| `DOMAIN_PTC_ATTESTER` | `DomainType('0x0C000000')` # (New in EIP-XXXX)| ### Max operations per block | Name | Value | | - | - | -| `MAX_PAYLOAD_ATTESTATIONS` | `2**2` (= 4) # (New in EIP-XXXX) | +| `MAX_PAYLOAD_ATTESTATIONS` | `2**2` (= 4) # (New in EIP-XXXX) | ## Containers @@ -186,8 +186,8 @@ class BeaconBlockBody(Container): # Removed blob_kzg_commitments [Removed in EIP-XXXX] bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # PBS - signed_execution_payload_header: SignedExecutionPayloadHeader # [New in EIP-XXXX] - payload_attestations: List[PayloadAttestation, MAX_PAYLOAD_ATTESTATIONS] # [New in EIP-XXXX] + signed_execution_payload_header: SignedExecutionPayloadHeader # [New in EIP-XXXX] + payload_attestations: List[PayloadAttestation, MAX_PAYLOAD_ATTESTATIONS] # [New in EIP-XXXX] ``` #### `ExecutionPayloadHeader` @@ -262,9 +262,9 @@ class BeaconState(Container): pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT] pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] # PBS - latest_block_hash: Hash32 # [New in EIP-XXXX] - latest_full_slot: Slot # [New in EIP-XXXX] - latest_withdrawals_root: Root # [New in EIP-XXXX] + latest_block_hash: Hash32 # [New in EIP-XXXX] + latest_full_slot: Slot # [New in EIP-XXXX] + latest_withdrawals_root: Root # [New in EIP-XXXX] ``` ## Helper functions @@ -288,9 +288,12 @@ def bit_floor(n: uint64) -> uint64: #### `is_valid_indexed_payload_attestation` ```python -def is_valid_indexed_payload_attestation(state: BeaconState, indexed_payload_attestation: IndexedPayloadAttestation) -> bool: +def is_valid_indexed_payload_attestation( + state: BeaconState, + indexed_payload_attestation: IndexedPayloadAttestation) -> bool: """ - Check if ``indexed_payload_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature. + Check if ``indexed_payload_attestation`` is not empty, has sorted and unique indices and has + a valid aggregate signature. """ # Verify the data is valid if indexed_payload_attestation.data.payload_status >= PAYLOAD_INVALID_STATUS: @@ -402,8 +405,8 @@ The post-state corresponding to a pre-state `state` and a signed execution paylo ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) - process_withdrawals(state) # [Modified in EIP-XXXX] - process_execution_payload_header(state, block) # [Modified in EIP-XXXX, removed process_execution_payload] + process_withdrawals(state) # [Modified in EIP-XXXX] + process_execution_payload_header(state, block) # [Modified in EIP-XXXX, removed process_execution_payload] process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) # [Modified in EIP-XXXX] @@ -415,7 +418,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: ```python def process_withdrawals(state: BeaconState) -> None: - ## return early if the parent block was empty + # return early if the parent block was empty if not is_parent_block_full(state): return @@ -448,7 +451,7 @@ def process_withdrawals(state: BeaconState) -> None: ```python def verify_execution_payload_header_signature(state: BeaconState, - signed_header: SignedExecutionPayloadHeader) -> bool: + signed_header: SignedExecutionPayloadHeader) -> bool: # Check the signature builder = state.validators[signed_header.message.builder_index] signing_root = compute_signing_root(signed_header.message, get_domain(state, DOMAIN_BEACON_BUILDER)) @@ -505,7 +508,7 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: # Removed `process_deposit_request` in EIP-XXXX # Removed `process_withdrawal_request` in EIP-XXXX # Removed `process_consolidation_request` in EIP-XXXX - for_ops(body.payload_attestations, process_payload_attestation) # [New in EIP-XXXX] + for_ops(body.payload_attestations, process_payload_attestation) # [New in EIP-XXXX] ``` ##### Payload Attestations @@ -518,17 +521,16 @@ def remove_flag(flags: ParticipationFlags, flag_index: int) -> ParticipationFlag ```python def process_payload_attestation(state: BeaconState, payload_attestation: PayloadAttestation) -> None: - ## Check that the attestation is for the parent beacon block + # Check that the attestation is for the parent beacon block data = payload_attestation.data assert data.beacon_block_root == state.latest_block_header.parent_root - ## Check that the attestation is for the previous slot + # Check that the attestation is for the previous slot assert data.slot + 1 == state.slot - #Verify signature + # Verify signature indexed_payload_attestation = get_indexed_payload_attestation(state, data.slot, payload_attestation) assert is_valid_indexed_payload_attestation(state, indexed_payload_attestation) - ptc = get_ptc(state, data.slot) if state.slot % SLOTS_PER_EPOCH == 0: epoch_participation = state.previous_epoch_participation else: @@ -548,7 +550,7 @@ def process_payload_attestation(state: BeaconState, payload_attestation: Payload epoch_participation[index] = remove_flag(epoch_participation[index], flag_index) proposer_penalty_numerator += get_base_reward(state, index) * weight # Penalize the proposer - proposer_penalty = Gwei(2*proposer_penalty_numerator // proposer_reward_denominator) + proposer_penalty = Gwei(2 * proposer_penalty_numerator // proposer_reward_denominator) decrease_balance(state, proposer_index, proposer_penalty) return @@ -568,7 +570,8 @@ def process_payload_attestation(state: BeaconState, payload_attestation: Payload #### New `verify_execution_payload_envelope_signature` ```python -def verify_execution_payload_envelope_signature(state: BeaconState, signed_envelope: SignedExecutionPayloadEnvelope) -> bool: +def verify_execution_payload_envelope_signature( + state: BeaconState, signed_envelope: SignedExecutionPayloadEnvelope) -> bool: builder = state.validators[signed_envelope.message.builder_index] signing_root = compute_signing_root(signed_envelope.message, get_domain(state, DOMAIN_BEACON_BUILDER)) return bls.Verify(builder.pubkey, signing_root, signed_envelope.signature) @@ -578,7 +581,9 @@ def verify_execution_payload_envelope_signature(state: BeaconState, signed_envel *Note*: `process_execution_payload` is now an independent check in state transition. It is called when importing a signed execution payload proposed by the builder of the current slot. ```python -def process_execution_payload(state: BeaconState, signed_envelope: SignedExecutionPayloadEnvelope, execution_engine: ExecutionEngine, verify = True) -> None: +def process_execution_payload(state: BeaconState, + signed_envelope: SignedExecutionPayloadEnvelope, + execution_engine: ExecutionEngine, verify=True) -> None: # Verify signature if verify: assert verify_execution_payload_envelope_signature(state, signed_envelope) @@ -607,7 +612,8 @@ def process_execution_payload(state: BeaconState, signed_envelope: SignedExecuti # Verify timestamp assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) # Verify the execution payload is valid - versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in envelope.blob_kzg_commitments] + versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) + for commitment in envelope.blob_kzg_commitments] assert execution_engine.verify_and_notify_new_payload( NewPayloadRequest( execution_payload=payload, diff --git a/specs/_features/eipxxxx/builder.md b/specs/_features/eipxxxx/builder.md index e44111bd9..35cf29603 100644 --- a/specs/_features/eipxxxx/builder.md +++ b/specs/_features/eipxxxx/builder.md @@ -41,7 +41,8 @@ Builders can broadcast a payload bid for the current or the next slot's proposer After building the `header`, the builder obtains a `signature` of the header by using ```python -def get_execution_payload_header_signature(state: BeaconState, header: ExecutionPayloadHeader, privkey: int) -> BLSSignature: +def get_execution_payload_header_signature( + state: BeaconState, header: ExecutionPayloadHeader, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_BUILDER, compute_epoch_at_slot(header.slot)) signing_root = compute_signing_root(header, domain) return bls.Sign(privkey, signing_root) @@ -101,7 +102,8 @@ After setting these parameters, the builder should run `process_execution_payloa 6. Set `state_root` to `hash_tree_root(state)`. After preparing the `envelope` the builder should sign the envelope using: ```python -def get_execution_payload_envelope_signature(state: BeaconState, envelope: ExecutionPayloadEnvelope, privkey: int) -> BLSSignature: +def get_execution_payload_envelope_signature( + state: BeaconState, envelope: ExecutionPayloadEnvelope, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_BUILDER, compute_epoch_at_slot(state.slot)) signing_root = compute_signing_root(envelope, domain) return bls.Sign(privkey, signing_root) diff --git a/specs/_features/eipxxxx/fork-choice.md b/specs/_features/eipxxxx/fork-choice.md index 52b7de037..2ddc79a98 100644 --- a/specs/_features/eipxxxx/fork-choice.md +++ b/specs/_features/eipxxxx/fork-choice.md @@ -44,7 +44,7 @@ This is the modification of the fork choice accompanying the ePBS upgrade. | Name | Value | | -------------------- | ----------- | -| `PAYLOAD_TIMELY_THRESHOLD` | `PTC_SIZE/2` (=`uint64(256)`) | +| `PAYLOAD_TIMELY_THRESHOLD` | `PTC_SIZE / 2` (=`uint64(256)`) | | `INTERVALS_PER_SLOT` | `4` # [modified in EIP-XXXX] | | `PROPOSER_SCORE_BOOST` | `20` # [modified in EIP-XXXX] | | `PAYLOAD_WITHHOLD_BOOST` | `40` | @@ -100,9 +100,9 @@ class Store(object): unrealized_justified_checkpoint: Checkpoint unrealized_finalized_checkpoint: Checkpoint proposer_boost_root: Root - payload_withhold_boost_root: Root # [New in EIP-XXXX] - payload_withhold_boost_full: boolean # [New in EIP-XXXX] - payload_reveal_boost_root: Root # [New in EIP-XXXX] + payload_withhold_boost_root: Root # [New in EIP-XXXX] + payload_withhold_boost_full: boolean # [New in EIP-XXXX] + payload_reveal_boost_root: Root # [New in EIP-XXXX] equivocating_indices: Set[ValidatorIndex] blocks: Dict[Root, BeaconBlock] = field(default_factory=dict) block_states: Dict[Root, BeaconState] = field(default_factory=dict) @@ -110,8 +110,8 @@ class Store(object): checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict) latest_messages: Dict[ValidatorIndex, LatestMessage] = field(default_factory=dict) unrealized_justifications: Dict[Root, Checkpoint] = field(default_factory=dict) - execution_payload_states: Dict[Root, BeaconState] = field(default_factory=dict) # [New in EIP-XXXX] - ptc_vote: Dict[Root, Vector[uint8, PTC_SIZE]] = field(default_factory=dict) # [New in EIP-XXXX] + execution_payload_states: Dict[Root, BeaconState] = field(default_factory=dict) # [New in EIP-XXXX] + ptc_vote: Dict[Root, Vector[uint8, PTC_SIZE]] = field(default_factory=dict) # [New in EIP-XXXX] ``` ### Modified `get_forkchoice_store` @@ -132,9 +132,9 @@ def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) - unrealized_justified_checkpoint=justified_checkpoint, unrealized_finalized_checkpoint=finalized_checkpoint, proposer_boost_root=proposer_boost_root, - payload_withhold_boost_root=proposer_boost_root, # [New in EIP-XXXX] - payload_withhold_boost_full=True, # [New in EIP-XXXX] - payload_reveal_boost_root=proposer_boost_root, # [New in EIP-XXXX] + payload_withhold_boost_root=proposer_boost_root, # [New in EIP-XXXX] + payload_withhold_boost_full=True, # [New in EIP-XXXX] + payload_reveal_boost_root=proposer_boost_root, # [New in EIP-XXXX] equivocating_indices=set(), blocks={anchor_root: copy(anchor_block)}, block_states={anchor_root: copy(anchor_state)}, @@ -156,8 +156,9 @@ def notify_ptc_messages(store: Store, state: BeaconState, payload_attestations: for payload_attestation in payload_attestations: indexed_payload_attestation = get_indexed_payload_attestation(state, Slot(state.slot - 1), payload_attestation) for idx in indexed_payload_attestation.attesting_indices: - on_payload_attestation_message(store, PayloadAttestationMessage(validator_index=idx, - data=payload_attestation.data, signature= BLSSignature(), is_from_block=True)) + on_payload_attestation_message(store, + PayloadAttestationMessage(validator_index=idx, + data=payload_attestation.data, signature=BLSSignature(), is_from_block=True)) ``` ### `is_payload_present` @@ -333,19 +334,29 @@ def get_head(store: Store) -> ChildNode: children = [ ChildNode(root=root, slot=block.slot, is_payload_present=present) for (root, block) in blocks.items() if block.parent_root == best_child.root and - is_parent_node_full(store, block) == best_child.is_payload_present if root != store.justified_checkpoint.root - for present in (True, False) if root in store.execution_payload_states or present == False + is_parent_node_full(store, block) == best_child.is_payload_present if + root != store.justified_checkpoint.root + for present in (True, False) if root in store.execution_payload_states or not present ] if len(children) == 0: return best_child # if we have children we consider the current head advanced as a possible head - children += [ChildNode(root=best_child.root, slot=best_child.slot + 1, is_payload_present=best_child.is_payload_present)] + children += [ + ChildNode(root=best_child.root, slot=best_child.slot + 1, is_payload_present=best_child.is_payload_present) + ] # Sort by latest attesting balance with ties broken lexicographically # Ties broken by favoring full blocks according to the PTC vote # Ties are then broken by favoring full blocks # Ties broken then by favoring higher slot numbers # Ties then broken by favoring block with lexicographically higher root - new_best_child = max(children, key=lambda child: (get_weight(store, child), is_payload_present(store, child.root), child.is_payload_present, child.slot, child.root)) + new_best_child = max(children, key=lambda child: ( + get_weight(store, child), + is_payload_present(store, child.root), + child.is_payload_present, + child.slot, + child.root + ) + ) if new_best_child.root == best_child.root: return new_best_child best_child = new_best_child @@ -402,7 +413,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: # Add new state for this block to the store store.block_states[block_root] = state # Add a new PTC voting for this block to the store - store.ptc_vote[block_root] = [PAYLOAD_ABSENT]*PTC_SIZE + store.ptc_vote[block_root] = [PAYLOAD_ABSENT] * PTC_SIZE # Notify the store about the payload_attestations in the block notify_ptc_messages(store, state, block.body.payload_attestations)