Skip to content

Commit

Permalink
add eth1 withdrawal credentials to spec
Browse files Browse the repository at this point in the history
  • Loading branch information
djrtwo committed Dec 11, 2020
1 parent 99934ee commit 2b3e2de
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 9 deletions.
4 changes: 4 additions & 0 deletions specs/phase0/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,11 @@ The following values are (non-configurable) constants used throughout the specif
| Name | Value |
| - | - |
| `GENESIS_FORK_VERSION` | `Version('0x00000000')` |

### Validator withdrawal credential versions

| `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` |
| `ETH1_ADDRESS_WITHDRAWAL_PREFIX` | `Bytes1('0x01')` |

### Time parameters

Expand Down
13 changes: 9 additions & 4 deletions specs/phase0/deposit-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,17 @@ The amount of ETH (rounded down to the closest Gwei) sent to the deposit contrac

#### Withdrawal credentials

One of the `DepositData` fields is `withdrawal_credentials`. It is a commitment to credentials for withdrawing validator balance (e.g. to another validator, or to shards). The first byte of `withdrawal_credentials` is a version number. As of now, the only expected format is as follows:
One of the `DepositData` fields is `withdrawal_credentials`.

* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX`
* `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]` where `withdrawal_pubkey` is a BLS pubkey
This field is a commitment to credentials for withdrawing validator balance (e.g. to another validator, or to shards).
The first byte of `withdrawal_credentials` is a version number. The remaining
bytes are content specific to the version.

The private key corresponding to `withdrawal_pubkey` will be required to initiate a withdrawal. It can be stored separately until a withdrawal is required, e.g. in cold storage.
Currently, `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX`
versioned withdrawal credentials are supported. Read more in the [validator guide](./validator.md).

*Note*: The deposit contract does *not* validate withdrawal credentials.
Thus, new versions can be added without modifications of the deposit contract.

#### `DepositEvent` log

Expand Down
36 changes: 31 additions & 5 deletions specs/phase0/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,40 @@ A validator must initialize many parameters locally before submitting a deposit

Validator public keys are [G1 points](beacon-chain.md#bls-signatures) on the [BLS12-381 curve](https://z.cash/blog/new-snark-curve). A private key, `privkey`, must be securely generated along with the resultant `pubkey`. This `privkey` must be "hot", that is, constantly available to sign data throughout the lifetime of the validator.

#### BLS withdrawal key
#### Withdrawal credentials

A secondary withdrawal private key, `withdrawal_privkey`, must also be securely generated along with the resultant `withdrawal_pubkey`. This `withdrawal_privkey` does not have to be available for signing during the normal lifetime of a validator and can live in "cold storage".
The `withdrawal_credentials` ultimately control the deposited ETH once the
validator has exited and is withdrawable. The 0th byte of this 32-byte field,
called the "withdrawal prefix" defines the withdrawal credential version
while the remaining 31 bytes define the version-specific content.

The validator constructs their `withdrawal_credentials` via the following:
The following withdrawal credentials versions are currently supported. The
validator must choose and construct a version for the `withdrawal_credentials` field.

* Set `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX`.
* Set `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]`.
##### BLS key credentials

BLS withdrawal credentials are controlled by a secondary withdrawal BLS private key, `bls_withdrawal_privkey`.
This key is securely generated along with the resultant `bls_withdrawal_pubkey`.
This `withdrawal_privkey` does not have to be available for signing during
the normal lifetime of a validator and can live in "cold storage".

The validator constructs `withdrawal_credentials` as the following:
* Set `withdrawal_credentials[:1] = BLS_WITHDRAWAL_PREFIX`.
* Set `withdrawal_credentials[1:] = hash(bls_withdrawal_pubkey)[1:]`.

##### Eth1 address credentials

Eth1 address credentials are controlled by an eth1 address. This can be an either an externally owned account or a contract.

The withdrawal to the address specified will be a normal ETH transfer with no payload other than the validator's ETH.
As long as such a account/contract can receive ETH transfers,
the future withdrawal protocol is agnostic to all other implementation details.

The validator selects a 20-byte eth1 address, `eth1_withdrawal_address`, and constructs `withdrawal_credentials` as the following:
* Set `withdrawal_credentials[:1] = ETH1_ADDRESS_WITHDRAWAL_PREFIX`.
* Set `withdrawal_credentials[12:] = eth1_withdrawal_address`.

*Note*: Bytes `withdrawal_credentials[1:12]` remain the default `0x00` value.

### Submit deposit

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,49 @@ def test_new_deposit_over_max(spec, state):
yield from run_deposit_processing(spec, state, deposit, validator_index)


@with_all_phases
@spec_state_test
def test_new_deposit_eth1_withdrawal_credentials(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
withdrawal_credentials = (
spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX
+ b'\x00' * 11 # specified 0s
+ b'\x59' * 20 # a 20-byte eth1 address
)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(
spec, state,
validator_index,
amount,
withdrawal_credentials=withdrawal_credentials,
signed=True,
)

yield from run_deposit_processing(spec, state, deposit, validator_index)


@with_all_phases
@spec_state_test
def test_new_deposit_non_versioned_withdrawal_credentials(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
withdrawal_credentials = (
b'\xFF' # Non specified withdrawal credentials version
+ b'\x02' * 31 # Garabage bytes
)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(
spec, state,
validator_index,
amount,
withdrawal_credentials=withdrawal_credentials,
signed=True,
)

yield from run_deposit_processing(spec, state, deposit, validator_index)


@with_all_phases
@spec_state_test
@always_bls
Expand Down

0 comments on commit 2b3e2de

Please sign in to comment.