Add EIP-6800 linter checks.

Fix the lint errors.
Remove custom type `StateDiff` and then use `List[StemStateDiff, MAX_STEMS]` directly in `ExecutionWitness`.
This commit is contained in:
Hsiao-Wei Wang 2024-05-28 16:24:11 +08:00
parent fd246d8ebf
commit 744ae2e687
No known key found for this signature in database
GPG Key ID: AE3D6B174F971DE4
13 changed files with 99 additions and 34 deletions

1
.gitignore vendored
View File

@ -24,6 +24,7 @@ tests/core/pyspec/eth2spec/deneb/
tests/core/pyspec/eth2spec/electra/ tests/core/pyspec/eth2spec/electra/
tests/core/pyspec/eth2spec/whisk/ tests/core/pyspec/eth2spec/whisk/
tests/core/pyspec/eth2spec/eip7594/ tests/core/pyspec/eth2spec/eip7594/
tests/core/pyspec/eth2spec/eip6800/
# coverage reports # coverage reports
.htmlcov .htmlcov

View File

@ -35,7 +35,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \
$(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \
$(wildcard $(SSZ_DIR)/*.md) $(wildcard $(SSZ_DIR)/*.md)
ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra whisk ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra whisk eip6800
# The parameters for commands. Use `foreach` to avoid listing specs again. # The parameters for commands. Use `foreach` to avoid listing specs again.
COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE))
PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S)

View File

@ -0,0 +1,12 @@
# Mainnet preset - EIP6800
# Misc
# ---------------------------------------------------------------
# `uint64(2**16)` (= 65,536)
MAX_STEMS: 65536
# `uint64(33)`
MAX_COMMITMENTS_PER_STEM: 33
# `uint64(2**8)` (= 256)
VERKLE_WIDTH: 256
# `uint64(2**3)` (= 8)
IPA_PROOF_DEPTH: 8

View File

@ -0,0 +1,12 @@
# Minimal preset - EIP6800
# Execution
# ---------------------------------------------------------------
# `uint64(2**16)` (= 65,536)
MAX_STEMS: 65536
# `uint64(33)`
MAX_COMMITMENTS_PER_STEM: 33
# `uint64(2**8)` (= 256)
VERKLE_WIDTH: 256
# `uint64(2**3)` (= 8)
IPA_PROOF_DEPTH: 8

View File

@ -6,10 +6,10 @@ CAPELLA = 'capella'
DENEB = 'deneb' DENEB = 'deneb'
ELECTRA = 'electra' ELECTRA = 'electra'
EIP7594 = 'eip7594' EIP7594 = 'eip7594'
EIP6800 = 'eip6800'
WHISK = 'whisk' WHISK = 'whisk'
# The helper functions that are used when defining constants # The helper functions that are used when defining constants
CONSTANT_DEP_SUNDRY_CONSTANTS_FUNCTIONS = ''' CONSTANT_DEP_SUNDRY_CONSTANTS_FUNCTIONS = '''
def ceillog2(x: int) -> uint64: def ceillog2(x: int) -> uint64:

View File

@ -178,7 +178,7 @@ def combine_dicts(old_dict: Dict[str, T], new_dict: Dict[str, T]) -> Dict[str, T
ignored_dependencies = [ ignored_dependencies = [
'bit', 'boolean', 'Vector', 'List', 'Container', 'BLSPubkey', 'BLSSignature', 'bit', 'boolean', 'Vector', 'List', 'Container', 'BLSPubkey', 'BLSSignature',
'Bytes1', 'Bytes4', 'Bytes8', 'Bytes20', 'Bytes32', 'Bytes48', 'Bytes96', 'Bitlist', 'Bitvector', 'Bytes1', 'Bytes4', 'Bytes8', 'Bytes20', 'Bytes31', 'Bytes32', 'Bytes48', 'Bytes96', 'Bitlist', 'Bitvector',
'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256', 'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256',
'bytes', 'byte', 'ByteList', 'ByteVector', 'bytes', 'byte', 'ByteList', 'ByteVector',
'Dict', 'dict', 'field', 'ceillog2', 'floorlog2', 'Set', 'Dict', 'dict', 'field', 'ceillog2', 'floorlog2', 'Set',

View File

@ -9,6 +9,7 @@ from .constants import (
ELECTRA, ELECTRA,
WHISK, WHISK,
EIP7594, EIP7594,
EIP6800,
) )
@ -21,6 +22,7 @@ PREVIOUS_FORK_OF = {
ELECTRA: DENEB, ELECTRA: DENEB,
WHISK: CAPELLA, WHISK: CAPELLA,
EIP7594: DENEB, EIP7594: DENEB,
EIP6800: DENEB,
} }
ALL_FORKS = list(PREVIOUS_FORK_OF.keys()) ALL_FORKS = list(PREVIOUS_FORK_OF.keys())

View File

@ -6,12 +6,13 @@ from .deneb import DenebSpecBuilder
from .electra import ElectraSpecBuilder from .electra import ElectraSpecBuilder
from .whisk import WhiskSpecBuilder from .whisk import WhiskSpecBuilder
from .eip7594 import EIP7594SpecBuilder from .eip7594 import EIP7594SpecBuilder
from .eip6800 import EIP6800SpecBuilder
spec_builders = { spec_builders = {
builder.fork: builder builder.fork: builder
for builder in ( for builder in (
Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder,
ElectraSpecBuilder, WhiskSpecBuilder, EIP7594SpecBuilder, ElectraSpecBuilder, WhiskSpecBuilder, EIP7594SpecBuilder, EIP6800SpecBuilder,
) )
} }

View File

@ -0,0 +1,21 @@
from typing import Dict
from .base import BaseSpecBuilder
from ..constants import EIP6800
class EIP6800SpecBuilder(BaseSpecBuilder):
fork: str = EIP6800
@classmethod
def imports(cls, preset_name: str):
return f'''
from eth2spec.deneb import {preset_name} as deneb
from eth2spec.utils.ssz.ssz_typing import Bytes31
'''
@classmethod
def hardcoded_custom_type_dep_constants(cls, spec_object) -> str:
return {
'MAX_STEMS': spec_object.preset_vars['MAX_STEMS'].value,
}

View File

@ -219,7 +219,13 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], pr
elif source.startswith("class"): elif source.startswith("class"):
class_name, parent_class = _get_class_info_from_source(source) class_name, parent_class = _get_class_info_from_source(source)
# check consistency with spec # check consistency with spec
try:
assert class_name == current_name assert class_name == current_name
except Exception:
print('class_name', class_name)
print('current_name', current_name)
raise
if parent_class: if parent_class:
assert parent_class == "Container" assert parent_class == "Container"
# NOTE: trim whitespace from spec # NOTE: trim whitespace from spec

View File

@ -1,4 +1,4 @@
# eip6800 -- The Beacon Chain # EIP6800 -- The Beacon Chain
## Table of contents ## Table of contents
@ -21,8 +21,6 @@
- [`VerkleProof`](#verkleproof) - [`VerkleProof`](#verkleproof)
- [`ExecutionWitness`](#executionwitness) - [`ExecutionWitness`](#executionwitness)
- [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Beacon chain state transition function](#beacon-chain-state-transition-function)
- [Execution engine](#execution-engine)
- [`notify_new_payload`](#notify_new_payload)
- [Block processing](#block-processing) - [Block processing](#block-processing)
- [Execution payload](#execution-payload) - [Execution payload](#execution-payload)
- [`process_execution_payload`](#process_execution_payload) - [`process_execution_payload`](#process_execution_payload)
@ -39,7 +37,6 @@ This upgrade adds transaction execution to the beacon chain as part of the eip68
| Name | SSZ equivalent | Description | | Name | SSZ equivalent | Description |
| - | - | - | | - | - | - |
| `StateDiff` | `List[StemStateDiff, MAX_STEMS]` | Only valid if list is sorted by stems |
| `BanderwagonGroupElement` | `Bytes32` | | | `BanderwagonGroupElement` | `Bytes32` | |
| `BanderwagonFieldElement` | `Bytes32` | | | `BanderwagonFieldElement` | `Bytes32` | |
| `Stem` | `Bytes31` | | | `Stem` | `Bytes31` | |
@ -50,10 +47,10 @@ This upgrade adds transaction execution to the beacon chain as part of the eip68
| Name | Value | | Name | Value |
| - | - | | - | - |
| `MAX_STEMS` | `2**16` | | `MAX_STEMS` | `uint64(2**16)` (= 65,536) |
| `MAX_COMMITMENTS_PER_STEM` | `33` | | `MAX_COMMITMENTS_PER_STEM` | `uint64(33)` |
| `VERKLE_WIDTH` | `256` | | `VERKLE_WIDTH` | `uint64(2**8)` (= 256) |
| `IPA_PROOF_DEPTH` | `8` | | `IPA_PROOF_DEPTH` | `uint64(2**3)` (= 8) |
## Containers ## Containers
@ -80,7 +77,9 @@ class ExecutionPayload(Container):
block_hash: Hash32 # Hash of execution block block_hash: Hash32 # Hash of execution block
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
execution_witness: ExecutionWitness # [New in eip6800] blob_gas_used: uint64
excess_blob_gas: uint64
execution_witness: ExecutionWitness # [New in EIP6800]
``` ```
#### `ExecutionPayloadHeader` #### `ExecutionPayloadHeader`
@ -104,8 +103,9 @@ class ExecutionPayloadHeader(Container):
block_hash: Hash32 # Hash of execution block block_hash: Hash32 # Hash of execution block
transactions_root: Root transactions_root: Root
withdrawals_root: Root withdrawals_root: Root
excess_data_gas: uint256 blob_gas_used: uint64
execution_witness_root: Root # [New in eip6800] excess_data_gas: uint64
execution_witness_root: Root # [New in EIP6800]
``` ```
### New containers ### New containers
@ -114,7 +114,7 @@ class ExecutionPayloadHeader(Container):
```python ```python
class SuffixStateDiff(Container): class SuffixStateDiff(Container):
suffix: Byte suffix: Bytes1
# Null means not currently present # Null means not currently present
current_value: Optional[Bytes32] current_value: Optional[Bytes32]
# Null means value not updated # Null means value not updated
@ -132,15 +132,10 @@ class StemStateDiff(Container):
suffix_diffs: List[SuffixStateDiff, VERKLE_WIDTH] suffix_diffs: List[SuffixStateDiff, VERKLE_WIDTH]
``` ```
```python
# Valid only if list is sorted by stems
StateDiff = List[StemStateDiff, MAX_STEMS]
```
#### `IPAProof` #### `IPAProof`
```python ```python
class IpaProof(Container): class IPAProof(Container):
cl: Vector[BanderwagonGroupElement, IPA_PROOF_DEPTH] cl: Vector[BanderwagonGroupElement, IPA_PROOF_DEPTH]
cr: Vector[BanderwagonGroupElement, IPA_PROOF_DEPTH] cr: Vector[BanderwagonGroupElement, IPA_PROOF_DEPTH]
final_evaluation = BanderwagonFieldElement final_evaluation = BanderwagonFieldElement
@ -154,14 +149,14 @@ class VerkleProof(Container):
depth_extension_present: ByteList[MAX_STEMS] depth_extension_present: ByteList[MAX_STEMS]
commitments_by_path: List[BanderwagonGroupElement, MAX_STEMS * MAX_COMMITMENTS_PER_STEM] commitments_by_path: List[BanderwagonGroupElement, MAX_STEMS * MAX_COMMITMENTS_PER_STEM]
d: BanderwagonGroupElement d: BanderwagonGroupElement
ipa_proof: IpaProof ipa_proof: IPAProof
``` ```
#### `ExecutionWitness` #### `ExecutionWitness`
```python ```python
class ExecutionWitness(container): class ExecutionWitness(Container):
state_diff: StateDiff state_diff: List[StemStateDiff, MAX_STEMS]
verkle_proof: VerkleProof verkle_proof: VerkleProof
``` ```
@ -174,16 +169,30 @@ class ExecutionWitness(container):
##### `process_execution_payload` ##### `process_execution_payload`
```python ```python
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None: def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None:
payload = body.execution_payload
# Verify consistency of the parent hash with respect to the previous execution payload header # Verify consistency of the parent hash with respect to the previous execution payload header
if is_merge_transition_complete(state):
assert payload.parent_hash == state.latest_execution_payload_header.block_hash assert payload.parent_hash == state.latest_execution_payload_header.block_hash
# Verify prev_randao # Verify prev_randao
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state)) assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
# Verify timestamp # Verify timestamp
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
# Verify commitments are under limit
assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK
# Verify the execution payload is valid # Verify the execution payload is valid
assert execution_engine.notify_new_payload(payload) # Pass `versioned_hashes` to Execution Engine
# Pass `parent_beacon_block_root` to Execution Engine
versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments]
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,
)
)
# Cache execution payload header # Cache execution payload header
state.latest_execution_payload_header = ExecutionPayloadHeader( state.latest_execution_payload_header = ExecutionPayloadHeader(
@ -203,7 +212,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
transactions_root=hash_tree_root(payload.transactions), transactions_root=hash_tree_root(payload.transactions),
withdrawals_root=hash_tree_root(payload.withdrawals), withdrawals_root=hash_tree_root(payload.withdrawals),
excess_data_gas=payload.excess_data_gas, excess_data_gas=payload.excess_data_gas,
execution_witness=payload.execution_witness, # [New in eip6800] execution_witness=payload.execution_witness, # [New in EIP6800]
) )
``` ```

View File

@ -1,4 +1,4 @@
# eip6800 -- Fork Logic # EIP-6800 -- Fork Logic
## Table of contents ## Table of contents
@ -72,7 +72,7 @@ Care must be taken when transitioning through the fork boundary as implementatio
In particular, the outer `state_transition` function defined in the Phase 0 document will not expose the precise fork slot to execute the upgrade in the presence of skipped slots at the fork boundary. Instead, the logic must be within `process_slots`. In particular, the outer `state_transition` function defined in the Phase 0 document will not expose the precise fork slot to execute the upgrade in the presence of skipped slots at the fork boundary. Instead, the logic must be within `process_slots`.
```python ```python
def upgrade_to_eip6800(pre: capella.BeaconState) -> BeaconState: def upgrade_to_eip6800(pre: deneb.BeaconState) -> BeaconState:
epoch = capella.get_current_epoch(pre) epoch = capella.get_current_epoch(pre)
latest_execution_payload_header = ExecutionPayloadHeader( latest_execution_payload_header = ExecutionPayloadHeader(
parent_hash=pre.latest_execution_payload_header.parent_hash, parent_hash=pre.latest_execution_payload_header.parent_hash,

View File

@ -10,3 +10,4 @@ from remerkleable.core import BasicView, View, Path
Bytes20 = ByteVector[20] # type: ignore Bytes20 = ByteVector[20] # type: ignore
Bytes31 = ByteVector[31] # type: ignore