From 25b6116c94279033fb5a48398c455117b06431c1 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Thu, 31 Oct 2024 16:00:45 +1300 Subject: [PATCH 1/4] Initial draft EIP-7800 --- EIPS/eip-7800.md | 220 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 EIPS/eip-7800.md diff --git a/EIPS/eip-7800.md b/EIPS/eip-7800.md new file mode 100644 index 0000000000000..f6ba144babd89 --- /dev/null +++ b/EIPS/eip-7800.md @@ -0,0 +1,220 @@ +--- +eip: XXXX +title: Withdrawal Credential Update Request +description: Allow validators to update their withdrawal credentials via execution requests +author: lucassaldanha (@lucassaldanha) +discussions-to: https://ethereum-magicians.org/t/ +status: Draft +type: Standards Track +category: Core +created: 2024-10-31 +--- + +## Abstract + +This proposal defines a mechanism to allow validators to update their withdrawal +credentials using a new execution request type (0x03). The request allows for +changing the execution address and the withdrawal credential prefix (0x01 or 0x02). + +## Motivation + +When the ability to update a validator BLS withdrawal credentials to execution +address was introduced in Capella, one of the most common questions was about +allowing the withdrawal credential to be changed in the future. +Either for security (e.g. credential rotation) or to allow for alternative ways +of handling withdrawals (e.g. having a contract address as credentials). +The main reason for not adding this options was because the complexity of implementing +this communication channel between the Execution Layer and the Consensus Layer was +complicated (based on the experience with the Eth1 bridge). + +In Electra, the protocol was upgraded with Execution Requests (deposits, withdrawals and +consolidations), and a mechanism for general purpose execution requests +[EIP-7685](https://eips.ethereum.org/EIPS/eip-7685), decreasing the complexity of adding +a new request from execution to consensus layer. + +The introduction of execution requests that are created on the execution layer, +opened up possibilities on how validators can be managed. +Execution request can be created via smart contracts, allowing for decentralized +and on-chain mechanisms to be explored. + +For an execution request to be authorized in the consensus layer, the withdrawal +credential of the validator must be the same of the `msg.caller` when processing +the transaction on the EVM. +So the validator's withdrawal credential must be the same address of the smart contract +creating the request (not the credential of the transaction sender), or the contract +needs to use `DELEGATECALL` to ensure the caller address matches the address in the +validator's withdrawal credential. +Validators that already have a contract address as their withdrawal credentials should +be able to update their contracts to meet this demand. + +There problems for existing validators that have their withdrawal credentials +set to an EOA account is they will never be able to use use smart contracts +for creating execution requests, because the current design does not allow for these +credentials to ever be changed. + +Allowing for validators to update their withdrawal credentials mean they can opt-in +and out of different schemes and strategies on managing their validators, favouring +experimentation and innovation. +Today, the only alternative to this is exitting the validator and creating a new +validator with different withdrawal credentials. + +Being able to update their withdrawal credentials also means they could move between +execution and compounding withdrawal credentials. This is not only benefitial due to +the flexibility it provides, but also solves problem that upon a validator consolidation +[EIP-7251](https://eips.ethereum.org/EIPS/eip-7251), the target validator withdrawal +credential is updated to 0x02, with no way to ever going back to 0x01. But because the +authentication of the message is only concerned with the source validator, a validator +can be forced to change to 0x02. If we implement the mechanism for them to change it +back 0x01, we solve this problem as well. + +## Specification + +### Constants + +| Name | Value | Comment | +| - | - | - | +|`FORK_TIMESTAMP` | *TBD* | Mainnet | + +### Configuration + +| Name | Value | Comment | +| - | - | - | +| `WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_PREDEPLOY_ADDRESS` | `0x09Fc772D0857550724b07B850a4323f39112aAaA` | Where to call and store relevant details about the withdrawal credentials update mechanism | +| `WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_TYPE` | `0x03` | The [EIP-7685](./eip-7685.md) type prefix for withdrawal credential update request | +| `SYSTEM_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffe` | Address used to invoke system operation on contract +| `EXCESS_WITHDRAWAL_CREDENTIALS_UPDATE_REQUESTS_STORAGE_SLOT` | 0 | | +| `WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_COUNT_STORAGE_SLOT` | 1 | | +| `WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_QUEUE_HEAD_STORAGE_SLOT` | 2 | Pointer to head of the withdrawal credential update request message queue | +| `WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_QUEUE_TAIL_STORAGE_SLOT` | 3 | Pointer to the tail of the withdrawal credential update request message queue| +| `WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_QUEUE_STORAGE_OFFSET` | 4 | The start memory slot of the in-state withdrawal credential update request message queue| +| `MAX_WITHDRAWAL_CREDENTIALS_UPDATE_REQUESTS_PER_BLOCK` | 4 | Maximum number of withdrawal credential update requests that can be dequeued into a block | +| `TARGET_WITHDRAWAL_CREDENTIALS_UPDATE_REQUESTS_PER_BLOCK` | 1 | | +| `MIN_WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_FEE` | 1 | | +| `WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_FEE_UPDATE_FRACTION` | 17 | | +| `EXCESS_INHIBITOR` | `2**256-1` | Excess value used to compute the fee before the first system call | + +### Execution Layer + +* **`FORK_BLOCK`** -- the first block in a blockchain with the `timestamp` greater or equal to `FORK_TIMESTAMP`. + +#### Withdrawal Credentials Update request operation + +The new withdrawal credential update request operation is an [EIP-7685](./eip-7685.md) request +with type `0x03` and consists of the following fields: + +1. `pubkey`: `Bytes48` +2. `old_address`: `Bytes20` +3. `new_address`: `Bytes20` + +The [EIP-7685](./eip-7685.md) encoding of a withdrawal credential update request is computed as follows. + +```python +request_type = WITHDRAWAL_CREDENTIALS_UPDATE_REQUEST_TYPE +request_data = read_withdrawal_credential_update_requests() +``` + +#### Withdrawal Credentials Update Request Contract + +The contract is similar to other execution requests contracts for Deposits, Withdrawals and Consolidation. +The contract has three different code paths, which can be summarized at a high level as follows: + +1. Add request - requires a `68` byte input, the validator's public key concatenated with the new address for withdrawal credentials. +2. Excess requests getter - if the input length is zero, return the current excess requests count. +3. System process - if called by system address, pop off the withdrawal credential update requests for the current block from the queue. + +_TODO: add sudo code / bytecode / deployment / etc_ (very similar to existing request contracts) + +#### Block processing + +At the end of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e. after processing all transactions and after performing the block body requests validations) client software **MUST** include a call the contract as `SYSTEM_ADDRESS` and empty input data to trigger the system subroutine execute. The resopnse should be treated as a new request type (0x03) according to [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). + +#### Block Validation + +EL must check that the commitment hash in the execution block header matches the hash of the list of execution requests the CL sends when +validating the execution block (including any requests of the the new defined type 0x03). + +### Consensus Layer + +[Full specification]() - TODO add link to PR + +Summary of changes: +- New container `WithdrawalCredentialUpdateRequest` +- New method in Block Processing: `process_withdrawal_credential_update_request` +- New Beacobn State mutator method: `update_withdrawal_credentials` + + +```python +class WithdrawalCredentialUpdateRequest(Container): + validator_pubkey: BLSPubkey + old_address: ExecutionAddress # request contract will set this to msg.caller + new_address: ExecutionAddress +``` + +```python +def process_withdrawal_credential_update_request(state: BeaconState, withdrawal_credentials_update_requests: WithdrawalCredentialUpdateRequest) -> None: + validator_pubkeys = [v.pubkey for v in state.validators] + # Verify pubkey exists + request_pubkey = withdrawal_credentials_update_requests.validator_pubkey + if request_pubkey not in validator_pubkeys: + return + index = ValidatorIndex(validator_pubkeys.index(request_pubkey)) + validator = state.validators[index] + + # Verify withdrawal credentials + has_correct_credential = has_execution_withdrawal_credential(validator) + is_correct_old_address = ( + validator.withdrawal_credentials[12:] == withdrawal_credentials_update_requests.old_address + ) + if not (has_correct_credential and is_correct_old_address): + return + + credential_type = withdrawal_credentials_update_requests.type + is_eth1_type = credential_type == ETH1_ADDRESS_WITHDRAWAL_PREFIX + is_compounding_type = credential_type == COMPOUNDING_WITHDRAWAL_PREFIX + # Verify valid type + if not (is_eth1_type or is_compounding_type): + return; + + update_withdrawal_credentials(state, index, credential_type, withdrawal_credentials_update_requests.new_address) +``` + +```python +def update_withdrawal_credentials(state: BeaconState, index: ValidatorIndex, new_credential_type: Bytes1, new_withdrawal_credentials: ExecutionAddress) -> None: + old_credential_type = validator.withdrawal_credentials[:1] + + validator = state.validators[index] + validator.withdrawal_credentials = ( + new_credential_type + + b'\x00' * 11 + + new_withdrawal_credentials + ) + + # If moving from 0x01 to 0x02 + if (old_credential_type == ETH1_ADDRESS_WITHDRAWAL_PREFIX and old_credential_type == COMPOUNDING_WITHDRAWAL_PREFIX) { + #TODO: in this case we need to ensure we put them through the churn/likely re-using some of the exiting rules + switch_to_compounding_validator(state, index) + } +``` + +## Rationale + +TODO + +## Backwards Compatibility + +TODO + +## Test Cases + +TODO + +## Security Considerations + +Ownership is defined based on control of the withdrawal credential account, either as a private key (for EOA accounts) or controlling +the smart contract at the address set as withdrawal credential. Therefore allowing an update should not bring any security implications. + +Futher discussion needed. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From 3374bca37d208a2669dc527c2fefd4048c5622c0 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Thu, 31 Oct 2024 16:26:23 +1300 Subject: [PATCH 2/4] Formatting --- EIPS/eip-7800.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/EIPS/eip-7800.md b/EIPS/eip-7800.md index f6ba144babd89..a871130fe6940 100644 --- a/EIPS/eip-7800.md +++ b/EIPS/eip-7800.md @@ -1,5 +1,5 @@ --- -eip: XXXX +eip: 7800 title: Withdrawal Credential Update Request description: Allow validators to update their withdrawal credentials via execution requests author: lucassaldanha (@lucassaldanha) @@ -29,7 +29,7 @@ complicated (based on the experience with the Eth1 bridge). In Electra, the protocol was upgraded with Execution Requests (deposits, withdrawals and consolidations), and a mechanism for general purpose execution requests -[EIP-7685](https://eips.ethereum.org/EIPS/eip-7685), decreasing the complexity of adding +[EIP-7685](./eip-7685.md), decreasing the complexity of adding a new request from execution to consensus layer. The introduction of execution requests that are created on the execution layer, @@ -61,7 +61,7 @@ validator with different withdrawal credentials. Being able to update their withdrawal credentials also means they could move between execution and compounding withdrawal credentials. This is not only benefitial due to the flexibility it provides, but also solves problem that upon a validator consolidation -[EIP-7251](https://eips.ethereum.org/EIPS/eip-7251), the target validator withdrawal +[EIP-7251](./eip-7251.md), the target validator withdrawal credential is updated to 0x02, with no way to ever going back to 0x01. But because the authentication of the message is only concerned with the source validator, a validator can be forced to change to 0x02. If we implement the mechanism for them to change it @@ -122,11 +122,11 @@ The contract has three different code paths, which can be summarized at a high l 2. Excess requests getter - if the input length is zero, return the current excess requests count. 3. System process - if called by system address, pop off the withdrawal credential update requests for the current block from the queue. -_TODO: add sudo code / bytecode / deployment / etc_ (very similar to existing request contracts) +TODO: add sudo code / bytecode / deployment / etc_ (very similar to existing request contracts) #### Block processing -At the end of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e. after processing all transactions and after performing the block body requests validations) client software **MUST** include a call the contract as `SYSTEM_ADDRESS` and empty input data to trigger the system subroutine execute. The resopnse should be treated as a new request type (0x03) according to [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685). +At the end of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e. after processing all transactions and after performing the block body requests validations) client software **MUST** include a call the contract as `SYSTEM_ADDRESS` and empty input data to trigger the system subroutine execute. The resopnse should be treated as a new request type (0x03) according to [EIP-7685](./eip-7685.md). #### Block Validation @@ -135,13 +135,13 @@ validating the execution block (including any requests of the the new defined ty ### Consensus Layer -[Full specification]() - TODO add link to PR +Full specification - TODO add link to PR Summary of changes: -- New container `WithdrawalCredentialUpdateRequest` -- New method in Block Processing: `process_withdrawal_credential_update_request` -- New Beacobn State mutator method: `update_withdrawal_credentials` +* New container `WithdrawalCredentialUpdateRequest` +* New method in Block Processing: `process_withdrawal_credential_update_request` +* New Beacon State mutator method: `update_withdrawal_credentials` ```python class WithdrawalCredentialUpdateRequest(Container): From ad89d33f23d552970989cf40140bb3186309ad16 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Thu, 31 Oct 2024 16:33:34 +1300 Subject: [PATCH 3/4] Add eth-magicians link --- EIPS/eip-7800.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-7800.md b/EIPS/eip-7800.md index a871130fe6940..0324a163b2171 100644 --- a/EIPS/eip-7800.md +++ b/EIPS/eip-7800.md @@ -3,7 +3,7 @@ eip: 7800 title: Withdrawal Credential Update Request description: Allow validators to update their withdrawal credentials via execution requests author: lucassaldanha (@lucassaldanha) -discussions-to: https://ethereum-magicians.org/t/ +discussions-to: https://ethereum-magicians.org/t/eip-7800-withdrawal-credential-update-request/21514 status: Draft type: Standards Track category: Core From c4652c0cecd4aa804c00d1fcbbf2731dfa535613 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 1 Nov 2024 07:42:15 +1300 Subject: [PATCH 4/4] Comments and correct number --- EIPS/{eip-7800.md => eip-7804.md} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename EIPS/{eip-7800.md => eip-7804.md} (97%) diff --git a/EIPS/eip-7800.md b/EIPS/eip-7804.md similarity index 97% rename from EIPS/eip-7800.md rename to EIPS/eip-7804.md index 0324a163b2171..31d17e04ad132 100644 --- a/EIPS/eip-7800.md +++ b/EIPS/eip-7804.md @@ -1,9 +1,9 @@ --- -eip: 7800 +eip: 7804 title: Withdrawal Credential Update Request description: Allow validators to update their withdrawal credentials via execution requests author: lucassaldanha (@lucassaldanha) -discussions-to: https://ethereum-magicians.org/t/eip-7800-withdrawal-credential-update-request/21514 +discussions-to: https://ethereum-magicians.org/t/eip-7804-withdrawal-credential-update-request/21514 status: Draft type: Standards Track category: Core @@ -23,9 +23,9 @@ address was introduced in Capella, one of the most common questions was about allowing the withdrawal credential to be changed in the future. Either for security (e.g. credential rotation) or to allow for alternative ways of handling withdrawals (e.g. having a contract address as credentials). -The main reason for not adding this options was because the complexity of implementing -this communication channel between the Execution Layer and the Consensus Layer was -complicated (based on the experience with the Eth1 bridge). +The main reason for not adding this options was because implementing +this communication channel between the Execution Layer and the Consensus Layer is +complex (based on the experience with the Eth1 bridge). In Electra, the protocol was upgraded with Execution Requests (deposits, withdrawals and consolidations), and a mechanism for general purpose execution requests