Merge branch 'dev' into ci-phasesconfig
This commit is contained in:
commit
6cf8df086f
8
Makefile
8
Makefile
|
@ -105,12 +105,12 @@ install_test:
|
||||||
# Testing against `minimal` config by default
|
# Testing against `minimal` config by default
|
||||||
test: pyspec
|
test: pyspec
|
||||||
. venv/bin/activate; cd $(PY_SPEC_DIR); \
|
. 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
|
# Testing against `minimal` config by default
|
||||||
find_test: pyspec
|
find_test: pyspec
|
||||||
. venv/bin/activate; cd $(PY_SPEC_DIR); \
|
. 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
|
citest: pyspec
|
||||||
mkdir -p $(TEST_REPORT_DIR);
|
mkdir -p $(TEST_REPORT_DIR);
|
||||||
|
@ -142,8 +142,8 @@ codespell:
|
||||||
lint: pyspec
|
lint: pyspec
|
||||||
. venv/bin/activate; cd $(PY_SPEC_DIR); \
|
. venv/bin/activate; cd $(PY_SPEC_DIR); \
|
||||||
flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \
|
flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \
|
||||||
&& pylint --disable=all --enable unused-argument ./eth2spec/phase0 ./eth2spec/altair ./eth2spec/bellatrix ./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
|
&& mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.bellatrix -p eth2spec.capella -p eth2spec.eip4844
|
||||||
|
|
||||||
lint_generators: pyspec
|
lint_generators: pyspec
|
||||||
. venv/bin/activate; cd $(TEST_GENERATORS_DIR); \
|
. venv/bin/activate; cd $(TEST_GENERATORS_DIR); \
|
||||||
|
|
|
@ -24,7 +24,7 @@ Features are researched and developed in parallel, and then consolidated into se
|
||||||
### In-development Specifications
|
### In-development Specifications
|
||||||
| Code Name or Topic | Specs | Notes |
|
| 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> |
|
| 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> |
|
| 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 |
|
| 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 |
|
||||||
|
|
|
@ -11,3 +11,8 @@ warn_unused_configs = True
|
||||||
warn_redundant_casts = True
|
warn_redundant_casts = True
|
||||||
|
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
|
|
||||||
|
# pylint
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
disable = all
|
||||||
|
enable = unused-argument
|
||||||
|
|
21
setup.py
21
setup.py
|
@ -588,6 +588,7 @@ class NoopExecutionEngine(ExecutionEngine):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload:
|
def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload:
|
||||||
|
# pylint: disable=unused-argument
|
||||||
raise NotImplementedError("no default block production")
|
raise NotImplementedError("no default block production")
|
||||||
|
|
||||||
|
|
||||||
|
@ -643,12 +644,14 @@ T = TypeVar('T') # For generic function
|
||||||
|
|
||||||
|
|
||||||
def no_op(fn): # type: ignore
|
def no_op(fn): # type: ignore
|
||||||
|
# pylint: disable=unused-argument
|
||||||
def wrapper(*args, **kw): # type: ignore
|
def wrapper(*args, **kw): # type: ignore
|
||||||
return None
|
return None
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def get_empty_list_result(fn): # type: ignore
|
def get_empty_list_result(fn): # type: ignore
|
||||||
|
# pylint: disable=unused-argument
|
||||||
def wrapper(*args, **kw): # type: ignore
|
def wrapper(*args, **kw): # type: ignore
|
||||||
return []
|
return []
|
||||||
return wrapper
|
return wrapper
|
||||||
|
@ -663,7 +666,8 @@ get_expected_withdrawals = get_empty_list_result(get_expected_withdrawals)
|
||||||
# End
|
# 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"'''
|
return "TEST"'''
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -682,8 +686,8 @@ spec_builders = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def is_spec_defined_type(value: str) -> bool:
|
def is_byte_vector(value: str) -> bool:
|
||||||
return value.startswith(('ByteList', 'Union', 'Vector', 'List'))
|
return value.startswith(('ByteVector'))
|
||||||
|
|
||||||
|
|
||||||
def objects_to_spec(preset_name: str,
|
def objects_to_spec(preset_name: str,
|
||||||
|
@ -696,17 +700,8 @@ def objects_to_spec(preset_name: str,
|
||||||
new_type_definitions = (
|
new_type_definitions = (
|
||||||
'\n\n'.join(
|
'\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()
|
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)
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -112,10 +112,10 @@ Up to `MAX_BLS_TO_EXECUTION_CHANGES`, [`BLSToExecutionChange`](./beacon-chain.md
|
||||||
|
|
||||||
## Enabling validator withdrawals
|
## 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:
|
There is one prerequisite for this automated process:
|
||||||
withdrawal credentials pointing to an execution layer address, i.e. having an `ETH1_ADDRESS_WITHDRAWAL_PREFIX`.
|
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
|
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
|
create a one-time message to change their withdrawal credential from the version authenticated with a BLS key to the
|
||||||
|
|
|
@ -55,7 +55,7 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an exte
|
||||||
| Name | Value |
|
| Name | Value |
|
||||||
| - | - |
|
| - | - |
|
||||||
| `BLOB_TX_TYPE` | `uint8(0x05)` |
|
| `BLOB_TX_TYPE` | `uint8(0x05)` |
|
||||||
| `VERSIONED_HASH_VERSION_KZG` | `Bytes1(0x01)` |
|
| `VERSIONED_HASH_VERSION_KZG` | `Bytes1('0x01')` |
|
||||||
|
|
||||||
## Preset
|
## 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:
|
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.
|
# `retrieve_blobs_sidecar` is implementation dependent, raises an exception if not available.
|
||||||
sidecar = retrieve_blobs_sidecar(slot, beacon_block_root)
|
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
|
return True
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -216,7 +219,7 @@ def tx_peek_blob_versioned_hashes(opaque_tx: Transaction) -> Sequence[VersionedH
|
||||||
```python
|
```python
|
||||||
def verify_kzg_commitments_against_transactions(transactions: Sequence[Transaction],
|
def verify_kzg_commitments_against_transactions(transactions: Sequence[Transaction],
|
||||||
kzg_commitments: Sequence[KZGCommitment]) -> bool:
|
kzg_commitments: Sequence[KZGCommitment]) -> bool:
|
||||||
all_versioned_hashes = []
|
all_versioned_hashes: List[VersionedHash] = []
|
||||||
for tx in transactions:
|
for tx in transactions:
|
||||||
if tx[0] == BLOB_TX_TYPE:
|
if tx[0] == BLOB_TX_TYPE:
|
||||||
all_versioned_hashes += tx_peek_blob_versioned_hashes(tx)
|
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
|
#### Blob KZG commitments
|
||||||
|
|
||||||
```python
|
```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)
|
assert verify_kzg_commitments_against_transactions(body.execution_payload.transactions, body.blob_kzg_commitments)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,10 @@
|
||||||
- [`reverse_bits`](#reverse_bits)
|
- [`reverse_bits`](#reverse_bits)
|
||||||
- [`bit_reversal_permutation`](#bit_reversal_permutation)
|
- [`bit_reversal_permutation`](#bit_reversal_permutation)
|
||||||
- [BLS12-381 helpers](#bls12-381-helpers)
|
- [BLS12-381 helpers](#bls12-381-helpers)
|
||||||
|
- [`hash_to_bls_field`](#hash_to_bls_field)
|
||||||
- [`bytes_to_bls_field`](#bytes_to_bls_field)
|
- [`bytes_to_bls_field`](#bytes_to_bls_field)
|
||||||
- [`blob_to_polynomial`](#blob_to_polynomial)
|
- [`blob_to_polynomial`](#blob_to_polynomial)
|
||||||
- [`hash_to_bls_field`](#hash_to_bls_field)
|
- [`compute_challenges`](#compute_challenges)
|
||||||
- [`bls_modular_inverse`](#bls_modular_inverse)
|
- [`bls_modular_inverse`](#bls_modular_inverse)
|
||||||
- [`div`](#div)
|
- [`div`](#div)
|
||||||
- [`g1_lincomb`](#g1_lincomb)
|
- [`g1_lincomb`](#g1_lincomb)
|
||||||
|
@ -41,7 +42,6 @@
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
<!-- /TOC -->
|
<!-- /TOC -->
|
||||||
|
|
||||||
|
|
||||||
## Introduction
|
## 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.
|
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
|
### 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`
|
#### `bytes_to_bls_field`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement:
|
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`
|
#### `blob_to_polynomial`
|
||||||
|
@ -157,37 +172,49 @@ def blob_to_polynomial(blob: Blob) -> Polynomial:
|
||||||
"""
|
"""
|
||||||
polynomial = Polynomial()
|
polynomial = Polynomial()
|
||||||
for i in range(FIELD_ELEMENTS_PER_BLOB):
|
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)
|
value = bytes_to_bls_field(blob[i * BYTES_PER_FIELD_ELEMENT: (i + 1) * BYTES_PER_FIELD_ELEMENT])
|
||||||
assert value < BLS_MODULUS
|
|
||||||
polynomial[i] = value
|
polynomial[i] = value
|
||||||
return polynomial
|
return polynomial
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `hash_to_bls_field`
|
#### `compute_challenges`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def hash_to_bls_field(polys: Sequence[Polynomial],
|
def compute_challenges(polynomials: Sequence[Polynomial],
|
||||||
comms: Sequence[KZGCommitment]) -> BLSFieldElement:
|
commitments: Sequence[KZGCommitment]) -> Tuple[Sequence[BLSFieldElement], BLSFieldElement]:
|
||||||
"""
|
"""
|
||||||
Compute 32-byte hash of serialized polynomials and commitments concatenated.
|
Return the Fiat-Shamir challenges required by the rest of the protocol.
|
||||||
This hash is then converted to a BLS field element, where the result is not uniform over the BLS field.
|
The Fiat-Shamir logic works as per the following pseudocode:
|
||||||
Return the BLS field element.
|
|
||||||
|
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
|
# 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)
|
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
|
# Append each polynomial which is composed by field elements
|
||||||
for poly in polys:
|
for poly in polynomials:
|
||||||
for field_element in poly:
|
for field_element in poly:
|
||||||
data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS)
|
data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS)
|
||||||
|
|
||||||
# Append serialized G1 points
|
# Append serialized G1 points
|
||||||
for commitment in comms:
|
for commitment in commitments:
|
||||||
data += commitment
|
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`
|
#### `bls_modular_inverse`
|
||||||
|
@ -198,7 +225,7 @@ def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement:
|
||||||
Compute the modular inverse of x
|
Compute the modular inverse of x
|
||||||
i.e. return y such that x * y % BLS_MODULUS == 1 and return 0 for x == 0
|
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`
|
#### `div`
|
||||||
|
@ -208,7 +235,7 @@ def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement:
|
||||||
"""
|
"""
|
||||||
Divide two field elements: ``x`` by `y``.
|
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`
|
#### `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
|
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.
|
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 v, s in zip(polys, scalars):
|
||||||
for i, x in enumerate(v):
|
for i, x in enumerate(v):
|
||||||
result[i] = (result[i] + int(s) * int(x)) % BLS_MODULUS
|
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`
|
#### `compute_powers`
|
||||||
|
@ -246,7 +274,7 @@ def poly_lincomb(polys: Sequence[Polynomial],
|
||||||
```python
|
```python
|
||||||
def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
|
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
|
current_power = 1
|
||||||
powers = []
|
powers = []
|
||||||
|
@ -256,6 +284,7 @@ def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]:
|
||||||
return powers
|
return powers
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Polynomials
|
### Polynomials
|
||||||
|
|
||||||
#### `evaluate_polynomial_in_evaluation_form`
|
#### `evaluate_polynomial_in_evaluation_form`
|
||||||
|
@ -270,7 +299,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
|
||||||
"""
|
"""
|
||||||
width = len(polynomial)
|
width = len(polynomial)
|
||||||
assert width == FIELD_ELEMENTS_PER_BLOB
|
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
|
# Make sure we won't divide by zero during division
|
||||||
assert z not in ROOTS_OF_UNITY
|
assert z not in ROOTS_OF_UNITY
|
||||||
|
@ -279,9 +308,11 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
|
||||||
|
|
||||||
result = 0
|
result = 0
|
||||||
for i in range(width):
|
for i in range(width):
|
||||||
result += div(int(polynomial[i]) * int(roots_of_unity_brp[i]), (int(z) - int(roots_of_unity_brp[i])))
|
a = BLSFieldElement(int(polynomial[i]) * int(roots_of_unity_brp[i]) % BLS_MODULUS)
|
||||||
result = result * (pow(z, width, BLS_MODULUS) - 1) * inverse_width % BLS_MODULUS
|
b = BLSFieldElement((int(BLS_MODULUS) + int(z) - int(roots_of_unity_brp[i])) % BLS_MODULUS)
|
||||||
return result
|
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
|
### 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
|
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)
|
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)
|
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
|
# Make sure we won't divide by zero during division
|
||||||
assert z not in ROOTS_OF_UNITY
|
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
|
# Calculate quotient polynomial by doing point-by-point division
|
||||||
quotient_polynomial = [div(a, b) for a, b in zip(polynomial_shifted, denominator_poly)]
|
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,
|
Return (1) the aggregated polynomial, (2) the aggregated KZG commitment,
|
||||||
and (3) the polynomial evaluation random challenge.
|
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
|
# Convert blobs to polynomials
|
||||||
polynomials = [blob_to_polynomial(blob) for blob in blobs]
|
polynomials = [blob_to_polynomial(blob) for blob in blobs]
|
||||||
|
|
||||||
# Generate random linear combination challenges
|
# Generate random linear combination and evaluation challenges
|
||||||
r = hash_to_bls_field(polynomials, kzg_commitments)
|
r_powers, evaluation_challenge = compute_challenges(polynomials, kzg_commitments)
|
||||||
r_powers = compute_powers(r, len(kzg_commitments))
|
|
||||||
evaluation_challenge = int(r_powers[-1]) * r % BLS_MODULUS
|
|
||||||
|
|
||||||
# Create aggregated polynomial in evaluation form
|
# 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
|
# Compute commitment to aggregated polynomial
|
||||||
aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers))
|
aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers))
|
||||||
|
@ -390,6 +418,7 @@ def compute_aggregated_poly_and_commitment(
|
||||||
```python
|
```python
|
||||||
def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof:
|
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.
|
Public method.
|
||||||
"""
|
"""
|
||||||
commitments = [blob_to_kzg_commitment(blob) for blob in blobs]
|
commitments = [blob_to_kzg_commitment(blob) for blob in blobs]
|
||||||
|
@ -405,8 +434,10 @@ def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof:
|
||||||
```python
|
```python
|
||||||
def verify_aggregate_kzg_proof(blobs: Sequence[Blob],
|
def verify_aggregate_kzg_proof(blobs: Sequence[Blob],
|
||||||
expected_kzg_commitments: Sequence[KZGCommitment],
|
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.
|
Public method.
|
||||||
"""
|
"""
|
||||||
aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment(
|
aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment(
|
||||||
|
|
|
@ -46,6 +46,7 @@ Implementers may also retrieve blobs individually per transaction.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_blobs_and_kzg_commitments(payload_id: PayloadId) -> Tuple[Sequence[BLSFieldElement], Sequence[KZGCommitment]]:
|
def get_blobs_and_kzg_commitments(payload_id: PayloadId) -> Tuple[Sequence[BLSFieldElement], Sequence[KZGCommitment]]:
|
||||||
|
# pylint: disable=unused-argument
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -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.
|
`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.
|
`BeaconBlocksByRange` is primarily used to sync historical blocks.
|
||||||
|
|
||||||
The request MUST be encoded as an SSZ-container.
|
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 MUST respond with at least one block, if they have it.
|
||||||
Clients MAY limit the number of blocks in the response.
|
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
|
#### Ping
|
||||||
|
|
||||||
**Protocol ID:** `/eth2/beacon_chain/req/ping/1/`
|
**Protocol ID:** `/eth2/beacon_chain/req/ping/1/`
|
||||||
|
|
|
@ -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)
|
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
|
@with_eip4844_and_later
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_validate_blobs_sidecar_one_blob(spec, state):
|
def test_validate_blobs_sidecar_one_blob(spec, state):
|
||||||
|
|
|
@ -165,6 +165,9 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict=
|
||||||
elif post_spec.fork == CAPELLA:
|
elif post_spec.fork == CAPELLA:
|
||||||
assert state.fork.previous_version == post_spec.config.BELLATRIX_FORK_VERSION
|
assert state.fork.previous_version == post_spec.config.BELLATRIX_FORK_VERSION
|
||||||
assert state.fork.current_version == post_spec.config.CAPELLA_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:
|
if with_block:
|
||||||
return state, _state_transition_and_sign_block_at_slot(post_spec, state, operation_dict=operation_dict)
|
return state, _state_transition_and_sign_block_at_slot(post_spec, state, operation_dict=operation_dict)
|
||||||
|
|
|
@ -60,7 +60,7 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
|
||||||
previous_version = spec.config.BELLATRIX_FORK_VERSION
|
previous_version = spec.config.BELLATRIX_FORK_VERSION
|
||||||
current_version = spec.config.CAPELLA_FORK_VERSION
|
current_version = spec.config.CAPELLA_FORK_VERSION
|
||||||
elif spec.fork == EIP4844:
|
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
|
current_version = spec.config.EIP4844_FORK_VERSION
|
||||||
|
|
||||||
state = spec.BeaconState(
|
state = spec.BeaconState(
|
||||||
|
|
Loading…
Reference in New Issue