Merge pull request #3288 from dapplion/voluntary_exit-domain
EIP-7044: Lock voluntary exit domain on capella
This commit is contained in:
commit
14212958d3
|
@ -33,7 +33,8 @@
|
||||||
- [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload)
|
- [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload)
|
||||||
- [Block processing](#block-processing)
|
- [Block processing](#block-processing)
|
||||||
- [Execution payload](#execution-payload)
|
- [Execution payload](#execution-payload)
|
||||||
- [`process_execution_payload`](#process_execution_payload)
|
- [Modified `process_execution_payload`](#modified-process_execution_payload)
|
||||||
|
- [Modified `process_voluntary_exit`](#modified-process_voluntary_exit)
|
||||||
- [Testing](#testing)
|
- [Testing](#testing)
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
@ -42,7 +43,8 @@
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
Deneb is a consensus-layer upgrade containing a number of features. Including:
|
Deneb is a consensus-layer upgrade containing a number of features. Including:
|
||||||
* [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844): Shard Blob Transactions scale data-availability of Ethereum in a simple, forwards-compatible manner.
|
* [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844): Shard Blob Transactions scale data-availability of Ethereum in a simple, forwards-compatible manner
|
||||||
|
* [EIP-7044](https://github.com/ethereum/EIPs/pull/7044): Perpetually Valid Signed Voluntary Exits
|
||||||
|
|
||||||
## Custom types
|
## Custom types
|
||||||
|
|
||||||
|
@ -221,7 +223,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine,
|
||||||
|
|
||||||
#### Execution payload
|
#### Execution payload
|
||||||
|
|
||||||
##### `process_execution_payload`
|
##### Modified `process_execution_payload`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None:
|
def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None:
|
||||||
|
@ -266,6 +268,31 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Modified `process_voluntary_exit`
|
||||||
|
|
||||||
|
*Note*: The function `process_voluntary_exit` is modified to use the a fixed fork version -- `CAPELLA_FORK_VERSION` -- for EIP-7044
|
||||||
|
|
||||||
|
```python
|
||||||
|
def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
|
||||||
|
voluntary_exit = signed_voluntary_exit.message
|
||||||
|
validator = state.validators[voluntary_exit.validator_index]
|
||||||
|
# Verify the validator is active
|
||||||
|
assert is_active_validator(validator, get_current_epoch(state))
|
||||||
|
# Verify exit has not been initiated
|
||||||
|
assert validator.exit_epoch == FAR_FUTURE_EPOCH
|
||||||
|
# Exits must specify an epoch when they become valid; they are not valid before then
|
||||||
|
assert get_current_epoch(state) >= voluntary_exit.epoch
|
||||||
|
# Verify the validator has been active long enough
|
||||||
|
assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
|
||||||
|
# Verify signature
|
||||||
|
# [Modified in Deneb:EIP7044]
|
||||||
|
domain = compute_domain(DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root)
|
||||||
|
signing_root = compute_signing_root(voluntary_exit, domain)
|
||||||
|
assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
|
||||||
|
# Initiate exit
|
||||||
|
initiate_validator_exit(state, voluntary_exit.validator_index)
|
||||||
|
```
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only.
|
*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only.
|
||||||
|
|
|
@ -2,6 +2,11 @@ from eth2spec.test.context import (
|
||||||
spec_state_test,
|
spec_state_test,
|
||||||
always_bls,
|
always_bls,
|
||||||
with_bellatrix_and_later,
|
with_bellatrix_and_later,
|
||||||
|
with_phases,
|
||||||
|
)
|
||||||
|
from eth2spec.test.helpers.constants import (
|
||||||
|
BELLATRIX,
|
||||||
|
CAPELLA,
|
||||||
)
|
)
|
||||||
from eth2spec.test.helpers.keys import pubkey_to_privkey
|
from eth2spec.test.helpers.keys import pubkey_to_privkey
|
||||||
from eth2spec.test.helpers.state import (
|
from eth2spec.test.helpers.state import (
|
||||||
|
@ -12,8 +17,10 @@ from eth2spec.test.helpers.voluntary_exits import (
|
||||||
sign_voluntary_exit,
|
sign_voluntary_exit,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
BELLATRIX_AND_CAPELLA = [BELLATRIX, CAPELLA]
|
||||||
|
|
||||||
def _run_voluntary_exit_processing_test(
|
|
||||||
|
def run_voluntary_exit_processing_test(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
fork_version,
|
fork_version,
|
||||||
|
@ -51,7 +58,7 @@ def _run_voluntary_exit_processing_test(
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
@always_bls
|
@always_bls
|
||||||
def test_invalid_voluntary_exit_with_current_fork_version_is_before_fork_epoch(spec, state):
|
def test_invalid_voluntary_exit_with_current_fork_version_is_before_fork_epoch(spec, state):
|
||||||
yield from _run_voluntary_exit_processing_test(
|
yield from run_voluntary_exit_processing_test(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
fork_version=state.fork.current_version,
|
fork_version=state.fork.current_version,
|
||||||
|
@ -60,11 +67,11 @@ def test_invalid_voluntary_exit_with_current_fork_version_is_before_fork_epoch(s
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@with_bellatrix_and_later
|
@with_phases(BELLATRIX_AND_CAPELLA)
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
@always_bls
|
@always_bls
|
||||||
def test_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec, state):
|
def test_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec, state):
|
||||||
yield from _run_voluntary_exit_processing_test(
|
yield from run_voluntary_exit_processing_test(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
fork_version=state.fork.current_version,
|
fork_version=state.fork.current_version,
|
||||||
|
@ -72,13 +79,13 @@ def test_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@with_bellatrix_and_later
|
@with_phases([BELLATRIX, CAPELLA])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
@always_bls
|
@always_bls
|
||||||
def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state):
|
def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state):
|
||||||
assert state.fork.previous_version != state.fork.current_version
|
assert state.fork.previous_version != state.fork.current_version
|
||||||
|
|
||||||
yield from _run_voluntary_exit_processing_test(
|
yield from run_voluntary_exit_processing_test(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
fork_version=state.fork.previous_version,
|
fork_version=state.fork.previous_version,
|
||||||
|
@ -86,13 +93,13 @@ def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, st
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@with_bellatrix_and_later
|
@with_phases(BELLATRIX_AND_CAPELLA)
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
@always_bls
|
@always_bls
|
||||||
def test_invalid_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state):
|
def test_invalid_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state):
|
||||||
assert state.fork.previous_version != state.fork.current_version
|
assert state.fork.previous_version != state.fork.current_version
|
||||||
|
|
||||||
yield from _run_voluntary_exit_processing_test(
|
yield from run_voluntary_exit_processing_test(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
fork_version=state.fork.previous_version,
|
fork_version=state.fork.previous_version,
|
||||||
|
@ -107,7 +114,7 @@ def test_invalid_voluntary_exit_with_previous_fork_version_not_is_before_fork_ep
|
||||||
def test_invalid_voluntary_exit_with_genesis_fork_version_is_before_fork_epoch(spec, state):
|
def test_invalid_voluntary_exit_with_genesis_fork_version_is_before_fork_epoch(spec, state):
|
||||||
assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version)
|
assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version)
|
||||||
|
|
||||||
yield from _run_voluntary_exit_processing_test(
|
yield from run_voluntary_exit_processing_test(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
fork_version=spec.config.GENESIS_FORK_VERSION,
|
fork_version=spec.config.GENESIS_FORK_VERSION,
|
||||||
|
@ -122,7 +129,7 @@ def test_invalid_voluntary_exit_with_genesis_fork_version_is_before_fork_epoch(s
|
||||||
def test_invalid_voluntary_exit_with_genesis_fork_version_not_is_before_fork_epoch(spec, state):
|
def test_invalid_voluntary_exit_with_genesis_fork_version_not_is_before_fork_epoch(spec, state):
|
||||||
assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version)
|
assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version)
|
||||||
|
|
||||||
yield from _run_voluntary_exit_processing_test(
|
yield from run_voluntary_exit_processing_test(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
fork_version=spec.config.GENESIS_FORK_VERSION,
|
fork_version=spec.config.GENESIS_FORK_VERSION,
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
from eth2spec.test.context import (
|
||||||
|
always_bls,
|
||||||
|
spec_state_test,
|
||||||
|
with_phases,
|
||||||
|
with_deneb_and_later,
|
||||||
|
)
|
||||||
|
from eth2spec.test.helpers.constants import (
|
||||||
|
DENEB,
|
||||||
|
)
|
||||||
|
from eth2spec.test.bellatrix.block_processing.test_process_voluntary_exit import (
|
||||||
|
run_voluntary_exit_processing_test,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_invalid_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec, state):
|
||||||
|
"""
|
||||||
|
Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION`
|
||||||
|
"""
|
||||||
|
assert state.fork.current_version != spec.config.CAPELLA_FORK_VERSION
|
||||||
|
yield from run_voluntary_exit_processing_test(
|
||||||
|
spec,
|
||||||
|
state,
|
||||||
|
fork_version=state.fork.current_version,
|
||||||
|
is_before_fork_epoch=False,
|
||||||
|
valid=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state):
|
||||||
|
"""
|
||||||
|
Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION`
|
||||||
|
|
||||||
|
Note: This test is valid for ``spec.fork == DENEB`` and invalid for subsequent forks
|
||||||
|
"""
|
||||||
|
assert state.fork.previous_version != state.fork.current_version
|
||||||
|
|
||||||
|
if spec.fork == DENEB:
|
||||||
|
assert state.fork.previous_version == spec.config.CAPELLA_FORK_VERSION
|
||||||
|
yield from run_voluntary_exit_processing_test(
|
||||||
|
spec,
|
||||||
|
state,
|
||||||
|
fork_version=state.fork.previous_version,
|
||||||
|
is_before_fork_epoch=False,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert state.fork.previous_version != spec.config.CAPELLA_FORK_VERSION
|
||||||
|
yield from run_voluntary_exit_processing_test(
|
||||||
|
spec,
|
||||||
|
state,
|
||||||
|
fork_version=state.fork.previous_version,
|
||||||
|
is_before_fork_epoch=False,
|
||||||
|
valid=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state):
|
||||||
|
"""
|
||||||
|
Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION`
|
||||||
|
|
||||||
|
Note: This test is valid for ``spec.fork == DENEB`` and invalid for subsequent forks
|
||||||
|
"""
|
||||||
|
assert state.fork.previous_version != state.fork.current_version
|
||||||
|
|
||||||
|
if spec.fork == DENEB:
|
||||||
|
assert state.fork.previous_version == spec.config.CAPELLA_FORK_VERSION
|
||||||
|
yield from run_voluntary_exit_processing_test(
|
||||||
|
spec,
|
||||||
|
state,
|
||||||
|
fork_version=state.fork.previous_version,
|
||||||
|
is_before_fork_epoch=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert state.fork.previous_version != spec.config.CAPELLA_FORK_VERSION
|
||||||
|
yield from run_voluntary_exit_processing_test(
|
||||||
|
spec,
|
||||||
|
state,
|
||||||
|
fork_version=state.fork.previous_version,
|
||||||
|
is_before_fork_epoch=True,
|
||||||
|
valid=False,
|
||||||
|
)
|
|
@ -1,29 +1,31 @@
|
||||||
from random import Random
|
from random import Random
|
||||||
from eth2spec.utils import bls
|
from eth2spec.utils import bls
|
||||||
from eth2spec.test.context import expect_assertion_error
|
from eth2spec.test.context import expect_assertion_error
|
||||||
|
from eth2spec.test.helpers.forks import is_post_deneb
|
||||||
from eth2spec.test.helpers.keys import privkeys
|
from eth2spec.test.helpers.keys import privkeys
|
||||||
|
|
||||||
|
|
||||||
def prepare_signed_exits(spec, state, indices, fork_version=None):
|
def prepare_signed_exits(spec, state, indices, fork_version=None):
|
||||||
if fork_version is None:
|
|
||||||
domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT)
|
|
||||||
else:
|
|
||||||
domain = spec.compute_domain(spec.DOMAIN_VOLUNTARY_EXIT, fork_version, state.genesis_validators_root)
|
|
||||||
|
|
||||||
def create_signed_exit(index):
|
def create_signed_exit(index):
|
||||||
exit = spec.VoluntaryExit(
|
voluntary_exit = spec.VoluntaryExit(
|
||||||
epoch=spec.get_current_epoch(state),
|
epoch=spec.get_current_epoch(state),
|
||||||
validator_index=index,
|
validator_index=index,
|
||||||
)
|
)
|
||||||
signing_root = spec.compute_signing_root(exit, domain)
|
return sign_voluntary_exit(spec, state, voluntary_exit, privkeys[index], fork_version=fork_version)
|
||||||
return spec.SignedVoluntaryExit(message=exit, signature=bls.Sign(privkeys[index], signing_root))
|
|
||||||
|
|
||||||
return [create_signed_exit(index) for index in indices]
|
return [create_signed_exit(index) for index in indices]
|
||||||
|
|
||||||
|
|
||||||
def sign_voluntary_exit(spec, state, voluntary_exit, privkey, fork_version=None):
|
def sign_voluntary_exit(spec, state, voluntary_exit, privkey, fork_version=None):
|
||||||
if fork_version is None:
|
if fork_version is None:
|
||||||
domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
if is_post_deneb(spec):
|
||||||
|
domain = spec.compute_domain(
|
||||||
|
spec.DOMAIN_VOLUNTARY_EXIT,
|
||||||
|
spec.config.CAPELLA_FORK_VERSION,
|
||||||
|
state.genesis_validators_root,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
||||||
else:
|
else:
|
||||||
domain = spec.compute_domain(spec.DOMAIN_VOLUNTARY_EXIT, fork_version, state.genesis_validators_root)
|
domain = spec.compute_domain(spec.DOMAIN_VOLUNTARY_EXIT, fork_version, state.genesis_validators_root)
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
_new_deneb_mods = {key: 'eth2spec.test.deneb.block_processing.test_process_' + key for key in [
|
_new_deneb_mods = {key: 'eth2spec.test.deneb.block_processing.test_process_' + key for key in [
|
||||||
'execution_payload',
|
'execution_payload',
|
||||||
|
'voluntary_exit',
|
||||||
]}
|
]}
|
||||||
deneb_mods = combine_mods(_new_deneb_mods, capella_mods)
|
deneb_mods = combine_mods(_new_deneb_mods, capella_mods)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue