mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-02-03 14:24:24 +00:00
Merge remote-tracking branch 'origin/dev' into single-attestation
This commit is contained in:
commit
9bef69c4b5
6
.github/workflows/generate_vectors.yml
vendored
6
.github/workflows/generate_vectors.yml
vendored
@ -12,17 +12,19 @@ on:
|
||||
default: dev
|
||||
type: string
|
||||
required: true
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
jobs:
|
||||
generate-tests:
|
||||
runs-on: [self-hosted-ghr-custom, size-chungus-x64, profile-consensusSpecs]
|
||||
runs-on: [self-hosted-ghr-custom, size-xl-x64, profile-consensusSpecs]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'ethereum/consensus-specs'
|
||||
path: 'consensus-specs'
|
||||
ref: ${{ inputs.source_ref }}
|
||||
ref: ${{ inputs.ref || 'dev' }}
|
||||
- name: Checkout consensus-spec-tests repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
|
8
Makefile
8
Makefile
@ -96,6 +96,9 @@ dist_check:
|
||||
dist_upload:
|
||||
python3 -m twine upload dist/*
|
||||
|
||||
build_wheel: install_test pyspec
|
||||
. venv/bin/activate && \
|
||||
python3 -m build --no-isolation --outdir ./dist ./
|
||||
|
||||
# "make generate_tests" to run all generators
|
||||
generate_tests: $(GENERATOR_TARGETS)
|
||||
@ -195,7 +198,8 @@ define run_generator
|
||||
cd $(GENERATOR_DIR)/$(1); \
|
||||
if ! test -d venv; then python3 -m venv venv; fi; \
|
||||
. venv/bin/activate; \
|
||||
pip3 install -r requirements.txt; \
|
||||
pip3 install ../../../dist/eth2spec-*.whl; \
|
||||
pip3 install 'eth2spec[generator]'; \
|
||||
python3 main.py -o $(CURRENT_DIR)/$(TEST_VECTOR_DIR); \
|
||||
echo "generator $(1) finished"
|
||||
endef
|
||||
@ -217,7 +221,7 @@ gen_kzg_setups:
|
||||
|
||||
# For any generator, build it using the run_generator function.
|
||||
# (creation of output dir is a dependency)
|
||||
gen_%: $(TEST_VECTOR_DIR)
|
||||
gen_%: build_wheel $(TEST_VECTOR_DIR)
|
||||
$(call run_generator,$*)
|
||||
|
||||
detect_generator_incomplete: $(TEST_VECTOR_DIR)
|
||||
|
16
README.md
16
README.md
@ -73,3 +73,19 @@ Documentation on the different components used during spec writing can be found
|
||||
## Consensus spec tests
|
||||
|
||||
Conformance tests built from the executable python spec are available in the [Ethereum Proof-of-Stake Consensus Spec Tests](https://github.com/ethereum/consensus-spec-tests) repo. Compressed tarballs are available in [releases](https://github.com/ethereum/consensus-spec-tests/releases).
|
||||
|
||||
|
||||
## Installation and Usage
|
||||
The consensus-specs repo can be used by running the tests locally or inside a docker container.
|
||||
|
||||
To run the tests locally:
|
||||
- Clone the repository with `git clone https://github.com/ethereum/consensus-specs.git`
|
||||
- Switch to the directory `cd consensus-specs`
|
||||
- Install the dependencies with: `make install_test && make preinstallation && make pyspec`
|
||||
- Run the tests with `make citest`
|
||||
|
||||
To run the tests inside a docker container:
|
||||
- Switch to the directory with `cd scripts`
|
||||
- Run the script `./build_run_docker_tests.sh`
|
||||
- Find the results in a folder called `./testResults`
|
||||
- Find more ways to customize the script with `./build_run_docker_tests.sh --h`
|
@ -169,3 +169,6 @@ CUSTODY_REQUIREMENT: 4
|
||||
# [New in Electra:EIP7251]
|
||||
MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 # 2**7 * 10**9 (= 128,000,000,000)
|
||||
MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000 # 2**8 * 10**9 (= 256,000,000,000)
|
||||
|
||||
# EIP7732
|
||||
MAX_REQUEST_PAYLOADS: 128
|
||||
|
@ -168,3 +168,6 @@ CUSTODY_REQUIREMENT: 4
|
||||
# [New in Electra:EIP7251]
|
||||
MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000 # 2**6 * 10**9 (= 64,000,000,000)
|
||||
MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000 # 2**7 * 10**9 (= 128,000,000,000)
|
||||
|
||||
# EIP7732
|
||||
MAX_REQUEST_PAYLOADS: 128
|
||||
|
@ -13,8 +13,8 @@ Ideally manual running of docker containers is for advanced users, we recommend
|
||||
The `scripts/build_run_docker_tests.sh` script will cover most usecases. The script allows the user to configure the fork(altair/bellatrix/capella..), `$IMAGE_NAME` (specifies the container to use), preset type (mainnet/minimal), and test all forks flags. Ideally, this is the main way that users interact with the spec tests instead of running it locally with varying versions of dependencies.
|
||||
|
||||
E.g:
|
||||
- `./build_run_test.sh --p mainnet` will run the mainnet preset tests
|
||||
- `./build_run_test.sh --a` will run all the tests across all the forks
|
||||
- `./build_run_test.sh --f deneb` will only run deneb tests
|
||||
- `./build_run_docker_tests.sh --p mainnet` will run the mainnet preset tests
|
||||
- `./build_run_docker_tests.sh --a` will run all the tests across all the forks
|
||||
- `./build_run_docker_tests.sh --f deneb` will only run deneb tests
|
||||
|
||||
Results are always placed in a folder called `./testResults`. The results are `.xml` files and contain the fork they represent and the date/time they were run at.
|
@ -19,3 +19,41 @@ from eth2spec.deneb import {preset_name} as deneb
|
||||
'CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(86)',
|
||||
'NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(87)',
|
||||
}
|
||||
|
||||
|
||||
@classmethod
|
||||
def execution_engine_cls(cls) -> str:
|
||||
return """
|
||||
class NoopExecutionEngine(ExecutionEngine):
|
||||
|
||||
def notify_new_payload(self: ExecutionEngine,
|
||||
execution_payload: ExecutionPayload,
|
||||
execution_requests: ExecutionRequests,
|
||||
parent_beacon_block_root: Root) -> bool:
|
||||
return True
|
||||
|
||||
def notify_forkchoice_updated(self: ExecutionEngine,
|
||||
head_block_hash: Hash32,
|
||||
safe_block_hash: Hash32,
|
||||
finalized_block_hash: Hash32,
|
||||
payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]:
|
||||
pass
|
||||
|
||||
def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadResponse:
|
||||
# pylint: disable=unused-argument
|
||||
raise NotImplementedError("no default block production")
|
||||
|
||||
def is_valid_block_hash(self: ExecutionEngine,
|
||||
execution_payload: ExecutionPayload,
|
||||
parent_beacon_block_root: Root) -> bool:
|
||||
return True
|
||||
|
||||
def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool:
|
||||
return True
|
||||
|
||||
def verify_and_notify_new_payload(self: ExecutionEngine,
|
||||
new_payload_request: NewPayloadRequest) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
EXECUTION_ENGINE = NoopExecutionEngine()"""
|
@ -1,4 +1,5 @@
|
||||
pip>=24.0.0
|
||||
wheel>=0.44.0
|
||||
setuptools>=72.0.0
|
||||
pylint>=3.2.0
|
||||
pylint>=3.2.0
|
||||
build>=1.2.2
|
@ -10,7 +10,7 @@
|
||||
|
||||
|
||||
# Set variables
|
||||
ALL_EXECUTABLE_SPECS=("phase0" "altair" "bellatrix" "capella" "deneb" "electra" "whisk")
|
||||
ALL_EXECUTABLE_SPECS=("phase0" "altair" "bellatrix" "capella" "deneb" "electra" "whisk" "eip7594")
|
||||
TEST_PRESET_TYPE=minimal
|
||||
FORK_TO_TEST=phase0
|
||||
WORKDIR="//consensus-specs//tests//core//pyspec"
|
||||
|
22
setup.py
22
setup.py
@ -524,32 +524,36 @@ setup(
|
||||
long_description=readme,
|
||||
long_description_content_type="text/markdown",
|
||||
author="ethereum",
|
||||
url="https://github.com/ethereum/eth2.0-specs",
|
||||
url="https://github.com/ethereum/consensus-specs",
|
||||
include_package_data=False,
|
||||
package_data={'configs': ['*.yaml'],
|
||||
'presets': ['*.yaml'],
|
||||
'specs': ['**/*.md'],
|
||||
'eth2spec': ['VERSION.txt']},
|
||||
package_data={
|
||||
'configs': ['*.yaml'],
|
||||
'eth2spec': ['VERSION.txt'],
|
||||
'presets': ['**/*.yaml', '**/*.json'],
|
||||
'specs': ['**/*.md'],
|
||||
'sync': ['optimistic.md'],
|
||||
},
|
||||
package_dir={
|
||||
"eth2spec": "tests/core/pyspec/eth2spec",
|
||||
"configs": "configs",
|
||||
"eth2spec": "tests/core/pyspec/eth2spec",
|
||||
"presets": "presets",
|
||||
"specs": "specs",
|
||||
"sync": "sync",
|
||||
},
|
||||
packages=find_packages(where='tests/core/pyspec') + ['configs', 'specs'],
|
||||
packages=find_packages(where='tests/core/pyspec') + ['configs', 'presets', 'specs', 'presets', 'sync'],
|
||||
py_modules=["eth2spec"],
|
||||
cmdclass=commands,
|
||||
python_requires=">=3.9, <4",
|
||||
extras_require={
|
||||
"test": ["pytest>=4.4", "pytest-cov", "pytest-xdist"],
|
||||
"lint": ["flake8==5.0.4", "mypy==0.981", "pylint==2.15.3"],
|
||||
"generator": ["python-snappy==0.6.1", "filelock", "pathos==0.3.0"],
|
||||
"generator": ["setuptools>=72.0.0", "pytest>4.4", "python-snappy==0.7.3", "filelock", "pathos==0.3.0"],
|
||||
"docs": ["mkdocs==1.4.2", "mkdocs-material==9.1.5", "mdx-truly-sane-lists==1.3", "mkdocs-awesome-pages-plugin==2.8.0"]
|
||||
},
|
||||
install_requires=[
|
||||
"eth-utils>=2.0.0,<3",
|
||||
"eth-typing>=3.2.0,<4.0.0",
|
||||
"pycryptodome==3.15.0",
|
||||
"pycryptodome>=3.19.1",
|
||||
"py_ecc==6.0.0",
|
||||
"milagro_bls_binding==1.9.0",
|
||||
"remerkleable==0.1.28",
|
||||
|
@ -67,7 +67,7 @@ The following values are (non-configurable) constants used throughout the specif
|
||||
|
||||
| Name | Value | Description |
|
||||
| - | - | - |
|
||||
| `DATA_COLUMN_SIDECAR_SUBNET_COUNT` | `128` | The number of data column sidecar subnets used in the gossipsub protocol |
|
||||
| `DATA_COLUMN_SIDECAR_SUBNET_COUNT` | `uint64(128)` | The number of data column sidecar subnets used in the gossipsub protocol |
|
||||
|
||||
### Custody setting
|
||||
|
||||
@ -222,7 +222,7 @@ def get_data_column_sidecars(signed_block: SignedBeaconBlock,
|
||||
|
||||
Each node downloads and custodies a minimum of `CUSTODY_REQUIREMENT` subnets per slot. The particular subnets that the node is required to custody are selected pseudo-randomly (more on this below).
|
||||
|
||||
A node *may* choose to custody and serve more than the minimum honesty requirement. Such a node explicitly advertises a number greater than `CUSTODY_REQUIREMENT` via the peer discovery mechanism -- for example, in their ENR (e.g. `custody_subnet_count: 4` if the node custodies `4` subnets each slot) -- up to a `DATA_COLUMN_SIDECAR_SUBNET_COUNT` (i.e. a super-full node).
|
||||
A node *may* choose to custody and serve more than the minimum honesty requirement. Such a node explicitly advertises a number greater than `CUSTODY_REQUIREMENT` through the peer discovery mechanism, specifically by setting a higher value in the `custody_subnet_count` field within its ENR. This value can be increased up to `DATA_COLUMN_SIDECAR_SUBNET_COUNT`, indicating a super-full node.
|
||||
|
||||
A node stores the custodied columns for the duration of the pruning period and responds to peer requests for samples on those columns.
|
||||
|
||||
|
@ -119,14 +119,14 @@ The `MetaData` stored locally by clients is updated with an additional field to
|
||||
seq_number: uint64
|
||||
attnets: Bitvector[ATTESTATION_SUBNET_COUNT]
|
||||
syncnets: Bitvector[SYNC_COMMITTEE_SUBNET_COUNT]
|
||||
custody_subnet_count: uint64
|
||||
custody_subnet_count: uint64 # csc
|
||||
)
|
||||
```
|
||||
|
||||
Where
|
||||
|
||||
- `seq_number`, `attnets`, and `syncnets` have the same meaning defined in the Altair document.
|
||||
- `custody_subnet_count` represents the node's custody subnet count. Clients MAY reject ENRs with a value less than `CUSTODY_REQUIREMENT`.
|
||||
- `custody_subnet_count` represents the node's custody subnet count. Clients MAY reject peers with a value less than `CUSTODY_REQUIREMENT`.
|
||||
|
||||
### The gossip domain: gossipsub
|
||||
|
||||
@ -324,4 +324,4 @@ A new field is added to the ENR under the key `csc` to facilitate custody data c
|
||||
|
||||
| Key | Value |
|
||||
|--------|------------------------------------------|
|
||||
| `csc` | Custody subnet count, big endian integer |
|
||||
| `csc` | Custody subnet count, `uint64` big endian integer with no leading zero bytes (`0` is encoded as empty byte string) |
|
||||
|
@ -15,8 +15,6 @@
|
||||
- [BLS12-381 helpers](#bls12-381-helpers)
|
||||
- [`cell_to_coset_evals`](#cell_to_coset_evals)
|
||||
- [`coset_evals_to_cell`](#coset_evals_to_cell)
|
||||
- [Linear combinations](#linear-combinations)
|
||||
- [`g2_lincomb`](#g2_lincomb)
|
||||
- [FFTs](#ffts)
|
||||
- [`_fft_field`](#_fft_field)
|
||||
- [`fft_field`](#fft_field)
|
||||
@ -125,28 +123,6 @@ def coset_evals_to_cell(coset_evals: CosetEvals) -> Cell:
|
||||
return Cell(cell)
|
||||
```
|
||||
|
||||
### Linear combinations
|
||||
|
||||
#### `g2_lincomb`
|
||||
|
||||
```python
|
||||
def g2_lincomb(points: Sequence[G2Point], scalars: Sequence[BLSFieldElement]) -> Bytes96:
|
||||
"""
|
||||
BLS multiscalar multiplication in G2. This can be naively implemented using double-and-add.
|
||||
"""
|
||||
assert len(points) == len(scalars)
|
||||
|
||||
if len(points) == 0:
|
||||
return bls.G2_to_bytes96(bls.Z2())
|
||||
|
||||
points_g2 = []
|
||||
for point in points:
|
||||
points_g2.append(bls.bytes96_to_G2(point))
|
||||
|
||||
result = bls.multi_exp(points_g2, scalars)
|
||||
return Bytes96(bls.G2_to_bytes96(result))
|
||||
```
|
||||
|
||||
### FFTs
|
||||
|
||||
#### `_fft_field`
|
||||
|
@ -50,10 +50,11 @@
|
||||
- [Modified `process_operations`](#modified-process_operations)
|
||||
- [Payload Attestations](#payload-attestations)
|
||||
- [`process_payload_attestation`](#process_payload_attestation)
|
||||
- [Modified `process_execution_payload`](#modified-process_execution_payload)
|
||||
- [New `verify_execution_payload_envelope_signature`](#new-verify_execution_payload_envelope_signature)
|
||||
- [Modified `is_merge_transition_complete`](#modified-is_merge_transition_complete)
|
||||
- [Modified `validate_merge_block`](#modified-validate_merge_block)
|
||||
- [Execution payload processing](#execution-payload-processing)
|
||||
- [New `verify_execution_payload_envelope_signature`](#new-verify_execution_payload_envelope_signature)
|
||||
- [New `process_execution_payload`](#new-process_execution_payload)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
@ -156,6 +157,7 @@ class SignedExecutionPayloadHeader(Container):
|
||||
```python
|
||||
class ExecutionPayloadEnvelope(Container):
|
||||
payload: ExecutionPayload
|
||||
execution_requests: ExecutionRequests
|
||||
builder_index: ValidatorIndex
|
||||
beacon_block_root: Root
|
||||
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
|
||||
@ -175,7 +177,7 @@ class SignedExecutionPayloadEnvelope(Container):
|
||||
|
||||
#### `BeaconBlockBody`
|
||||
|
||||
**Note:** The Beacon Block body is modified to contain a `Signed ExecutionPayloadHeader`. The containers `BeaconBlock` and `SignedBeaconBlock` are modified indirectly.
|
||||
**Note:** The Beacon Block body is modified to contain a `Signed ExecutionPayloadHeader`. The containers `BeaconBlock` and `SignedBeaconBlock` are modified indirectly. The field `execution_requests` is removed from the beacon block body and moved into the signed execution payload envelope.
|
||||
|
||||
```python
|
||||
class BeaconBlockBody(Container):
|
||||
@ -184,15 +186,16 @@ class BeaconBlockBody(Container):
|
||||
graffiti: Bytes32 # Arbitrary data
|
||||
# Operations
|
||||
proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS]
|
||||
attestations: List[Attestation, MAX_ATTESTATIONS]
|
||||
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA]
|
||||
attestations: List[Attestation, MAX_ATTESTATIONS_ELECTRA]
|
||||
deposits: List[Deposit, MAX_DEPOSITS]
|
||||
voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
|
||||
sync_aggregate: SyncAggregate
|
||||
# Execution
|
||||
# Removed execution_payload [Removed in EIP-7732]
|
||||
# Removed blob_kzg_commitments [Removed in EIP-7732]
|
||||
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
|
||||
# Removed blob_kzg_commitments [Removed in EIP-7732]
|
||||
# Removed execution_requests [Removed in EIP-7732]
|
||||
# PBS
|
||||
signed_execution_payload_header: SignedExecutionPayloadHeader # [New in EIP-7732]
|
||||
payload_attestations: List[PayloadAttestation, MAX_PAYLOAD_ATTESTATIONS] # [New in EIP-7732]
|
||||
@ -427,7 +430,8 @@ The post-state corresponding to a pre-state `state` and a signed execution paylo
|
||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
process_withdrawals(state) # [Modified in EIP-7732]
|
||||
process_execution_payload_header(state, block) # [Modified in EIP-7732, removed process_execution_payload]
|
||||
# Removed `process_execution_payload` in EIP-7732
|
||||
process_execution_payload_header(state, block) # [New in EIP-7732]
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body) # [Modified in EIP-7732]
|
||||
@ -493,9 +497,12 @@ def process_execution_payload_header(state: BeaconState, block: BeaconBlock) ->
|
||||
signed_header = block.body.signed_execution_payload_header
|
||||
assert verify_execution_payload_header_signature(state, signed_header)
|
||||
|
||||
# Check that the builder has funds to cover the bid
|
||||
# Check that the builder is active non-slashed has funds to cover the bid
|
||||
header = signed_header.message
|
||||
builder_index = header.builder_index
|
||||
builder = state.validators[builder_index]
|
||||
assert is_active_validator(builder, get_current_epoch(state))
|
||||
assert not builder.slashed
|
||||
amount = header.value
|
||||
assert state.balances[builder_index] >= amount
|
||||
|
||||
@ -592,9 +599,51 @@ def process_payload_attestation(state: BeaconState, payload_attestation: Payload
|
||||
increase_balance(state, proposer_index, proposer_reward)
|
||||
```
|
||||
|
||||
#### Modified `process_execution_payload`
|
||||
#### Modified `is_merge_transition_complete`
|
||||
|
||||
##### New `verify_execution_payload_envelope_signature`
|
||||
`is_merge_transition_complete` is modified only for testing purposes to add the blob kzg commitments root for an empty list
|
||||
|
||||
```python
|
||||
def is_merge_transition_complete(state: BeaconState) -> bool:
|
||||
header = ExecutionPayloadHeader()
|
||||
kzgs = List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]()
|
||||
header.blob_kzg_commitments_root = kzgs.hash_tree_root()
|
||||
|
||||
return state.latest_execution_payload_header != header
|
||||
```
|
||||
|
||||
#### Modified `validate_merge_block`
|
||||
`validate_merge_block` is modified to use the new `signed_execution_payload_header` message in the Beacon Block Body
|
||||
|
||||
```python
|
||||
def validate_merge_block(block: BeaconBlock) -> None:
|
||||
"""
|
||||
Check the parent PoW block of execution payload is a valid terminal PoW block.
|
||||
|
||||
Note: Unavailable PoW block(s) may later become available,
|
||||
and a client software MAY delay a call to ``validate_merge_block``
|
||||
until the PoW block(s) become available.
|
||||
"""
|
||||
if TERMINAL_BLOCK_HASH != Hash32():
|
||||
# If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
|
||||
assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||
assert block.body.signed_execution_payload_header.message.parent_block_hash == TERMINAL_BLOCK_HASH
|
||||
return
|
||||
|
||||
# Modified in EIP-7732
|
||||
pow_block = get_pow_block(block.body.signed_execution_payload_header.message.parent_block_hash)
|
||||
# Check if `pow_block` is available
|
||||
assert pow_block is not None
|
||||
pow_parent = get_pow_block(pow_block.parent_hash)
|
||||
# Check if `pow_parent` is available
|
||||
assert pow_parent is not None
|
||||
# Check if `pow_block` is a valid terminal PoW block
|
||||
assert is_valid_terminal_pow_block(pow_block, pow_parent)
|
||||
```
|
||||
|
||||
### Execution payload processing
|
||||
|
||||
#### New `verify_execution_payload_envelope_signature`
|
||||
|
||||
```python
|
||||
def verify_execution_payload_envelope_signature(
|
||||
@ -604,6 +653,8 @@ def verify_execution_payload_envelope_signature(
|
||||
return bls.Verify(builder.pubkey, signing_root, signed_envelope.signature)
|
||||
```
|
||||
|
||||
#### New `process_execution_payload`
|
||||
|
||||
*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
|
||||
@ -647,11 +698,13 @@ def process_execution_payload(state: BeaconState,
|
||||
# Verify the execution payload is valid
|
||||
versioned_hashes = [kzg_commitment_to_versioned_hash(commitment)
|
||||
for commitment in envelope.blob_kzg_commitments]
|
||||
requests = envelope.execution_requests
|
||||
assert execution_engine.verify_and_notify_new_payload(
|
||||
NewPayloadRequest(
|
||||
execution_payload=payload,
|
||||
versioned_hashes=versioned_hashes,
|
||||
parent_beacon_block_root=state.latest_block_header.parent_root,
|
||||
execution_requests=requests,
|
||||
)
|
||||
)
|
||||
|
||||
@ -660,9 +713,9 @@ def process_execution_payload(state: BeaconState,
|
||||
for operation in operations:
|
||||
fn(state, operation)
|
||||
|
||||
for_ops(payload.deposit_requests, process_deposit_request)
|
||||
for_ops(payload.withdrawal_requests, process_withdrawal_request)
|
||||
for_ops(payload, process_consolidation_request)
|
||||
for_ops(requests.deposit_requests, process_deposit_request)
|
||||
for_ops(requests.withdrawal_requests, process_withdrawal_request)
|
||||
for_ops(requests.consolidation_requests, process_consolidation_request)
|
||||
|
||||
# Cache the execution payload header and proposer
|
||||
state.latest_block_hash = payload.block_hash
|
||||
@ -672,45 +725,3 @@ def process_execution_payload(state: BeaconState,
|
||||
if verify:
|
||||
assert envelope.state_root == hash_tree_root(state)
|
||||
```
|
||||
|
||||
#### Modified `is_merge_transition_complete`
|
||||
|
||||
`is_merge_transition_complete` is modified only for testing purposes to add the blob kzg commitments root for an empty list
|
||||
|
||||
```python
|
||||
def is_merge_transition_complete(state: BeaconState) -> bool:
|
||||
header = ExecutionPayloadHeader()
|
||||
kzgs = List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]()
|
||||
header.blob_kzg_commitments_root = kzgs.hash_tree_root()
|
||||
|
||||
return state.latest_execution_payload_header != header
|
||||
```
|
||||
|
||||
#### Modified `validate_merge_block`
|
||||
`validate_merge_block` is modified to use the new `signed_execution_payload_header` message in the Beacon Block Body
|
||||
|
||||
```python
|
||||
def validate_merge_block(block: BeaconBlock) -> None:
|
||||
"""
|
||||
Check the parent PoW block of execution payload is a valid terminal PoW block.
|
||||
|
||||
Note: Unavailable PoW block(s) may later become available,
|
||||
and a client software MAY delay a call to ``validate_merge_block``
|
||||
until the PoW block(s) become available.
|
||||
"""
|
||||
if TERMINAL_BLOCK_HASH != Hash32():
|
||||
# If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
|
||||
assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||
assert block.body.signed_execution_payload_header.message.parent_block_hash == TERMINAL_BLOCK_HASH
|
||||
return
|
||||
|
||||
# Modified in EIP-7732
|
||||
pow_block = get_pow_block(block.body.signed_execution_payload_header.message.parent_block_hash)
|
||||
# Check if `pow_block` is available
|
||||
assert pow_block is not None
|
||||
pow_parent = get_pow_block(pow_block.parent_hash)
|
||||
# Check if `pow_parent` is available
|
||||
assert pow_parent is not None
|
||||
# Check if `pow_block` is a valid terminal PoW block
|
||||
assert is_valid_terminal_pow_block(pow_block, pow_parent)
|
||||
```
|
||||
|
@ -7,6 +7,7 @@ This document contains the consensus-layer networking specification for EIP7732.
|
||||
|
||||
- [Modification in EIP-7732](#modification-in-eip-7732)
|
||||
- [Preset](#preset)
|
||||
- [Configuration](#configuration)
|
||||
- [Containers](#containers)
|
||||
- [`BlobSidecar`](#blobsidecar)
|
||||
- [Helpers](#helpers)
|
||||
@ -23,7 +24,7 @@ This document contains the consensus-layer networking specification for EIP7732.
|
||||
- [BeaconBlocksByRange v3](#beaconblocksbyrange-v3)
|
||||
- [BeaconBlocksByRoot v3](#beaconblocksbyroot-v3)
|
||||
- [BlobSidecarsByRoot v2](#blobsidecarsbyroot-v2)
|
||||
- [ExecutionPayloadEnvelopeByRoot v1](#executionpayloadenvelopebyroot-v1)
|
||||
- [ExecutionPayloadEnvelopesByRoot v1](#executionpayloadenvelopesbyroot-v1)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
@ -37,6 +38,14 @@ This document contains the consensus-layer networking specification for EIP7732.
|
||||
|------------------------------------------|-----------------------------------|---------------------------------------------------------------------|
|
||||
| `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH_EIP7732` | `13` # TODO: Compute it when the spec stabilizes | Merkle proof depth for the `blob_kzg_commitments` list item |
|
||||
|
||||
### Configuration
|
||||
|
||||
*[New in EIP7732]*
|
||||
|
||||
| Name | Value | Description |
|
||||
|------------------------|----------------|-------------------------------------------------------------------|
|
||||
| `MAX_REQUEST_PAYLOADS` | `2**7` (= 128) | Maximum number of execution payload envelopes in a single request |
|
||||
|
||||
|
||||
### Containers
|
||||
|
||||
@ -170,9 +179,10 @@ The following validations MUST pass before forwarding the `signed_execution_payl
|
||||
|
||||
- _[IGNORE]_ this is the first signed bid seen with a valid signature from the given builder for this slot.
|
||||
- _[IGNORE]_ this bid is the highest value bid seen for the pair of the corresponding slot and the given parent block hash.
|
||||
- _[REJECT]_ The signed builder bid, `header.builder_index` is a valid and non-slashed builder index in state.
|
||||
- _[REJECT]_ The signed builder bid, `header.builder_index` is a valid, active, and non-slashed builder index in state.
|
||||
- _[IGNORE]_ The signed builder bid value, `header.value`, is less or equal than the builder's balance in state. i.e. `MIN_BUILDER_BALANCE + header.value < state.builder_balances[header.builder_index]`.
|
||||
- _[IGNORE]_ `header.parent_block_hash` is the block hash of a known execution payload in fork choice.
|
||||
_ _[IGNORE]_ `header.parent_block_root` is the hash tree root of a known beacon block in fork choice.
|
||||
- _[IGNORE]_ `header.slot` is the current slot or the next slot.
|
||||
- _[REJECT]_ The builder signature, `signed_execution_payload_header_envelope.signature`, is valid with respect to the `header_envelope.builder_index`.
|
||||
|
||||
@ -225,9 +235,9 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`:
|
||||
| `EIP7732_FORK_VERSION` | `eip7732.BlobSidecar` |
|
||||
|
||||
|
||||
##### ExecutionPayloadEnvelopeByRoot v1
|
||||
##### ExecutionPayloadEnvelopesByRoot v1
|
||||
|
||||
**Protocol ID:** `/eth2/beacon_chain/req/execution_payload_envelope_by_root/1/`
|
||||
**Protocol ID:** `/eth2/beacon_chain/req/execution_payload_envelopes_by_root/1/`
|
||||
|
||||
The `<context-bytes>` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`:
|
||||
|
||||
@ -241,7 +251,7 @@ Request Content:
|
||||
|
||||
```
|
||||
(
|
||||
List[Root, MAX_REQUEST_PAYLOAD]
|
||||
List[Root, MAX_REQUEST_PAYLOADS]
|
||||
)
|
||||
```
|
||||
|
||||
@ -249,14 +259,14 @@ Response Content:
|
||||
|
||||
```
|
||||
(
|
||||
List[SignedExecutionPayloadEnvelope, MAX_REQUEST_PAYLOAD]
|
||||
List[SignedExecutionPayloadEnvelope, MAX_REQUEST_PAYLOADS]
|
||||
)
|
||||
```
|
||||
Requests execution payload envelope by `signed_execution_payload_envelope.message.block_root`. The response is a list of `SignedExecutionPayloadEnvelope` whose length is less than or equal to the number of requested execution payload envelopes. It may be less in the case that the responding peer is missing payload envelopes.
|
||||
Requests execution payload envelopes by `signed_execution_payload_envelope.message.block_root`. The response is a list of `SignedExecutionPayloadEnvelope` whose length is less than or equal to the number of requested execution payload envelopes. It may be less in the case that the responding peer is missing payload envelopes.
|
||||
|
||||
No more than `MAX_REQUEST_PAYLOAD` may be requested at a time.
|
||||
No more than `MAX_REQUEST_PAYLOADS` may be requested at a time.
|
||||
|
||||
ExecutionPayloadEnvelopeByRoot is primarily used to recover recent execution payload envelope (e.g. when receiving a payload attestation with revealed status as true but never received a payload).
|
||||
ExecutionPayloadEnvelopesByRoot is primarily used to recover recent execution payload envelopes (e.g. when receiving a payload attestation with revealed status as true but never received a payload).
|
||||
|
||||
The request MUST be encoded as an SSZ-field.
|
||||
|
||||
|
@ -232,7 +232,7 @@ def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdat
|
||||
new_has_supermajority = new_num_active_participants * 3 >= max_active_participants * 2
|
||||
old_has_supermajority = old_num_active_participants * 3 >= max_active_participants * 2
|
||||
if new_has_supermajority != old_has_supermajority:
|
||||
return new_has_supermajority > old_has_supermajority
|
||||
return new_has_supermajority
|
||||
if not new_has_supermajority and new_num_active_participants != old_num_active_participants:
|
||||
return new_num_active_participants > old_num_active_participants
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
- [Constants](#constants)
|
||||
- [Misc](#misc)
|
||||
- [Withdrawal prefixes](#withdrawal-prefixes)
|
||||
- [Domains](#domains)
|
||||
- [Preset](#preset)
|
||||
- [Gwei values](#gwei-values)
|
||||
- [Rewards and penalties](#rewards-and-penalties)
|
||||
@ -33,12 +32,10 @@
|
||||
- [`SingleAttestation`](#singleattestation)
|
||||
- [Modified Containers](#modified-containers)
|
||||
- [`AttesterSlashing`](#attesterslashing)
|
||||
- [`BeaconBlockBody`](#beaconblockbody)
|
||||
- [Extended Containers](#extended-containers)
|
||||
- [`Attestation`](#attestation)
|
||||
- [`IndexedAttestation`](#indexedattestation)
|
||||
- [`BeaconBlockBody`](#beaconblockbody)
|
||||
- [`ExecutionPayload`](#executionpayload)
|
||||
- [`ExecutionPayloadHeader`](#executionpayloadheader)
|
||||
- [`BeaconState`](#beaconstate)
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Predicates](#predicates)
|
||||
@ -51,7 +48,7 @@
|
||||
- [Modified `is_partially_withdrawable_validator`](#modified-is_partially_withdrawable_validator)
|
||||
- [Misc](#misc-1)
|
||||
- [New `get_committee_indices`](#new-get_committee_indices)
|
||||
- [New `get_validator_max_effective_balance`](#new-get_validator_max_effective_balance)
|
||||
- [New `get_max_effective_balance`](#new-get_max_effective_balance)
|
||||
- [Beacon state accessors](#beacon-state-accessors)
|
||||
- [New `get_balance_churn_limit`](#new-get_balance_churn_limit)
|
||||
- [New `get_activation_exit_churn_limit`](#new-get_activation_exit_churn_limit)
|
||||
@ -72,9 +69,16 @@
|
||||
- [Epoch processing](#epoch-processing)
|
||||
- [Modified `process_epoch`](#modified-process_epoch)
|
||||
- [Modified `process_registry_updates`](#modified-process_registry_updates)
|
||||
- [Modified `process_slashings`](#modified-process_slashings)
|
||||
- [New `process_pending_balance_deposits`](#new-process_pending_balance_deposits)
|
||||
- [New `process_pending_consolidations`](#new-process_pending_consolidations)
|
||||
- [Modified `process_effective_balance_updates`](#modified-process_effective_balance_updates)
|
||||
- [Execution engine](#execution-engine)
|
||||
- [Request data](#request-data)
|
||||
- [Modified `NewPayloadRequest`](#modified-newpayloadrequest)
|
||||
- [Engine APIs](#engine-apis)
|
||||
- [Modified `notify_new_payload`](#modified-notify_new_payload)
|
||||
- [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload)
|
||||
- [Block processing](#block-processing)
|
||||
- [Withdrawals](#withdrawals)
|
||||
- [Modified `get_expected_withdrawals`](#modified-get_expected_withdrawals)
|
||||
@ -130,12 +134,6 @@ The following values are (non-configurable) constants used throughout the specif
|
||||
| - | - |
|
||||
| `COMPOUNDING_WITHDRAWAL_PREFIX` | `Bytes1('0x02')` |
|
||||
|
||||
### Domains
|
||||
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `DOMAIN_CONSOLIDATION` | `DomainType('0x0B000000')` |
|
||||
|
||||
## Preset
|
||||
|
||||
### Gwei values
|
||||
@ -268,6 +266,18 @@ class SingleAttestation(Container):
|
||||
attester_index: ValidatorIndex
|
||||
data: AttestationData
|
||||
signature: BLSSignature
|
||||
|
||||
#### `ExecutionRequests`
|
||||
|
||||
*Note*: This container holds requests from the execution layer that are received in [
|
||||
`ExecutionPayloadV4`](https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#executionpayloadv4) via
|
||||
the Engine API. These requests are required for CL state transition (see `BeaconBlockBody`).
|
||||
|
||||
```python
|
||||
class ExecutionRequests(Container):
|
||||
deposits: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110]
|
||||
withdrawals: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7002:EIP7251]
|
||||
consolidations: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7251]
|
||||
```
|
||||
|
||||
### Modified Containers
|
||||
@ -280,6 +290,27 @@ class AttesterSlashing(Container):
|
||||
attestation_2: IndexedAttestation # [Modified in Electra:EIP7549]
|
||||
```
|
||||
|
||||
#### `BeaconBlockBody`
|
||||
|
||||
```python
|
||||
class BeaconBlockBody(Container):
|
||||
randao_reveal: BLSSignature
|
||||
eth1_data: Eth1Data # Eth1 data vote
|
||||
graffiti: Bytes32 # Arbitrary data
|
||||
# Operations
|
||||
proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA] # [Modified in Electra:EIP7549]
|
||||
attestations: List[Attestation, MAX_ATTESTATIONS_ELECTRA] # [Modified in Electra:EIP7549]
|
||||
deposits: List[Deposit, MAX_DEPOSITS]
|
||||
voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
|
||||
sync_aggregate: SyncAggregate
|
||||
# Execution
|
||||
execution_payload: ExecutionPayload
|
||||
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
|
||||
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
|
||||
execution_requests: ExecutionRequests # [New in Electra]
|
||||
```
|
||||
|
||||
### Extended Containers
|
||||
|
||||
#### `Attestation`
|
||||
@ -302,84 +333,6 @@ class IndexedAttestation(Container):
|
||||
signature: BLSSignature
|
||||
```
|
||||
|
||||
#### `BeaconBlockBody`
|
||||
|
||||
```python
|
||||
class BeaconBlockBody(Container):
|
||||
randao_reveal: BLSSignature
|
||||
eth1_data: Eth1Data # Eth1 data vote
|
||||
graffiti: Bytes32 # Arbitrary data
|
||||
# Operations
|
||||
proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
|
||||
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA] # [Modified in Electra:EIP7549]
|
||||
attestations: List[Attestation, MAX_ATTESTATIONS_ELECTRA] # [Modified in Electra:EIP7549]
|
||||
deposits: List[Deposit, MAX_DEPOSITS]
|
||||
voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
|
||||
sync_aggregate: SyncAggregate
|
||||
# Execution
|
||||
execution_payload: ExecutionPayload # [Modified in Electra:EIP6110:EIP7002]
|
||||
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
|
||||
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
|
||||
```
|
||||
|
||||
#### `ExecutionPayload`
|
||||
|
||||
```python
|
||||
class ExecutionPayload(Container):
|
||||
# Execution block header fields
|
||||
parent_hash: Hash32
|
||||
fee_recipient: ExecutionAddress
|
||||
state_root: Bytes32
|
||||
receipts_root: Bytes32
|
||||
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
|
||||
prev_randao: 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
|
||||
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
|
||||
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
|
||||
blob_gas_used: uint64
|
||||
excess_blob_gas: uint64
|
||||
deposit_requests: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110]
|
||||
# [New in Electra:EIP7002:EIP7251]
|
||||
withdrawal_requests: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD]
|
||||
# [New in Electra:EIP7251]
|
||||
consolidation_requests: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD]
|
||||
```
|
||||
|
||||
#### `ExecutionPayloadHeader`
|
||||
|
||||
```python
|
||||
class ExecutionPayloadHeader(Container):
|
||||
# Execution block header fields
|
||||
parent_hash: Hash32
|
||||
fee_recipient: ExecutionAddress
|
||||
state_root: Bytes32
|
||||
receipts_root: Bytes32
|
||||
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
|
||||
prev_randao: 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
|
||||
transactions_root: Root
|
||||
withdrawals_root: Root
|
||||
blob_gas_used: uint64
|
||||
excess_blob_gas: uint64
|
||||
deposit_requests_root: Root # [New in Electra:EIP6110]
|
||||
withdrawal_requests_root: Root # [New in Electra:EIP7002:EIP7251]
|
||||
consolidation_requests_root: Root # [New in Electra:EIP7251]
|
||||
```
|
||||
|
||||
#### `BeaconState`
|
||||
|
||||
```python
|
||||
@ -419,7 +372,7 @@ class BeaconState(Container):
|
||||
current_sync_committee: SyncCommittee
|
||||
next_sync_committee: SyncCommittee
|
||||
# Execution
|
||||
latest_execution_payload_header: ExecutionPayloadHeader # [Modified in Electra:EIP6110:EIP7002]
|
||||
latest_execution_payload_header: ExecutionPayloadHeader
|
||||
# Withdrawals
|
||||
next_withdrawal_index: WithdrawalIndex
|
||||
next_withdrawal_validator_index: ValidatorIndex
|
||||
@ -524,14 +477,14 @@ def is_fully_withdrawable_validator(validator: Validator, balance: Gwei, epoch:
|
||||
|
||||
#### Modified `is_partially_withdrawable_validator`
|
||||
|
||||
*Note*: The function `is_partially_withdrawable_validator` is modified to use `get_validator_max_effective_balance` instead of `MAX_EFFECTIVE_BALANCE` and `has_execution_withdrawal_credential` instead of `has_eth1_withdrawal_credential`.
|
||||
*Note*: The function `is_partially_withdrawable_validator` is modified to use `get_max_effective_balance` instead of `MAX_EFFECTIVE_BALANCE` and `has_execution_withdrawal_credential` instead of `has_eth1_withdrawal_credential`.
|
||||
|
||||
```python
|
||||
def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> bool:
|
||||
"""
|
||||
Check if ``validator`` is partially withdrawable.
|
||||
"""
|
||||
max_effective_balance = get_validator_max_effective_balance(validator)
|
||||
max_effective_balance = get_max_effective_balance(validator)
|
||||
has_max_effective_balance = validator.effective_balance == max_effective_balance # [Modified in Electra:EIP7251]
|
||||
has_excess_balance = balance > max_effective_balance # [Modified in Electra:EIP7251]
|
||||
return (
|
||||
@ -550,10 +503,10 @@ def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]
|
||||
return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit]
|
||||
```
|
||||
|
||||
#### New `get_validator_max_effective_balance`
|
||||
#### New `get_max_effective_balance`
|
||||
|
||||
```python
|
||||
def get_validator_max_effective_balance(validator: Validator) -> Gwei:
|
||||
def get_max_effective_balance(validator: Validator) -> Gwei:
|
||||
"""
|
||||
Get max effective balance for ``validator``.
|
||||
"""
|
||||
@ -600,7 +553,7 @@ def get_consolidation_churn_limit(state: BeaconState) -> Gwei:
|
||||
|
||||
```python
|
||||
def get_active_balance(state: BeaconState, validator_index: ValidatorIndex) -> Gwei:
|
||||
max_effective_balance = get_validator_max_effective_balance(state.validators[validator_index])
|
||||
max_effective_balance = get_max_effective_balance(state.validators[validator_index])
|
||||
return min(state.balances[validator_index], max_effective_balance)
|
||||
```
|
||||
|
||||
@ -825,7 +778,7 @@ def process_epoch(state: BeaconState) -> None:
|
||||
process_inactivity_updates(state)
|
||||
process_rewards_and_penalties(state)
|
||||
process_registry_updates(state) # [Modified in Electra:EIP7251]
|
||||
process_slashings(state)
|
||||
process_slashings(state) # [Modified in Electra:EIP7251]
|
||||
process_eth1_data_reset(state)
|
||||
process_pending_balance_deposits(state) # [New in Electra:EIP7251]
|
||||
process_pending_consolidations(state) # [New in Electra:EIP7251]
|
||||
@ -862,6 +815,28 @@ def process_registry_updates(state: BeaconState) -> None:
|
||||
validator.activation_epoch = activation_epoch
|
||||
```
|
||||
|
||||
#### Modified `process_slashings`
|
||||
|
||||
*Note*: The function `process_slashings` is modified to use a new algorithm to compute correlation penalty.
|
||||
|
||||
```python
|
||||
def process_slashings(state: BeaconState) -> None:
|
||||
epoch = get_current_epoch(state)
|
||||
total_balance = get_total_active_balance(state)
|
||||
adjusted_total_slashing_balance = min(
|
||||
sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX,
|
||||
total_balance
|
||||
)
|
||||
increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from total balance to avoid uint64 overflow
|
||||
penalty_per_effective_balance_increment = adjusted_total_slashing_balance // (total_balance // increment)
|
||||
for index, validator in enumerate(state.validators):
|
||||
if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
|
||||
effective_balance_increments = validator.effective_balance // increment
|
||||
# [Modified in Electra:EIP7251]
|
||||
penalty = penalty_per_effective_balance_increment * effective_balance_increments
|
||||
decrease_balance(state, ValidatorIndex(index), penalty)
|
||||
```
|
||||
|
||||
#### New `process_pending_balance_deposits`
|
||||
|
||||
```python
|
||||
@ -953,6 +928,70 @@ def process_effective_balance_updates(state: BeaconState) -> None:
|
||||
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, EFFECTIVE_BALANCE_LIMIT)
|
||||
```
|
||||
|
||||
### Execution engine
|
||||
|
||||
#### Request data
|
||||
|
||||
##### Modified `NewPayloadRequest`
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class NewPayloadRequest(object):
|
||||
execution_payload: ExecutionPayload
|
||||
versioned_hashes: Sequence[VersionedHash]
|
||||
parent_beacon_block_root: Root
|
||||
execution_requests: ExecutionRequests # [New in Electra]
|
||||
```
|
||||
|
||||
#### Engine APIs
|
||||
|
||||
##### Modified `notify_new_payload`
|
||||
|
||||
*Note*: The function `notify_new_payload` is modified to include the additional `execution_requests` parameter in Electra.
|
||||
|
||||
```python
|
||||
def notify_new_payload(self: ExecutionEngine,
|
||||
execution_payload: ExecutionPayload,
|
||||
execution_requests: ExecutionRequests,
|
||||
parent_beacon_block_root: Root) -> bool:
|
||||
"""
|
||||
Return ``True`` if and only if ``execution_payload`` and ``execution_requests``
|
||||
are valid with respect to ``self.execution_state``.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
##### Modified `verify_and_notify_new_payload`
|
||||
|
||||
*Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameter `execution_requests`
|
||||
when calling `notify_new_payload` in Electra.
|
||||
|
||||
```python
|
||||
def verify_and_notify_new_payload(self: ExecutionEngine,
|
||||
new_payload_request: NewPayloadRequest) -> bool:
|
||||
"""
|
||||
Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``.
|
||||
"""
|
||||
execution_payload = new_payload_request.execution_payload
|
||||
execution_requests = new_payload_request.execution_requests # [New in Electra]
|
||||
parent_beacon_block_root = new_payload_request.parent_beacon_block_root
|
||||
|
||||
if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root):
|
||||
return False
|
||||
|
||||
if not self.is_valid_versioned_hashes(new_payload_request):
|
||||
return False
|
||||
|
||||
# [Modified in Electra]
|
||||
if not self.notify_new_payload(
|
||||
execution_payload,
|
||||
execution_requests,
|
||||
parent_beacon_block_root):
|
||||
return False
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
### Block processing
|
||||
|
||||
```python
|
||||
@ -1017,7 +1056,7 @@ def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal],
|
||||
index=withdrawal_index,
|
||||
validator_index=validator_index,
|
||||
address=ExecutionAddress(validator.withdrawal_credentials[12:]),
|
||||
amount=balance - get_validator_max_effective_balance(validator), # [Modified in Electra:EIP7251]
|
||||
amount=balance - get_max_effective_balance(validator), # [Modified in Electra:EIP7251]
|
||||
))
|
||||
withdrawal_index += WithdrawalIndex(1)
|
||||
if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
|
||||
@ -1034,10 +1073,9 @@ def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal],
|
||||
def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
|
||||
expected_withdrawals, partial_withdrawals_count = get_expected_withdrawals(state) # [Modified in Electra:EIP7251]
|
||||
|
||||
assert len(payload.withdrawals) == len(expected_withdrawals)
|
||||
assert payload.withdrawals == expected_withdrawals
|
||||
|
||||
for expected_withdrawal, withdrawal in zip(expected_withdrawals, payload.withdrawals):
|
||||
assert withdrawal == expected_withdrawal
|
||||
for withdrawal in expected_withdrawals:
|
||||
decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
|
||||
|
||||
# Update pending partial withdrawals [New in Electra:EIP7251]
|
||||
@ -1064,7 +1102,7 @@ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
|
||||
|
||||
##### Modified `process_execution_payload`
|
||||
|
||||
*Note*: The function `process_execution_payload` is modified to use the new `ExecutionPayloadHeader` type.
|
||||
*Note*: The function `process_execution_payload` is modified to pass `execution_requests` into `execution_engine.verify_and_notify_new_payload` (via the updated `NewPayloadRequest`).
|
||||
|
||||
```python
|
||||
def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None:
|
||||
@ -1083,6 +1121,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
|
||||
assert execution_engine.verify_and_notify_new_payload(
|
||||
NewPayloadRequest(
|
||||
execution_payload=payload,
|
||||
execution_requests=body.execution_requests, # [New in Electra]
|
||||
versioned_hashes=versioned_hashes,
|
||||
parent_beacon_block_root=state.latest_block_header.parent_root,
|
||||
)
|
||||
@ -1106,9 +1145,6 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi
|
||||
withdrawals_root=hash_tree_root(payload.withdrawals),
|
||||
blob_gas_used=payload.blob_gas_used,
|
||||
excess_blob_gas=payload.excess_blob_gas,
|
||||
deposit_requests_root=hash_tree_root(payload.deposit_requests), # [New in Electra:EIP6110]
|
||||
withdrawal_requests_root=hash_tree_root(payload.withdrawal_requests), # [New in Electra:EIP7002:EIP7251]
|
||||
consolidation_requests_root=hash_tree_root(payload.consolidation_requests), # [New in Electra:EIP7251]
|
||||
)
|
||||
```
|
||||
|
||||
@ -1135,14 +1171,12 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||
for_ops(body.proposer_slashings, process_proposer_slashing)
|
||||
for_ops(body.attester_slashings, process_attester_slashing)
|
||||
for_ops(body.attestations, process_attestation) # [Modified in Electra:EIP7549]
|
||||
for_ops(body.deposits, process_deposit) # [Modified in Electra:EIP7251]
|
||||
for_ops(body.deposits, process_deposit)
|
||||
for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251]
|
||||
for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
|
||||
for_ops(body.execution_payload.deposit_requests, process_deposit_request) # [New in Electra:EIP6110]
|
||||
# [New in Electra:EIP7002:EIP7251]
|
||||
for_ops(body.execution_payload.withdrawal_requests, process_withdrawal_request)
|
||||
# [New in Electra:EIP7251]
|
||||
for_ops(body.execution_payload.consolidation_requests, process_consolidation_request)
|
||||
for_ops(body.execution_requests.deposits, process_deposit_request) # [New in Electra:EIP6110]
|
||||
for_ops(body.execution_requests.withdrawals, process_withdrawal_request) # [New in Electra:EIP7002:EIP7251]
|
||||
for_ops(body.execution_requests.consolidations, process_consolidation_request) # [New in Electra:EIP7251]
|
||||
```
|
||||
|
||||
##### Attestations
|
||||
@ -1196,7 +1230,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||
|
||||
###### Modified `apply_deposit`
|
||||
|
||||
*Note*: The function `process_deposit` is modified to support EIP7251.
|
||||
*Note*: The function `apply_deposit` is modified to support EIP7251.
|
||||
|
||||
```python
|
||||
def apply_deposit(state: BeaconState,
|
||||
@ -1508,7 +1542,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32,
|
||||
balance = state.balances[index]
|
||||
# [Modified in Electra:EIP7251]
|
||||
validator.effective_balance = min(
|
||||
balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_validator_max_effective_balance(validator))
|
||||
balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_max_effective_balance(validator))
|
||||
if validator.effective_balance >= MIN_ACTIVATION_BALANCE:
|
||||
validator.activation_eligibility_epoch = GENESIS_EPOCH
|
||||
validator.activation_epoch = GENESIS_EPOCH
|
||||
|
@ -72,28 +72,7 @@ an irregular state change is made to upgrade to Electra.
|
||||
```python
|
||||
def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState:
|
||||
epoch = deneb.get_current_epoch(pre)
|
||||
latest_execution_payload_header = ExecutionPayloadHeader(
|
||||
parent_hash=pre.latest_execution_payload_header.parent_hash,
|
||||
fee_recipient=pre.latest_execution_payload_header.fee_recipient,
|
||||
state_root=pre.latest_execution_payload_header.state_root,
|
||||
receipts_root=pre.latest_execution_payload_header.receipts_root,
|
||||
logs_bloom=pre.latest_execution_payload_header.logs_bloom,
|
||||
prev_randao=pre.latest_execution_payload_header.prev_randao,
|
||||
block_number=pre.latest_execution_payload_header.block_number,
|
||||
gas_limit=pre.latest_execution_payload_header.gas_limit,
|
||||
gas_used=pre.latest_execution_payload_header.gas_used,
|
||||
timestamp=pre.latest_execution_payload_header.timestamp,
|
||||
extra_data=pre.latest_execution_payload_header.extra_data,
|
||||
base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas,
|
||||
block_hash=pre.latest_execution_payload_header.block_hash,
|
||||
transactions_root=pre.latest_execution_payload_header.transactions_root,
|
||||
withdrawals_root=pre.latest_execution_payload_header.withdrawals_root,
|
||||
blob_gas_used=pre.latest_execution_payload_header.blob_gas_used,
|
||||
excess_blob_gas=pre.latest_execution_payload_header.excess_blob_gas,
|
||||
deposit_requests_root=Root(), # [New in Electra:EIP6110]
|
||||
withdrawal_requests_root=Root(), # [New in Electra:EIP7002]
|
||||
consolidation_requests_root=Root(), # [New in Electra:EIP7251]
|
||||
)
|
||||
latest_execution_payload_header = pre.latest_execution_payload_header
|
||||
|
||||
exit_epochs = [v.exit_epoch for v in pre.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
|
||||
if not exit_epochs:
|
||||
|
@ -39,28 +39,7 @@ A Electra `LightClientStore` can still process earlier light client data. In ord
|
||||
def upgrade_lc_header_to_electra(pre: deneb.LightClientHeader) -> LightClientHeader:
|
||||
return LightClientHeader(
|
||||
beacon=pre.beacon,
|
||||
execution=ExecutionPayloadHeader(
|
||||
parent_hash=pre.execution.parent_hash,
|
||||
fee_recipient=pre.execution.fee_recipient,
|
||||
state_root=pre.execution.state_root,
|
||||
receipts_root=pre.execution.receipts_root,
|
||||
logs_bloom=pre.execution.logs_bloom,
|
||||
prev_randao=pre.execution.prev_randao,
|
||||
block_number=pre.execution.block_number,
|
||||
gas_limit=pre.execution.gas_limit,
|
||||
gas_used=pre.execution.gas_used,
|
||||
timestamp=pre.execution.timestamp,
|
||||
extra_data=pre.execution.extra_data,
|
||||
base_fee_per_gas=pre.execution.base_fee_per_gas,
|
||||
block_hash=pre.execution.block_hash,
|
||||
transactions_root=pre.execution.transactions_root,
|
||||
withdrawals_root=pre.execution.withdrawals_root,
|
||||
blob_gas_used=pre.execution.blob_gas_used,
|
||||
excess_blob_gas=pre.execution.blob_gas_used,
|
||||
deposit_requests_root=Root(), # [New in Electra:EIP6110]
|
||||
withdrawal_requests_root=Root(), # [New in Electra:EIP7002:EIP7251]
|
||||
consolidation_requests_root=Root(), # [New in Electra:EIP7251]
|
||||
),
|
||||
execution=pre.execution,
|
||||
execution_branch=pre.execution_branch,
|
||||
)
|
||||
```
|
||||
|
@ -50,12 +50,6 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader:
|
||||
execution_header.blob_gas_used = payload.blob_gas_used
|
||||
execution_header.excess_blob_gas = payload.excess_blob_gas
|
||||
|
||||
# [New in Electra:EIP6110:EIP7002:EIP7251]
|
||||
if epoch >= ELECTRA_FORK_EPOCH:
|
||||
execution_header.deposit_requests_root = hash_tree_root(payload.deposit_requests)
|
||||
execution_header.withdrawal_requests_root = hash_tree_root(payload.withdrawal_requests)
|
||||
execution_header.consolidation_requests_root = hash_tree_root(payload.consolidation_requests)
|
||||
|
||||
execution_branch = ExecutionBranch(
|
||||
compute_merkle_proof(block.message.body, EXECUTION_PAYLOAD_GINDEX))
|
||||
else:
|
||||
|
@ -159,15 +159,6 @@ def get_lc_execution_root(header: LightClientHeader) -> Root:
|
||||
def is_valid_light_client_header(header: LightClientHeader) -> bool:
|
||||
epoch = compute_epoch_at_slot(header.beacon.slot)
|
||||
|
||||
# [New in Electra:EIP6110:EIP7002:EIP7251]
|
||||
if epoch < ELECTRA_FORK_EPOCH:
|
||||
if (
|
||||
header.execution.deposit_requests_root != Root()
|
||||
or header.execution.withdrawal_requests_root != Root()
|
||||
or header.execution.consolidation_requests_root != Root()
|
||||
):
|
||||
return False
|
||||
|
||||
if epoch < DENEB_FORK_EPOCH:
|
||||
if header.execution.blob_gas_used != uint64(0) or header.execution.excess_blob_gas != uint64(0):
|
||||
return False
|
||||
|
@ -257,7 +257,7 @@ We define a Merkle multiproof as a minimal subset of nodes in a Merkle tree need
|
||||
x x . . . . x *
|
||||
```
|
||||
|
||||
. are unused nodes, * are used nodes, x are the values we are trying to prove. Notice how despite being a multiproof for 3 values, it requires only 3 auxiliary nodes, only one node more than would be required to prove a single value. Normally the efficiency gains are not quite that extreme, but the savings relative to individual Merkle proofs are still significant. As a rule of thumb, a multiproof for k nodes at the same level of an n-node tree has size `k * (n/k + log(n/k))`.
|
||||
. are unused nodes, * are used nodes, x are the values we are trying to prove. Notice how despite being a multiproof for 3 values, it requires only 3 auxiliary nodes, the same amount required to prove a single value. Normally the efficiency gains are not quite that extreme, but the savings relative to individual Merkle proofs are still significant. As a rule of thumb, a multiproof for k nodes at the same level of an n-node tree has size `k * (n/k + log(n/k))`.
|
||||
|
||||
First, we provide a method for computing the generalized indices of the auxiliary tree nodes that a proof of a given set of generalized indices will require:
|
||||
|
||||
|
@ -1 +1 @@
|
||||
1.5.0-alpha.5
|
||||
1.5.0-alpha.6
|
||||
|
@ -16,7 +16,7 @@ def _run_get_custody_columns(spec, rng, node_id=None, custody_subnet_count=None)
|
||||
|
||||
result = spec.get_custody_columns(node_id, custody_subnet_count)
|
||||
yield 'node_id', 'meta', node_id
|
||||
yield 'custody_subnet_count', 'meta', custody_subnet_count
|
||||
yield 'custody_subnet_count', 'meta', int(custody_subnet_count)
|
||||
|
||||
assert len(result) == len(set(result))
|
||||
assert len(result) == (
|
||||
|
@ -1,3 +1,4 @@
|
||||
import random
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
expect_assertion_error,
|
||||
@ -19,6 +20,31 @@ from eth2spec.test.helpers.withdrawals import (
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_basic_withdrawal_request(spec, state):
|
||||
rng = random.Random(1337)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
withdrawal_request = spec.WithdrawalRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
yield from run_withdrawal_request_processing(
|
||||
spec, state, withdrawal_request
|
||||
)
|
||||
|
||||
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_basic_withdrawal_request_with_first_validator(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
@ -43,11 +69,12 @@ def test_basic_withdrawal_request(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_basic_withdrawal_request_with_compounding_credentials(spec, state):
|
||||
rng = random.Random(1338)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
@ -66,9 +93,10 @@ def test_basic_withdrawal_request_with_compounding_credentials(spec, state):
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL], "need full partial withdrawal queue")
|
||||
def test_basic_withdrawal_request_with_full_partial_withdrawal_queue(spec, state):
|
||||
rng = random.Random(1339)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
@ -102,11 +130,12 @@ def test_basic_withdrawal_request_with_full_partial_withdrawal_queue(spec, state
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_source_address(spec, state):
|
||||
rng = random.Random(1340)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
incorrect_address = b"\x33" * 20
|
||||
@ -127,11 +156,12 @@ def test_incorrect_source_address(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_withdrawal_credential_prefix(spec, state):
|
||||
rng = random.Random(1341)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
@ -156,11 +186,12 @@ def test_incorrect_withdrawal_credential_prefix(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_on_withdrawal_request_initiated_validator(spec, state):
|
||||
rng = random.Random(1342)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
@ -182,8 +213,9 @@ def test_on_withdrawal_request_initiated_validator(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_activation_epoch_less_than_shard_committee_period(spec, state):
|
||||
rng = random.Random(1343)
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
@ -211,9 +243,10 @@ def test_activation_epoch_less_than_shard_committee_period(spec, state):
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_basic_partial_withdrawal_request(spec, state):
|
||||
rng = random.Random(1344)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -243,9 +276,10 @@ def test_basic_partial_withdrawal_request(spec, state):
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_basic_partial_withdrawal_request_higher_excess_balance(spec, state):
|
||||
rng = random.Random(1345)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -275,9 +309,10 @@ def test_basic_partial_withdrawal_request_higher_excess_balance(spec, state):
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_basic_partial_withdrawal_request_lower_than_excess_balance(spec, state):
|
||||
rng = random.Random(1346)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
excess_balance = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -308,9 +343,10 @@ def test_basic_partial_withdrawal_request_lower_than_excess_balance(spec, state)
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_pending_withdrawals(spec, state):
|
||||
rng = random.Random(1347)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -349,9 +385,10 @@ def test_partial_withdrawal_request_with_pending_withdrawals(spec, state):
|
||||
def test_partial_withdrawal_request_with_pending_withdrawals_and_high_amount(
|
||||
spec, state
|
||||
):
|
||||
rng = random.Random(1348)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.UINT64_MAX
|
||||
@ -387,9 +424,10 @@ def test_partial_withdrawal_request_with_pending_withdrawals_and_high_amount(
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_high_balance(spec, state):
|
||||
rng = random.Random(1349)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE_ELECTRA
|
||||
@ -424,9 +462,10 @@ def test_partial_withdrawal_request_with_high_balance(spec, state):
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_high_amount(spec, state):
|
||||
rng = random.Random(1350)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
# Set high amount requested to withdraw
|
||||
@ -457,9 +496,10 @@ def test_partial_withdrawal_request_with_high_amount(spec, state):
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_low_amount(spec, state):
|
||||
rng = random.Random(1351)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = 1
|
||||
@ -492,9 +532,10 @@ def test_partial_withdrawal_request_with_low_amount(spec, state):
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL], "need full partial withdrawal queue")
|
||||
def test_partial_withdrawal_queue_full(spec, state):
|
||||
rng = random.Random(1352)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -522,9 +563,10 @@ def test_partial_withdrawal_queue_full(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_no_compounding_credentials(spec, state):
|
||||
rng = random.Random(1353)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -551,9 +593,10 @@ def test_no_compounding_credentials(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_no_excess_balance(spec, state):
|
||||
rng = random.Random(1354)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -573,9 +616,10 @@ def test_no_excess_balance(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_pending_withdrawals_consume_all_excess_balance(spec, state):
|
||||
rng = random.Random(1355)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -603,9 +647,10 @@ def test_pending_withdrawals_consume_all_excess_balance(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_insufficient_effective_balance(spec, state):
|
||||
rng = random.Random(1356)
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -632,11 +677,12 @@ def test_insufficient_effective_balance(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_partial_withdrawal_incorrect_source_address(spec, state):
|
||||
rng = random.Random(1357)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
incorrect_address = b"\x33" * 20
|
||||
@ -658,11 +704,12 @@ def test_partial_withdrawal_incorrect_source_address(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_partial_withdrawal_incorrect_withdrawal_credential_prefix(spec, state):
|
||||
rng = random.Random(1358)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -687,11 +734,12 @@ def test_partial_withdrawal_incorrect_withdrawal_credential_prefix(spec, state):
|
||||
@with_electra_and_later
|
||||
@spec_state_test
|
||||
def test_partial_withdrawal_on_exit_initiated_validator(spec, state):
|
||||
rng = random.Random(1359)
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
@ -715,8 +763,9 @@ def test_partial_withdrawal_on_exit_initiated_validator(spec, state):
|
||||
def test_partial_withdrawal_activation_epoch_less_than_shard_committee_period(
|
||||
spec, state
|
||||
):
|
||||
rng = random.Random(1360)
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_index = rng.choice(spec.get_active_validator_indices(state, current_epoch))
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
|
@ -1,6 +1,6 @@
|
||||
from eth2spec.test.helpers.epoch_processing import (
|
||||
run_epoch_processing_with,
|
||||
compute_state_by_epoch_processing_to,
|
||||
run_epoch_processing_to,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
@ -219,7 +219,8 @@ def test_pending_consolidation_future_epoch(spec, state):
|
||||
next_epoch_with_full_participation(spec, state)
|
||||
|
||||
# Obtain state before the call to process_pending_consolidations
|
||||
state_before_consolidation = compute_state_by_epoch_processing_to(spec, state, "process_pending_consolidations")
|
||||
state_before_consolidation = state.copy()
|
||||
run_epoch_processing_to(spec, state_before_consolidation, "process_pending_consolidations")
|
||||
|
||||
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
|
||||
|
||||
@ -270,7 +271,8 @@ def test_pending_consolidation_compounding_creds(spec, state):
|
||||
next_epoch_with_full_participation(spec, state)
|
||||
|
||||
# Obtain state before the call to process_pending_consolidations
|
||||
state_before_consolidation = compute_state_by_epoch_processing_to(spec, state, "process_pending_consolidations")
|
||||
state_before_consolidation = state.copy()
|
||||
run_epoch_processing_to(spec, state_before_consolidation, "process_pending_consolidations")
|
||||
|
||||
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
|
||||
|
||||
@ -325,7 +327,8 @@ def test_pending_consolidation_with_pending_deposit(spec, state):
|
||||
next_epoch_with_full_participation(spec, state)
|
||||
|
||||
# Obtain state before the call to process_pending_balance_deposits
|
||||
state_before_consolidation = compute_state_by_epoch_processing_to(spec, state, "process_pending_balance_deposits")
|
||||
state_before_consolidation = state.copy()
|
||||
run_epoch_processing_to(spec, state_before_consolidation, "process_pending_consolidations")
|
||||
|
||||
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
|
||||
|
||||
|
@ -41,7 +41,7 @@ def test_basic_el_withdrawal_request(spec, state):
|
||||
validator_pubkey=validator_pubkey,
|
||||
)
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.withdrawal_requests = [withdrawal_request]
|
||||
block.body.execution_requests.withdrawals = [withdrawal_request]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
@ -77,7 +77,7 @@ def test_basic_btec_and_el_withdrawal_request_in_same_block(spec, state):
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
)
|
||||
block.body.execution_payload.withdrawal_requests = [withdrawal_request]
|
||||
block.body.execution_requests.withdrawals = [withdrawal_request]
|
||||
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
@ -130,7 +130,7 @@ def test_basic_btec_before_el_withdrawal_request(spec, state):
|
||||
validator_pubkey=validator_pubkey,
|
||||
)
|
||||
block_2 = build_empty_block_for_next_slot(spec, state)
|
||||
block_2.body.execution_payload.withdrawal_requests = [withdrawal_request]
|
||||
block_2.body.execution_requests.withdrawals = [withdrawal_request]
|
||||
block_2.body.execution_payload.block_hash = compute_el_block_hash(spec, block_2.body.execution_payload, state)
|
||||
signed_block_2 = state_transition_and_sign_block(spec, state, block_2)
|
||||
|
||||
@ -163,7 +163,7 @@ def test_cl_exit_and_el_withdrawal_request_in_same_block(spec, state):
|
||||
)
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.voluntary_exits = signed_voluntary_exits
|
||||
block.body.execution_payload.withdrawal_requests = [withdrawal_request]
|
||||
block.body.execution_requests.withdrawals = [withdrawal_request]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
|
@ -38,7 +38,7 @@ def run_deposit_transition_block(spec, state, block, top_up_keys=[], valid=True)
|
||||
# Check that deposits are applied
|
||||
if valid:
|
||||
expected_pubkeys = [d.data.pubkey for d in block.body.deposits]
|
||||
deposit_requests = block.body.execution_payload.deposit_requests
|
||||
deposit_requests = block.body.execution_requests.deposits
|
||||
expected_pubkeys = expected_pubkeys + [d.pubkey for d in deposit_requests if (d.pubkey not in top_up_keys)]
|
||||
actual_pubkeys = [v.pubkey for v in state.validators[len(state.validators) - len(expected_pubkeys):]]
|
||||
|
||||
@ -102,7 +102,7 @@ def prepare_state_and_block(spec,
|
||||
|
||||
# Assign deposits and deposit requests
|
||||
block.body.deposits = deposits
|
||||
block.body.execution_payload.deposit_requests = deposit_requests
|
||||
block.body.execution_requests.deposits = deposit_requests
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state)
|
||||
|
||||
return state, block
|
||||
@ -120,7 +120,7 @@ def test_deposit_transition__start_index_is_set(spec, state):
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
# deposit_requests_start_index must be set to the index of the first request
|
||||
assert state.deposit_requests_start_index == block.body.execution_payload.deposit_requests[0].index
|
||||
assert state.deposit_requests_start_index == block.body.execution_requests.deposits[0].index
|
||||
|
||||
|
||||
@with_phases([ELECTRA])
|
||||
@ -219,7 +219,7 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state):
|
||||
|
||||
# Artificially assign deposit's pubkey to a deposit request of the same block
|
||||
top_up_keys = [block.body.deposits[0].data.pubkey]
|
||||
block.body.execution_payload.deposit_requests[0].pubkey = top_up_keys[0]
|
||||
block.body.execution_requests.deposits[0].pubkey = top_up_keys[0]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state)
|
||||
|
||||
pre_pending_deposits = len(state.pending_balance_deposits)
|
||||
@ -229,5 +229,5 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state):
|
||||
# Check the top up
|
||||
assert len(state.pending_balance_deposits) == pre_pending_deposits + 2
|
||||
assert state.pending_balance_deposits[pre_pending_deposits].amount == block.body.deposits[0].data.amount
|
||||
amount_from_deposit = block.body.execution_payload.deposit_requests[0].amount
|
||||
amount_from_deposit = block.body.execution_requests.deposits[0].amount
|
||||
assert state.pending_balance_deposits[pre_pending_deposits + 1].amount == amount_from_deposit
|
||||
|
@ -1,6 +1,7 @@
|
||||
from eth2spec.test.helpers.execution_payload import build_empty_execution_payload
|
||||
from eth2spec.test.helpers.execution_payload import build_empty_signed_execution_payload_header
|
||||
from eth2spec.test.helpers.forks import is_post_whisk, is_post_altair, is_post_bellatrix, is_post_eip7732
|
||||
from eth2spec.test.helpers.forks import is_post_whisk, is_post_altair, is_post_bellatrix, is_post_eip7732, \
|
||||
is_post_electra
|
||||
from eth2spec.test.helpers.keys import privkeys, whisk_ks_initial, whisk_ks_final
|
||||
from eth2spec.utils import bls
|
||||
from eth2spec.utils.bls import only_with_bls
|
||||
@ -126,6 +127,11 @@ def build_empty_block(spec, state, slot=None, proposer_index=None):
|
||||
if is_post_bellatrix(spec):
|
||||
empty_block.body.execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
if is_post_electra(spec):
|
||||
empty_block.body.execution_requests.deposits = []
|
||||
empty_block.body.execution_requests.withdrawals = []
|
||||
empty_block.body.execution_requests.consolidations = []
|
||||
|
||||
if is_post_whisk(spec):
|
||||
# Whisk opening proof
|
||||
#######
|
||||
|
@ -38,13 +38,14 @@ def run_fork_test(post_spec, pre_state):
|
||||
'next_withdrawal_index', 'next_withdrawal_validator_index',
|
||||
# Deep history valid from Capella onwards
|
||||
'historical_summaries',
|
||||
'latest_execution_payload_header'
|
||||
|
||||
]
|
||||
for field in stable_fields:
|
||||
assert getattr(pre_state, field) == getattr(post_state, field)
|
||||
|
||||
# Modified fields
|
||||
modified_fields = ['fork', 'latest_execution_payload_header']
|
||||
modified_fields = ['fork']
|
||||
for field in modified_fields:
|
||||
assert getattr(pre_state, field) != getattr(post_state, field)
|
||||
|
||||
|
@ -36,8 +36,6 @@ def get_process_calls(spec):
|
||||
'process_participation_record_updates'
|
||||
),
|
||||
'process_sync_committee_updates', # altair
|
||||
'process_full_withdrawals', # capella
|
||||
'process_partial_withdrawals', # capella
|
||||
# TODO: add sharding processing functions when spec stabilizes.
|
||||
]
|
||||
|
||||
@ -74,9 +72,3 @@ def run_epoch_processing_with(spec, state, process_name: str):
|
||||
yield 'pre', state
|
||||
getattr(spec, process_name)(state)
|
||||
yield 'post', state
|
||||
|
||||
|
||||
def compute_state_by_epoch_processing_to(spec, state, process_name: str):
|
||||
state_copy = state.copy()
|
||||
run_epoch_processing_to(spec, state_copy, process_name)
|
||||
return state_copy
|
||||
|
@ -7,12 +7,7 @@ from eth2spec.test.helpers.keys import privkeys
|
||||
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
|
||||
from eth2spec.debug.random_value import get_random_bytes_list
|
||||
from eth2spec.test.helpers.withdrawals import get_expected_withdrawals
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_capella,
|
||||
is_post_deneb,
|
||||
is_post_electra,
|
||||
is_post_eip7732,
|
||||
)
|
||||
from eth2spec.test.helpers.forks import is_post_capella, is_post_deneb, is_post_eip7732
|
||||
|
||||
|
||||
def get_execution_payload_header(spec, execution_payload):
|
||||
@ -49,10 +44,6 @@ def get_execution_payload_header(spec, execution_payload):
|
||||
if is_post_deneb(spec):
|
||||
payload_header.blob_gas_used = execution_payload.blob_gas_used
|
||||
payload_header.excess_blob_gas = execution_payload.excess_blob_gas
|
||||
if is_post_electra(spec):
|
||||
payload_header.deposit_requests_root = spec.hash_tree_root(execution_payload.deposit_requests)
|
||||
payload_header.withdrawal_requests_root = spec.hash_tree_root(execution_payload.withdrawal_requests)
|
||||
payload_header.consolidation_requests_root = spec.hash_tree_root(execution_payload.consolidation_requests)
|
||||
return payload_header
|
||||
|
||||
|
||||
@ -74,8 +65,7 @@ def compute_el_header_block_hash(spec,
|
||||
payload_header,
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root=None,
|
||||
parent_beacon_block_root=None,
|
||||
requests_trie_root=None):
|
||||
parent_beacon_block_root=None):
|
||||
"""
|
||||
Computes the RLP execution block hash described by an `ExecutionPayloadHeader`.
|
||||
"""
|
||||
@ -126,9 +116,6 @@ def compute_el_header_block_hash(spec,
|
||||
execution_payload_header_rlp.append((big_endian_int, payload_header.excess_blob_gas))
|
||||
# parent_beacon_root
|
||||
execution_payload_header_rlp.append((Binary(32, 32), parent_beacon_block_root))
|
||||
if is_post_electra(spec):
|
||||
# requests_root
|
||||
execution_payload_header_rlp.append((Binary(32, 32), requests_trie_root))
|
||||
|
||||
sedes = List([schema for schema, _ in execution_payload_header_rlp])
|
||||
values = [value for _, value in execution_payload_header_rlp]
|
||||
@ -204,25 +191,19 @@ def get_consolidation_request_rlp_bytes(consolidation_request):
|
||||
return b"\x02" + encode(values, sedes)
|
||||
|
||||
|
||||
def compute_el_block_hash(spec, payload, pre_state):
|
||||
def compute_el_block_hash_with_parent_root(spec, payload, parent_beacon_block_root):
|
||||
if payload == spec.ExecutionPayload():
|
||||
return spec.Hash32()
|
||||
|
||||
transactions_trie_root = compute_trie_root_from_indexed_data(payload.transactions)
|
||||
|
||||
withdrawals_trie_root = None
|
||||
parent_beacon_block_root = None
|
||||
requests_trie_root = None
|
||||
|
||||
if is_post_capella(spec):
|
||||
withdrawals_encoded = [get_withdrawal_rlp(withdrawal) for withdrawal in payload.withdrawals]
|
||||
withdrawals_trie_root = compute_trie_root_from_indexed_data(withdrawals_encoded)
|
||||
if is_post_deneb(spec):
|
||||
parent_beacon_block_root = pre_state.latest_block_header.hash_tree_root()
|
||||
if is_post_electra(spec):
|
||||
requests_encoded = []
|
||||
requests_encoded += [get_deposit_request_rlp_bytes(request) for request in payload.deposit_requests]
|
||||
requests_encoded += [get_withdrawal_request_rlp_bytes(request) for request in payload.withdrawal_requests]
|
||||
requests_encoded += [get_consolidation_request_rlp_bytes(request) for request in payload.consolidation_requests]
|
||||
|
||||
requests_trie_root = compute_trie_root_from_indexed_data(requests_encoded)
|
||||
if not is_post_deneb(spec):
|
||||
parent_beacon_block_root = None
|
||||
|
||||
payload_header = get_execution_payload_header(spec, payload)
|
||||
|
||||
@ -232,10 +213,27 @@ def compute_el_block_hash(spec, payload, pre_state):
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root,
|
||||
parent_beacon_block_root,
|
||||
requests_trie_root,
|
||||
)
|
||||
|
||||
|
||||
def compute_el_block_hash(spec, payload, pre_state):
|
||||
parent_beacon_block_root = None
|
||||
|
||||
if is_post_deneb(spec):
|
||||
previous_block_header = pre_state.latest_block_header.copy()
|
||||
if previous_block_header.state_root == spec.Root():
|
||||
previous_block_header.state_root = pre_state.hash_tree_root()
|
||||
parent_beacon_block_root = previous_block_header.hash_tree_root()
|
||||
|
||||
return compute_el_block_hash_with_parent_root(
|
||||
spec, payload, parent_beacon_block_root)
|
||||
|
||||
|
||||
def compute_el_block_hash_for_block(spec, block):
|
||||
return compute_el_block_hash_with_parent_root(
|
||||
spec, block.body.execution_payload, block.parent_root)
|
||||
|
||||
|
||||
def build_empty_post_eip7732_execution_payload_header(spec, state):
|
||||
if not is_post_eip7732(spec):
|
||||
return
|
||||
@ -296,10 +294,6 @@ def build_empty_execution_payload(spec, state, randao_mix=None):
|
||||
if is_post_deneb(spec):
|
||||
payload.blob_gas_used = 0
|
||||
payload.excess_blob_gas = 0
|
||||
if is_post_electra(spec):
|
||||
payload.deposit_requests = []
|
||||
payload.withdrawal_requests = []
|
||||
payload.consolidation_requests = []
|
||||
|
||||
payload.block_hash = compute_el_block_hash(spec, payload, state)
|
||||
|
||||
|
@ -66,14 +66,11 @@ def get_sample_genesis_execution_payload_header(spec,
|
||||
transactions_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
withdrawals_trie_root = None
|
||||
parent_beacon_block_root = None
|
||||
requests_trie_root = None
|
||||
|
||||
if is_post_capella(spec):
|
||||
withdrawals_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
if is_post_deneb(spec):
|
||||
parent_beacon_block_root = bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000")
|
||||
if is_post_electra(spec):
|
||||
requests_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
payload_header.block_hash = compute_el_header_block_hash(
|
||||
spec,
|
||||
@ -81,7 +78,6 @@ def get_sample_genesis_execution_payload_header(spec,
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root,
|
||||
parent_beacon_block_root,
|
||||
requests_trie_root,
|
||||
)
|
||||
return payload_header
|
||||
|
||||
|
@ -2,6 +2,8 @@ from copy import deepcopy
|
||||
|
||||
from eth2spec.test.context import spec_state_test, expect_assertion_error, with_all_phases
|
||||
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
||||
from eth2spec.test.helpers.execution_payload import compute_el_block_hash_for_block
|
||||
from eth2spec.test.helpers.forks import is_post_bellatrix
|
||||
from eth2spec.test.helpers.state import next_slot
|
||||
|
||||
|
||||
@ -65,6 +67,8 @@ def test_invalid_proposer_index(spec, state):
|
||||
def test_invalid_parent_root(spec, state):
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.parent_root = b'\12' * 32 # invalid prev root
|
||||
if is_post_bellatrix(spec):
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block)
|
||||
|
||||
yield from run_block_header_processing(spec, state, block, valid=False)
|
||||
|
||||
@ -81,6 +85,8 @@ def test_invalid_multiple_blocks_single_slot(spec, state):
|
||||
|
||||
child_block = block.copy()
|
||||
child_block.parent_root = block.hash_tree_root()
|
||||
if is_post_bellatrix(spec):
|
||||
child_block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, child_block)
|
||||
|
||||
yield from run_block_header_processing(spec, state, child_block, prepare_state=False, valid=False)
|
||||
|
||||
|
@ -3,7 +3,11 @@ from eth2spec.test.context import spec_state_test, with_all_phases
|
||||
from eth2spec.test.helpers.epoch_processing import (
|
||||
run_epoch_processing_with, run_epoch_processing_to
|
||||
)
|
||||
from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_altair,
|
||||
is_post_bellatrix,
|
||||
is_post_electra,
|
||||
)
|
||||
from eth2spec.test.helpers.random import randomize_state
|
||||
from eth2spec.test.helpers.state import has_active_balance_differential
|
||||
from eth2spec.test.helpers.voluntary_exits import get_unslashed_exited_validators
|
||||
@ -40,6 +44,18 @@ def get_slashing_multiplier(spec):
|
||||
return spec.PROPORTIONAL_SLASHING_MULTIPLIER
|
||||
|
||||
|
||||
def _compute_expected_correlation_penalty(spec, effective_balance, total_slashed_balance, total_balance):
|
||||
if is_post_electra(spec):
|
||||
return ((get_slashing_multiplier(spec) * total_slashed_balance)
|
||||
// (total_balance // spec.EFFECTIVE_BALANCE_INCREMENT)
|
||||
* (effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT))
|
||||
else:
|
||||
return (effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
* (get_slashing_multiplier(spec) * total_slashed_balance)
|
||||
// total_balance
|
||||
* spec.EFFECTIVE_BALANCE_INCREMENT)
|
||||
|
||||
|
||||
def _setup_process_slashings_test(spec, state, not_slashable_set=set()):
|
||||
# Slashed count to ensure that enough validators are slashed to induce maximum penalties
|
||||
slashed_count = min(
|
||||
@ -99,7 +115,8 @@ def test_minimal_penalty(spec, state):
|
||||
#
|
||||
|
||||
# Just the bare minimum for this one validator
|
||||
state.balances[0] = state.validators[0].effective_balance = spec.config.EJECTION_BALANCE
|
||||
state.balances[0] = state.validators[0].effective_balance = (
|
||||
spec.config.EJECTION_BALANCE + spec.EFFECTIVE_BALANCE_INCREMENT)
|
||||
# All the other validators get the maximum.
|
||||
for i in range(1, len(state.validators)):
|
||||
state.validators[i].effective_balance = state.balances[i] = spec.MAX_EFFECTIVE_BALANCE
|
||||
@ -119,15 +136,10 @@ def test_minimal_penalty(spec, state):
|
||||
spec.process_slashings(state)
|
||||
yield 'post', state
|
||||
|
||||
expected_penalty = (
|
||||
state.validators[0].effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
* (get_slashing_multiplier(spec) * total_penalties)
|
||||
// total_balance
|
||||
* spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
)
|
||||
expected_penalty = _compute_expected_correlation_penalty(
|
||||
spec, state.validators[0].effective_balance, total_penalties, total_balance)
|
||||
|
||||
assert expected_penalty == 0
|
||||
assert state.balances[0] == pre_slash_balances[0]
|
||||
assert state.balances[0] == pre_slash_balances[0] - expected_penalty
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@ -181,12 +193,8 @@ def test_scaled_penalties(spec, state):
|
||||
|
||||
for i in slashed_indices:
|
||||
v = state.validators[i]
|
||||
expected_penalty = (
|
||||
v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
* (get_slashing_multiplier(spec) * total_penalties)
|
||||
// (total_balance)
|
||||
* spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
)
|
||||
expected_penalty = _compute_expected_correlation_penalty(
|
||||
spec, v.effective_balance, total_penalties, total_balance)
|
||||
assert state.balances[i] == pre_slash_balances[i] - expected_penalty
|
||||
|
||||
|
||||
|
@ -18,6 +18,9 @@ from eth2spec.test.helpers.block import (
|
||||
transition_unsigned_block,
|
||||
sign_block,
|
||||
)
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
compute_el_block_hash_for_block,
|
||||
)
|
||||
from eth2spec.test.helpers.fork_choice import (
|
||||
get_genesis_forkchoice_store_and_block,
|
||||
on_tick_and_append_step,
|
||||
@ -28,6 +31,9 @@ from eth2spec.test.helpers.fork_choice import (
|
||||
is_ready_to_justify,
|
||||
find_next_justifying_slot,
|
||||
)
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_bellatrix,
|
||||
)
|
||||
from eth2spec.test.helpers.state import (
|
||||
next_epoch,
|
||||
next_slots,
|
||||
@ -152,6 +158,8 @@ def test_on_block_bad_parent_root(spec, state):
|
||||
block.state_root = state.hash_tree_root()
|
||||
|
||||
block.parent_root = b'\x45' * 32
|
||||
if is_post_bellatrix(spec):
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block)
|
||||
|
||||
signed_block = sign_block(spec, state, block)
|
||||
|
||||
|
@ -20,7 +20,10 @@ from eth2spec.test.helpers.attester_slashings import (
|
||||
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing, check_proposer_slashing_effect
|
||||
from eth2spec.test.helpers.attestations import get_valid_attestation
|
||||
from eth2spec.test.helpers.deposits import prepare_state_and_deposit
|
||||
from eth2spec.test.helpers.execution_payload import build_empty_execution_payload
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
build_empty_execution_payload,
|
||||
compute_el_block_hash_for_block,
|
||||
)
|
||||
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits
|
||||
from eth2spec.test.helpers.multi_operations import (
|
||||
run_slash_and_exit,
|
||||
@ -158,7 +161,7 @@ def process_and_sign_block_without_header_validations(spec, state, block):
|
||||
if is_post_altair(spec):
|
||||
spec.process_sync_aggregate(state, block.body.sync_aggregate)
|
||||
|
||||
# Insert post-state rot
|
||||
# Insert post-state root
|
||||
block.state_root = state.hash_tree_root()
|
||||
|
||||
# Sign block
|
||||
@ -197,11 +200,13 @@ def test_invalid_parent_from_same_slot(spec, state):
|
||||
signed_parent_block = state_transition_and_sign_block(spec, state, parent_block)
|
||||
|
||||
child_block = parent_block.copy()
|
||||
child_block.parent_root = state.latest_block_header.hash_tree_root()
|
||||
|
||||
if is_post_bellatrix(spec):
|
||||
child_block.body.execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
child_block.parent_root = state.latest_block_header.hash_tree_root()
|
||||
if is_post_bellatrix(spec):
|
||||
child_block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, child_block)
|
||||
|
||||
# Show that normal path through transition fails
|
||||
failed_state = state.copy()
|
||||
expect_assertion_error(
|
||||
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
@ -1,2 +0,0 @@
|
||||
pytest>=4.4
|
||||
../../../[generator]
|
Loading…
x
Reference in New Issue
Block a user