Merge branch 'dev' into sf-epochoverrides

This commit is contained in:
Etan Kissling 2022-12-05 16:22:24 +01:00
commit 8524f54433
No known key found for this signature in database
GPG Key ID: B21DA824C5A3D03D
12 changed files with 116 additions and 67 deletions

View File

@ -105,12 +105,12 @@ install_test:
# Testing against `minimal` config by default
test: pyspec
. venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.bellatrix.minimal --cov=eth2spec.capella.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec
python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.bellatrix.minimal --cov=eth2spec.capella.minimal --cov=eth2spec.eip4844.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec
# Testing against `minimal` config by default
find_test: pyspec
. venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.bellatrix.minimal --cov=eth2spec.capella.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec
python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.bellatrix.minimal --cov=eth2spec.capella.minimal --cov=eth2spec.eip4844.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec
citest: pyspec
mkdir -p $(TEST_REPORT_DIR);
@ -142,8 +142,8 @@ codespell:
lint: pyspec
. venv/bin/activate; cd $(PY_SPEC_DIR); \
flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \
&& pylint --disable=all --enable unused-argument ./eth2spec/phase0 ./eth2spec/altair ./eth2spec/bellatrix ./eth2spec/capella \
&& mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.bellatrix -p eth2spec.capella
&& pylint --rcfile $(LINTER_CONFIG_FILE) ./eth2spec/phase0 ./eth2spec/altair ./eth2spec/bellatrix ./eth2spec/capella ./eth2spec/eip4844 \
&& mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.bellatrix -p eth2spec.capella -p eth2spec.eip4844
lint_generators: pyspec
. venv/bin/activate; cd $(TEST_GENERATORS_DIR); \

View File

@ -24,7 +24,7 @@ Features are researched and developed in parallel, and then consolidated into se
### In-development Specifications
| Code Name or Topic | Specs | Notes |
| - | - | - |
| Capella (tentative) | <ul><li>Core</li><ul><li>[Beacon chain changes](specs/capella/beacon-chain.md)</li><li>[Capella fork](specs/capella/fork.md)</li></ul><li>Additions</li><ul><li>[Validator additions](specs/capella/validator.md)</li></ul></ul> |
| Capella (tentative) | <ul><li>Core</li><ul><li>[Beacon chain changes](specs/capella/beacon-chain.md)</li><li>[Capella fork](specs/capella/fork.md)</li></ul><li>Additions</li><ul><li>[Validator additions](specs/capella/validator.md)</li><li>[P2P networking](specs/capella/p2p-interface.md)</li></ul></ul> |
| EIP4844 (tentative) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/eip4844/beacon-chain.md)</li><li>[EIP-4844 fork](specs/eip4844/fork.md)</li><li>[Polynomial commitments](specs/eip4844/polynomial-commitments.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/eip4844/validator.md)</li><li>[P2P networking](specs/eip4844/p2p-interface.md)</li></ul></ul> |
| Sharding (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/sharding/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[P2P networking](specs/sharding/p2p-interface.md)</li></ul></ul> |
| Custody Game (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/custody_game/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/custody_game/validator.md)</li></ul></ul> | Dependent on sharding |

View File

@ -11,3 +11,8 @@ warn_unused_configs = True
warn_redundant_casts = True
ignore_missing_imports = True
# pylint
[MESSAGES CONTROL]
disable = all
enable = unused-argument

View File

@ -588,6 +588,7 @@ class NoopExecutionEngine(ExecutionEngine):
pass
def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload:
# pylint: disable=unused-argument
raise NotImplementedError("no default block production")
@ -643,12 +644,14 @@ T = TypeVar('T') # For generic function
def no_op(fn): # type: ignore
# pylint: disable=unused-argument
def wrapper(*args, **kw): # type: ignore
return None
return wrapper
def get_empty_list_result(fn): # type: ignore
# pylint: disable=unused-argument
def wrapper(*args, **kw): # type: ignore
return []
return wrapper
@ -663,7 +666,8 @@ get_expected_withdrawals = get_empty_list_result(get_expected_withdrawals)
# End
#
def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> Optional[BlobsSidecar]:
def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> PyUnion[BlobsSidecar, str]:
# pylint: disable=unused-argument
return "TEST"'''
@classmethod
@ -682,8 +686,8 @@ spec_builders = {
}
def is_spec_defined_type(value: str) -> bool:
return value.startswith(('ByteList', 'Union', 'Vector', 'List'))
def is_byte_vector(value: str) -> bool:
return value.startswith(('ByteVector'))
def objects_to_spec(preset_name: str,
@ -696,17 +700,8 @@ def objects_to_spec(preset_name: str,
new_type_definitions = (
'\n\n'.join(
[
f"class {key}({value}):\n pass\n"
f"class {key}({value}):\n pass\n" if not is_byte_vector(value) else f"class {key}({value}): # type: ignore\n pass\n"
for key, value in spec_object.custom_types.items()
if not is_spec_defined_type(value)
]
)
+ ('\n\n' if len([key for key, value in spec_object.custom_types.items() if is_spec_defined_type(value)]) > 0 else '')
+ '\n\n'.join(
[
f"{key} = {value}\n"
for key, value in spec_object.custom_types.items()
if is_spec_defined_type(value)
]
)
)

View File

@ -112,10 +112,10 @@ Up to `MAX_BLS_TO_EXECUTION_CHANGES`, [`BLSToExecutionChange`](./beacon-chain.md
## Enabling validator withdrawals
Validator balances are fully or partially withdrawn via an automatic process.
Validator balances are withdrawn periodically via an automatic process. For exited validators, the full balance is withdrawn. For active validators, the balance in excess of `MAX_EFFECTIVE_BALANCE` is withdrawn.
For validators, there is one prerequisite for this automated process:
withdrawal credentials pointing to an execution layer address, i.e. having an `ETH1_ADDRESS_WITHDRAWAL_PREFIX`.
There is one prerequisite for this automated process:
the validator's withdrawal credentials pointing to an execution layer address, i.e. having an `ETH1_ADDRESS_WITHDRAWAL_PREFIX`.
If a validator has a `BLS_WITHDRAWAL_PREFIX` withdrawal credential prefix, to participate in withdrawals the validator must
create a one-time message to change their withdrawal credential from the version authenticated with a BLS key to the

View File

@ -55,7 +55,7 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an exte
| Name | Value |
| - | - |
| `BLOB_TX_TYPE` | `uint8(0x05)` |
| `VERSIONED_HASH_VERSION_KZG` | `Bytes1(0x01)` |
| `VERSIONED_HASH_VERSION_KZG` | `Bytes1('0x01')` |
## Preset
@ -175,10 +175,13 @@ but MUST NOT be considered valid until a valid `BlobsSidecar` has been downloade
def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool:
# `retrieve_blobs_sidecar` is implementation dependent, raises an exception if not available.
sidecar = retrieve_blobs_sidecar(slot, beacon_block_root)
if sidecar == "TEST":
return True # For testing; remove once we have a way to inject `BlobsSidecar` into tests
validate_blobs_sidecar(slot, beacon_block_root, blob_kzg_commitments, sidecar)
# For testing, `retrieve_blobs_sidecar` returns "TEST.
# TODO: Remove it once we have a way to inject `BlobsSidecar` into tests.
if isinstance(sidecar, str):
return True
validate_blobs_sidecar(slot, beacon_block_root, blob_kzg_commitments, sidecar)
return True
```
@ -216,7 +219,7 @@ def tx_peek_blob_versioned_hashes(opaque_tx: Transaction) -> Sequence[VersionedH
```python
def verify_kzg_commitments_against_transactions(transactions: Sequence[Transaction],
kzg_commitments: Sequence[KZGCommitment]) -> bool:
all_versioned_hashes = []
all_versioned_hashes: List[VersionedHash] = []
for tx in transactions:
if tx[0] == BLOB_TX_TYPE:
all_versioned_hashes += tx_peek_blob_versioned_hashes(tx)
@ -283,7 +286,8 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
#### Blob KZG commitments
```python
def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody):
def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody) -> None:
# pylint: disable=unused-argument
assert verify_kzg_commitments_against_transactions(body.execution_payload.transactions, body.blob_kzg_commitments)
```

View File

@ -19,9 +19,10 @@
- [`reverse_bits`](#reverse_bits)
- [`bit_reversal_permutation`](#bit_reversal_permutation)
- [BLS12-381 helpers](#bls12-381-helpers)
- [`hash_to_bls_field`](#hash_to_bls_field)
- [`bytes_to_bls_field`](#bytes_to_bls_field)
- [`blob_to_polynomial`](#blob_to_polynomial)
- [`hash_to_bls_field`](#hash_to_bls_field)
- [`compute_challenges`](#compute_challenges)
- [`bls_modular_inverse`](#bls_modular_inverse)
- [`div`](#div)
- [`g1_lincomb`](#g1_lincomb)
@ -41,7 +42,6 @@
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction
This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the EIP-4844 specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations.
@ -138,14 +138,29 @@ def bit_reversal_permutation(sequence: Sequence[T]) -> Sequence[T]:
### BLS12-381 helpers
#### `hash_to_bls_field`
```python
def hash_to_bls_field(data: bytes) -> BLSFieldElement:
"""
Hash ``data`` and convert the output to a BLS scalar field element.
The output is not uniform over the BLS field.
"""
hashed_data = hash(data)
return BLSFieldElement(int.from_bytes(hashed_data, ENDIANNESS) % BLS_MODULUS)
```
#### `bytes_to_bls_field`
```python
def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement:
"""
Convert 32-byte value to a BLS field scalar. The output is not uniform over the BLS field.
Convert 32-byte value to a BLS scalar field element.
This function does not accept inputs greater than the BLS modulus.
"""
return int.from_bytes(b, ENDIANNESS) % BLS_MODULUS
field_element = int.from_bytes(b, ENDIANNESS)
assert field_element < BLS_MODULUS
return BLSFieldElement(field_element)
```
#### `blob_to_polynomial`
@ -157,37 +172,49 @@ def blob_to_polynomial(blob: Blob) -> Polynomial:
"""
polynomial = Polynomial()
for i in range(FIELD_ELEMENTS_PER_BLOB):
value = int.from_bytes(blob[i * BYTES_PER_FIELD_ELEMENT: (i + 1) * BYTES_PER_FIELD_ELEMENT], ENDIANNESS)
assert value < BLS_MODULUS
value = bytes_to_bls_field(blob[i * BYTES_PER_FIELD_ELEMENT: (i + 1) * BYTES_PER_FIELD_ELEMENT])
polynomial[i] = value
return polynomial
```
#### `hash_to_bls_field`
#### `compute_challenges`
```python
def hash_to_bls_field(polys: Sequence[Polynomial],
comms: Sequence[KZGCommitment]) -> BLSFieldElement:
def compute_challenges(polynomials: Sequence[Polynomial],
commitments: Sequence[KZGCommitment]) -> Tuple[Sequence[BLSFieldElement], BLSFieldElement]:
"""
Compute 32-byte hash of serialized polynomials and commitments concatenated.
This hash is then converted to a BLS field element, where the result is not uniform over the BLS field.
Return the BLS field element.
Return the Fiat-Shamir challenges required by the rest of the protocol.
The Fiat-Shamir logic works as per the following pseudocode:
hashed_data = hash(DOMAIN_SEPARATOR, polynomials, commitments)
r = hash(hashed_data, 0)
r_powers = [1, r, r**2, r**3, ...]
eval_challenge = hash(hashed_data, 1)
Then return `r_powers` and `eval_challenge` after converting them to BLS field elements.
The resulting field elements are not uniform over the BLS field.
"""
# Append the number of polynomials and the degree of each polynomial as a domain separator
num_polys = int.to_bytes(len(polys), 8, ENDIANNESS)
num_polynomials = int.to_bytes(len(polynomials), 8, ENDIANNESS)
degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS)
data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polys
data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polynomials
# Append each polynomial which is composed by field elements
for poly in polys:
for poly in polynomials:
for field_element in poly:
data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS)
# Append serialized G1 points
for commitment in comms:
for commitment in commitments:
data += commitment
return bytes_to_bls_field(hash(data))
# Transcript has been prepared: time to create the challenges
hashed_data = hash(data)
r = hash_to_bls_field(hashed_data + b'\x00')
r_powers = compute_powers(r, len(commitments))
eval_challenge = hash_to_bls_field(hashed_data + b'\x01')
return r_powers, eval_challenge
```
#### `bls_modular_inverse`
@ -198,7 +225,7 @@ def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement:
Compute the modular inverse of x
i.e. return y such that x * y % BLS_MODULUS == 1 and return 0 for x == 0
"""
return pow(x, -1, BLS_MODULUS) if x != 0 else 0
return BLSFieldElement(pow(x, -1, BLS_MODULUS)) if x != 0 else BLSFieldElement(0)
```
#### `div`
@ -208,7 +235,7 @@ def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement:
"""
Divide two field elements: ``x`` by `y``.
"""
return (int(x) * int(bls_modular_inverse(y))) % BLS_MODULUS
return BLSFieldElement((int(x) * int(bls_modular_inverse(y))) % BLS_MODULUS)
```
#### `g1_lincomb`
@ -234,11 +261,12 @@ def poly_lincomb(polys: Sequence[Polynomial],
Given a list of ``polynomials``, interpret it as a 2D matrix and compute the linear combination
of each column with `scalars`: return the resulting polynomials.
"""
result = [0] * len(polys[0])
assert len(polys) == len(scalars)
result = [0] * FIELD_ELEMENTS_PER_BLOB
for v, s in zip(polys, scalars):
for i, x in enumerate(v):
result[i] = (result[i] + int(s) * int(x)) % BLS_MODULUS
return [BLSFieldElement(x) for x in result]
return Polynomial([BLSFieldElement(x) for x in result])
```
#### `compute_powers`
@ -246,7 +274,7 @@ def poly_lincomb(polys: Sequence[Polynomial],
```python
def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
"""
Return ``x`` to power of [0, n-1].
Return ``x`` to power of [0, n-1], if n > 0. When n==0, an empty array is returned.
"""
current_power = 1
powers = []
@ -256,6 +284,7 @@ def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
return powers
```
### Polynomials
#### `evaluate_polynomial_in_evaluation_form`
@ -270,7 +299,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
"""
width = len(polynomial)
assert width == FIELD_ELEMENTS_PER_BLOB
inverse_width = bls_modular_inverse(width)
inverse_width = bls_modular_inverse(BLSFieldElement(width))
# Make sure we won't divide by zero during division
assert z not in ROOTS_OF_UNITY
@ -279,9 +308,11 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
result = 0
for i in range(width):
result += div(int(polynomial[i]) * int(roots_of_unity_brp[i]), (int(z) - int(roots_of_unity_brp[i])))
result = result * (pow(z, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS
return result
a = BLSFieldElement(int(polynomial[i]) * int(roots_of_unity_brp[i]) % BLS_MODULUS)
b = BLSFieldElement((int(BLS_MODULUS) + int(z) - int(roots_of_unity_brp[i])) % BLS_MODULUS)
result += int(div(a, b) % BLS_MODULUS)
result = result * int(pow(z, width, BLS_MODULUS) - 1) * int(inverse_width)
return BLSFieldElement(result % BLS_MODULUS)
```
### KZG
@ -341,17 +372,13 @@ def compute_kzg_proof(polynomial: Polynomial, z: BLSFieldElement) -> KZGProof:
Compute KZG proof at point `z` with `polynomial` being in evaluation form
Do this by computing the quotient polynomial in evaluation form: q(x) = (p(x) - p(z)) / (x - z)
"""
# To avoid SSZ overflow/underflow, convert element into int
polynomial = [int(i) for i in polynomial]
z = int(z)
y = evaluate_polynomial_in_evaluation_form(polynomial, z)
polynomial_shifted = [(p - int(y)) % BLS_MODULUS for p in polynomial]
polynomial_shifted = [BLSFieldElement((int(p) - int(y)) % BLS_MODULUS) for p in polynomial]
# Make sure we won't divide by zero during division
assert z not in ROOTS_OF_UNITY
denominator_poly = [(int(x) - z) % BLS_MODULUS for x in bit_reversal_permutation(ROOTS_OF_UNITY)]
denominator_poly = [BLSFieldElement((int(x) - int(z)) % BLS_MODULUS)
for x in bit_reversal_permutation(ROOTS_OF_UNITY)]
# Calculate quotient polynomial by doing point-by-point division
quotient_polynomial = [div(a, b) for a, b in zip(polynomial_shifted, denominator_poly)]
@ -367,17 +394,18 @@ def compute_aggregated_poly_and_commitment(
"""
Return (1) the aggregated polynomial, (2) the aggregated KZG commitment,
and (3) the polynomial evaluation random challenge.
This function should also work with blobs == [] and kzg_commitments == []
"""
assert len(blobs) == len(kzg_commitments)
# Convert blobs to polynomials
polynomials = [blob_to_polynomial(blob) for blob in blobs]
# Generate random linear combination challenges
r = hash_to_bls_field(polynomials, kzg_commitments)
r_powers = compute_powers(r, len(kzg_commitments))
evaluation_challenge = int(r_powers[-1]) * r % BLS_MODULUS
# Generate random linear combination and evaluation challenges
r_powers, evaluation_challenge = compute_challenges(polynomials, kzg_commitments)
# Create aggregated polynomial in evaluation form
aggregated_poly = Polynomial(poly_lincomb(polynomials, r_powers))
aggregated_poly = poly_lincomb(polynomials, r_powers)
# Compute commitment to aggregated polynomial
aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers))
@ -390,6 +418,7 @@ def compute_aggregated_poly_and_commitment(
```python
def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof:
"""
Given a list of blobs, return the aggregated KZG proof that is used to verify them against their commitments.
Public method.
"""
commitments = [blob_to_kzg_commitment(blob) for blob in blobs]
@ -405,8 +434,10 @@ def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof:
```python
def verify_aggregate_kzg_proof(blobs: Sequence[Blob],
expected_kzg_commitments: Sequence[KZGCommitment],
kzg_aggregated_proof: KZGCommitment) -> bool:
kzg_aggregated_proof: KZGProof) -> bool:
"""
Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments.
Public method.
"""
aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment(

View File

@ -46,6 +46,7 @@ Implementers may also retrieve blobs individually per transaction.
```python
def get_blobs_and_kzg_commitments(payload_id: PayloadId) -> Tuple[Sequence[BLSFieldElement], Sequence[KZGCommitment]]:
# pylint: disable=unused-argument
...
```

View File

@ -745,6 +745,8 @@ For example, if slot 4 were empty in the previous example, the returned array wo
`step` is deprecated and must be set to 1. Clients may respond with a single block if a larger step is returned during the deprecation transition period.
`/eth2/beacon_chain/req/beacon_blocks_by_range/1/` is deprecated. Clients MAY respond with an empty list during the deprecation transition period.
`BeaconBlocksByRange` is primarily used to sync historical blocks.
The request MUST be encoded as an SSZ-container.
@ -831,6 +833,8 @@ Clients MUST support requesting blocks since the latest finalized epoch.
Clients MUST respond with at least one block, if they have it.
Clients MAY limit the number of blocks in the response.
`/eth2/beacon_chain/req/beacon_blocks_by_root/1/` is deprecated. Clients MAY respond with an empty list during the deprecation transition period.
#### Ping
**Protocol ID:** `/eth2/beacon_chain/req/ping/1/`

View File

@ -25,6 +25,12 @@ def _run_validate_blobs_sidecar_test(spec, state, blob_count):
spec.validate_blobs_sidecar(block.slot, block.hash_tree_root(), expected_commitments, blobs_sidecar)
@with_eip4844_and_later
@spec_state_test
def test_validate_blobs_sidecar_zero_blobs(spec, state):
_run_validate_blobs_sidecar_test(spec, state, blob_count=0)
@with_eip4844_and_later
@spec_state_test
def test_validate_blobs_sidecar_one_blob(spec, state):

View File

@ -165,6 +165,9 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict=
elif post_spec.fork == CAPELLA:
assert state.fork.previous_version == post_spec.config.BELLATRIX_FORK_VERSION
assert state.fork.current_version == post_spec.config.CAPELLA_FORK_VERSION
elif post_spec.fork == EIP4844:
assert state.fork.previous_version == post_spec.config.CAPELLA_FORK_VERSION
assert state.fork.current_version == post_spec.config.EIP4844_FORK_VERSION
if with_block:
return state, _state_transition_and_sign_block_at_slot(post_spec, state, operation_dict=operation_dict)

View File

@ -60,7 +60,7 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
previous_version = spec.config.BELLATRIX_FORK_VERSION
current_version = spec.config.CAPELLA_FORK_VERSION
elif spec.fork == EIP4844:
previous_version = spec.config.BELLATRIX_FORK_VERSION
previous_version = spec.config.CAPELLA_FORK_VERSION
current_version = spec.config.EIP4844_FORK_VERSION
state = spec.BeaconState(