From e80a142d836f6762abf100827ad135e513044831 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 23 Feb 2022 15:05:55 -0700 Subject: [PATCH] modified withdrawals for push --- specs/capella/beacon-chain.md | 148 ++++++++++++++++++++++++++++++---- 1 file changed, 132 insertions(+), 16 deletions(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index d479fa17c..29094e5c7 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -20,10 +20,6 @@ to validator withdrawals. Including: ## Custom types -| Name | SSZ equivalent | Description | -| - | - | - | -| `WithdrawalReceiptIndex` | `uint64` | a withdrawal receipt index | - ## Constants ## Preset @@ -32,7 +28,14 @@ to validator withdrawals. Including: | Name | Value | Unit | Duration | | - | - | :-: | :-: | -| `WITHDRAWAL_RECEIPT_LIMIT` | `uint64(2**40)` (= 1,099,511,627,776) | withdrawal receipts| +| `WITHDRAWAL_TRANSACTION_LIMIT` | `uint64(2**40)` (= 1,099,511,627,776) | withdrawal transactions enqueued in state| + +### Execution + +| Name | Value | Description | +| - | - | - | +| `WITHDRAWAL_TX_TYPE` | `Bytes1(0x05)` | EIP-2718 TX Type | +| `MAX_WITHDRAWAL_TRANSACTIONS_PER_PAYLOAD` | `uint64(2**4)` (= 16) | Maximum amount of withdrawal transactions allowed in each payload | ## Configuration @@ -56,7 +59,6 @@ class Validator(Container): withdrawn_epoch: Epoch # [New in Capella] ``` - #### `BeaconState` ```python @@ -98,18 +100,66 @@ class BeaconState(Container): # Execution latest_execution_payload_header: ExecutionPayloadHeader # Withdrawals - withdrawal_receipts: List[WithdrawalReceipt, WITHDRAWAL_RECEIPT_LIMIT] # [New in Capella] + withdrawal_receipts: List[WithdrawalTransaction, WITHDRAWAL_TRANSACTION_LIMIT] # [New in Capella] +``` + +#### `ExecutionPayload` + +```python +class ExecutionPayload(Container): + # Execution block header fields + parent_hash: Hash32 + fee_recipient: ExecutionAddress # 'beneficiary' in the yellow paper + state_root: Bytes32 + receipt_root: Bytes32 # 'receipts root' in the yellow paper + logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + random: Bytes32 # 'difficulty' in the yellow paper + block_number: uint64 # 'number' in the yellow paper + gas_limit: uint64 + gas_used: uint64 + timestamp: uint64 + extra_data: ByteList[MAX_EXTRA_DATA_BYTES] + base_fee_per_gas: uint256 + # Extra payload fields + block_hash: Hash32 # Hash of execution block + transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] + withdrawal_transactions: List[WithdrawalTransaction, MAX_WITHDRAWAL_TRANSACTIONS_PER_PAYLOAD] # [New in Capella] +``` + +#### `ExecutionPayloadHeader` + +```python +class ExecutionPayloadHeader(Container): + # Execution block header fields + parent_hash: Hash32 + fee_recipient: ExecutionAddress + state_root: Bytes32 + receipt_root: Bytes32 + logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + random: Bytes32 + block_number: uint64 + gas_limit: uint64 + gas_used: uint64 + timestamp: uint64 + extra_data: ByteList[MAX_EXTRA_DATA_BYTES] + base_fee_per_gas: uint256 + # Extra payload fields + block_hash: Hash32 # Hash of execution block + transactions_root: Root + withdrawal_transactions_root: Root # [New in Capella] ``` ### New containers -#### `WithdrawalReceipt` +#### `WithdrawalTransaction` + +New EIP-2718 transaction type, with the format being the single byte `WITHDRAWAL_TX_TYPE` +followed by an SSZ encoding of the `WithdrawalTransaction` container comprising the transaction contents. ```python -class WithdrawalReceipt(Container): - index: WithdrawalReceiptIndex +class WithdrawalTransaction(Container): address: ExecutionAddress - amount: Gwei + value: Gwei ``` ## Helpers @@ -123,8 +173,7 @@ def withdraw(state: BeaconState, index: ValidatorIndex, amount: Gwei) -> None: # Decrease the validator's balance decrease_balance(state, index, amount) # Create a corresponding withdrawal receipt - receipt = WithdrawalReceipt( - index=WithdrawalReceiptIndex(len(state.withdrawal_receipts)), + receipt = WithdrawalTransaction( address=state.validators[index].withdrawal_credentials[12:], amount=amount, ) @@ -162,15 +211,15 @@ def process_epoch(state: BeaconState) -> None: process_historical_roots_update(state) process_participation_flag_updates(state) process_sync_committee_updates(state) - process_withdrawals(state) # [New in Capella] + process_full_withdrawals(state) # [New in Capella] ``` #### Withdrawals -*Note*: The function `process_withdrawals` is new. +*Note*: The function `process_full_withdrawals` is new. ```python -def process_withdrawals(state: BeaconState) -> None: +def process_full_withdrawals(state: BeaconState) -> None: current_epoch = get_current_epoch(state) for index, validator in enumerate(state.validators): if is_withdrawable_validator(validator, current_epoch): @@ -178,3 +227,70 @@ def process_withdrawals(state: BeaconState) -> None: withdraw(state, ValidatorIndex(index), state.balances[index]) validator.withdrawn_epoch = current_epoch ``` + +### Block processing + +```python +def process_block(state: BeaconState, block: BeaconBlock) -> None: + process_block_header(state, block) + process_withdrawal_transactions(state, block.body.execution_payload) # [New in Capella] + process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Capella] + process_randao(state, block.body) + process_eth1_data(state, block.body) + process_operations(state, block.body) + process_sync_aggregate(state, block.body.sync_aggregate) +``` + +#### New `process_withdrawal_transactions` + +```python +def process_withdrawal_transactions(state: BeaconState, payload: ExecutionPayload) -> None: + num_withdrawal_transactions = min(MAX_WITHDRAWAL_TRANSACTIONS_PER_PAYLOAD, len(state.withdrawal_receipts)) + dequeued_withdrawal_receipts = state.withdrawal_receipts[:num_withdrawal_transactions] + + assert len(dequeued_withdrawal_receipts) == len(payload.withdrawal_transactions) + for dequeued_receipt, withdrawal_transaction in zip(dequeued_withdrawal_receipts, payload.withdrawal_transactions): + assert dequeued_receipt == withdrawal_transaction + + # Ensure no withdrawal type transactions in the normal payload transactions + # assert no_withdrawal_type_transactions_in(payload.transactions) + + # Remove dequeued receipts from state + state.withdrawal_receipts = state.withdrawal_receipts[num_withdrawal_transactions:] +``` + +#### Modified `process_execution_payload` + +*Note*: The function `process_execution_payload` is modified to use the new `ExecutionPayloadHeader` type. + +```python +def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None: + # Verify consistency of the parent hash with respect to the previous execution payload header + if is_merge_transition_complete(state): + assert payload.parent_hash == state.latest_execution_payload_header.block_hash + # Verify random + assert payload.random == get_randao_mix(state, get_current_epoch(state)) + # Verify timestamp + assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) + # Verify the execution payload is valid + assert execution_engine.execute_payload(payload) + # Cache execution payload header + state.latest_execution_payload_header = ExecutionPayloadHeader( + parent_hash=payload.parent_hash, + fee_recipient=payload.fee_recipient, + state_root=payload.state_root, + receipt_root=payload.receipt_root, + logs_bloom=payload.logs_bloom, + random=payload.random, + block_number=payload.block_number, + gas_limit=payload.gas_limit, + gas_used=payload.gas_used, + timestamp=payload.timestamp, + extra_data=payload.extra_data, + base_fee_per_gas=payload.base_fee_per_gas, + block_hash=payload.block_hash, + transactions_root=hash_tree_root(payload.transactions), + withdrawal_transactions=hash_tree_root(payload.withdrawal_transactions), + ) +``` +