mirror of
https://github.com/ethereum/consensus-specs.git
synced 2026-02-01 17:14:55 -05:00
Merge pull request #3359 from ethereum/engine-versioned-hashes
Use `engine_newPayloadV3` to pass `versioned_hashes` to EL for validation
This commit is contained in:
67
setup.py
67
setup.py
@@ -336,6 +336,10 @@ class SpecBuilder(ABC):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@classmethod
|
||||
def execution_engine_cls(cls) -> str:
|
||||
raise NotImplementedError()
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]:
|
||||
@@ -469,6 +473,12 @@ get_attesting_indices = cache_this(
|
||||
),
|
||||
_get_attesting_indices, lru_size=SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT * 3)'''
|
||||
|
||||
|
||||
@classmethod
|
||||
def execution_engine_cls(cls) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
@classmethod
|
||||
def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]:
|
||||
return {}
|
||||
@@ -573,9 +583,11 @@ def get_execution_state(_execution_state_root: Bytes32) -> ExecutionState:
|
||||
|
||||
|
||||
def get_pow_chain_head() -> PowBlock:
|
||||
pass
|
||||
|
||||
pass"""
|
||||
|
||||
@classmethod
|
||||
def execution_engine_cls(cls) -> str:
|
||||
return "\n\n" + """
|
||||
class NoopExecutionEngine(ExecutionEngine):
|
||||
|
||||
def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
|
||||
@@ -592,6 +604,13 @@ class NoopExecutionEngine(ExecutionEngine):
|
||||
# pylint: disable=unused-argument
|
||||
raise NotImplementedError("no default block production")
|
||||
|
||||
def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
|
||||
return True
|
||||
|
||||
def verify_and_notify_new_payload(self: ExecutionEngine,
|
||||
new_payload_request: NewPayloadRequest) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
EXECUTION_ENGINE = NoopExecutionEngine()"""
|
||||
|
||||
@@ -658,6 +677,39 @@ def retrieve_blobs_and_proofs(beacon_block_root: Root) -> PyUnion[Tuple[Blob, KZ
|
||||
# pylint: disable=unused-argument
|
||||
return ("TEST", "TEST")'''
|
||||
|
||||
@classmethod
|
||||
def execution_engine_cls(cls) -> str:
|
||||
return "\n\n" + """
|
||||
class NoopExecutionEngine(ExecutionEngine):
|
||||
|
||||
def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> 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) -> 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()"""
|
||||
|
||||
|
||||
@classmethod
|
||||
def hardcoded_custom_type_dep_constants(cls, spec_object) -> str:
|
||||
constants = {
|
||||
@@ -691,6 +743,11 @@ def is_byte_vector(value: str) -> bool:
|
||||
return value.startswith(('ByteVector'))
|
||||
|
||||
|
||||
def make_function_abstract(protocol_def: ProtocolDefinition, key: str):
|
||||
function = protocol_def.functions[key].split('"""')
|
||||
protocol_def.functions[key] = function[0] + "..."
|
||||
|
||||
|
||||
def objects_to_spec(preset_name: str,
|
||||
spec_object: SpecObject,
|
||||
builder: SpecBuilder,
|
||||
@@ -708,6 +765,11 @@ def objects_to_spec(preset_name: str,
|
||||
)
|
||||
|
||||
def format_protocol(protocol_name: str, protocol_def: ProtocolDefinition) -> str:
|
||||
abstract_functions = ["verify_and_notify_new_payload"]
|
||||
for key in protocol_def.functions.keys():
|
||||
if key in abstract_functions:
|
||||
make_function_abstract(protocol_def, key)
|
||||
|
||||
protocol = f"class {protocol_name}(Protocol):"
|
||||
for fn_source in protocol_def.functions.values():
|
||||
fn_source = fn_source.replace("self: "+protocol_name, "self")
|
||||
@@ -783,6 +845,7 @@ def objects_to_spec(preset_name: str,
|
||||
+ ('\n\n\n' + protocols_spec if protocols_spec != '' else '')
|
||||
+ '\n\n\n' + functions_spec
|
||||
+ '\n\n' + builder.sundry_functions()
|
||||
+ builder.execution_engine_cls()
|
||||
# Since some constants are hardcoded in setup.py, the following assertions verify that the hardcoded constants are
|
||||
# as same as the spec definition.
|
||||
+ ('\n\n\n' + ssz_dep_constants_verification if ssz_dep_constants_verification != '' else '')
|
||||
|
||||
@@ -177,12 +177,11 @@ class BeaconState(Container):
|
||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
process_withdrawals(state, block.body.execution_payload)
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP6110]
|
||||
process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in EIP6110]
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body) # [Modified in EIP6110]
|
||||
process_sync_aggregate(state, block.body.sync_aggregate)
|
||||
process_blob_kzg_commitments(block.body)
|
||||
```
|
||||
|
||||
#### Modified `process_operations`
|
||||
@@ -236,7 +235,9 @@ def process_deposit_receipt(state: BeaconState, deposit_receipt: DepositReceipt)
|
||||
*Note*: The function `process_execution_payload` is modified to use the new `ExecutionPayloadHeader` type.
|
||||
|
||||
```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
|
||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||
# Verify prev_randao
|
||||
@@ -244,7 +245,10 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
||||
# Verify timestamp
|
||||
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
|
||||
# Verify the execution payload is valid
|
||||
assert execution_engine.notify_new_payload(payload)
|
||||
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)
|
||||
)
|
||||
# Cache execution payload header
|
||||
state.latest_execution_payload_header = ExecutionPayloadHeader(
|
||||
parent_hash=payload.parent_hash,
|
||||
|
||||
@@ -33,7 +33,12 @@
|
||||
- [Modified `slash_validator`](#modified-slash_validator)
|
||||
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
||||
- [Execution engine](#execution-engine)
|
||||
- [Request data](#request-data)
|
||||
- [`NewPayloadRequest`](#newpayloadrequest)
|
||||
- [Engine APIs](#engine-apis)
|
||||
- [`notify_new_payload`](#notify_new_payload)
|
||||
- [`is_valid_block_hash`](#is_valid_block_hash)
|
||||
- [`verify_and_notify_new_payload`](#verify_and_notify_new_payload)
|
||||
- [Block processing](#block-processing)
|
||||
- [Execution payload](#execution-payload)
|
||||
- [`process_execution_payload`](#process_execution_payload)
|
||||
@@ -300,18 +305,30 @@ def slash_validator(state: BeaconState,
|
||||
|
||||
### Execution engine
|
||||
|
||||
#### Request data
|
||||
|
||||
##### `NewPayloadRequest`
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class NewPayloadRequest(object):
|
||||
execution_payload: ExecutionPayload
|
||||
```
|
||||
|
||||
#### Engine APIs
|
||||
|
||||
The implementation-dependent `ExecutionEngine` protocol encapsulates the execution sub-system logic via:
|
||||
|
||||
* a state object `self.execution_state` of type `ExecutionState`
|
||||
* a notification function `self.notify_new_payload` which may apply changes to the `self.execution_state`
|
||||
|
||||
*Note*: `notify_new_payload` is a function accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol.
|
||||
|
||||
The body of this function is implementation dependent.
|
||||
The body of these functions are implementation dependent.
|
||||
The Engine API may be used to implement this and similarly defined functions via an external execution engine.
|
||||
|
||||
#### `notify_new_payload`
|
||||
|
||||
`notify_new_payload` is a function accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol.
|
||||
|
||||
```python
|
||||
def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
|
||||
"""
|
||||
@@ -320,6 +337,31 @@ def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayloa
|
||||
...
|
||||
```
|
||||
|
||||
#### `is_valid_block_hash`
|
||||
|
||||
```python
|
||||
def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
|
||||
"""
|
||||
Return ``True`` if and only if ``execution_payload.block_hash`` is computed correctly.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
#### `verify_and_notify_new_payload`
|
||||
|
||||
```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``.
|
||||
"""
|
||||
if not self.is_valid_block_hash(new_payload_request.execution_payload):
|
||||
return False
|
||||
if not self.notify_new_payload(new_payload_request.execution_payload):
|
||||
return False
|
||||
return True
|
||||
```
|
||||
|
||||
### Block processing
|
||||
|
||||
*Note*: The call to the `process_execution_payload` must happen before the call to the `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block.
|
||||
@@ -328,7 +370,7 @@ def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayloa
|
||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
if is_execution_enabled(state, block.body):
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [New in Bellatrix]
|
||||
process_execution_payload(state, block.body, EXECUTION_ENGINE) # [New in Bellatrix]
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body)
|
||||
@@ -340,7 +382,9 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
##### `process_execution_payload`
|
||||
|
||||
```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
|
||||
if is_merge_transition_complete(state):
|
||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||
@@ -349,7 +393,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
||||
# Verify timestamp
|
||||
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
|
||||
# Verify the execution payload is valid
|
||||
assert execution_engine.notify_new_payload(payload)
|
||||
assert execution_engine.verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload))
|
||||
# Cache execution payload header
|
||||
state.latest_execution_payload_header = ExecutionPayloadHeader(
|
||||
parent_hash=payload.parent_hash,
|
||||
|
||||
@@ -333,7 +333,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
# [Modified in Capella] Removed `is_execution_enabled` check in Capella
|
||||
process_withdrawals(state, block.body.execution_payload) # [New in Capella]
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Capella]
|
||||
process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in Capella]
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body) # [Modified in Capella]
|
||||
@@ -404,10 +404,12 @@ 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 use the new `ExecutionPayloadHeader` type
|
||||
and removed the `is_merge_transition_complete` check.
|
||||
|
||||
```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
|
||||
# [Modified in Capella] Removed `is_merge_transition_complete` check in Capella
|
||||
# Verify consistency of the parent hash with respect to the previous execution payload header
|
||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||
@@ -416,7 +418,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
||||
# Verify timestamp
|
||||
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
|
||||
# Verify the execution payload is valid
|
||||
assert execution_engine.notify_new_payload(payload)
|
||||
assert execution_engine.verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload))
|
||||
# Cache execution payload header
|
||||
state.latest_execution_payload_header = ExecutionPayloadHeader(
|
||||
parent_hash=payload.parent_hash,
|
||||
|
||||
@@ -24,13 +24,16 @@
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Misc](#misc)
|
||||
- [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash)
|
||||
- [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes)
|
||||
- [`verify_kzg_commitments_against_transactions`](#verify_kzg_commitments_against_transactions)
|
||||
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
||||
- [Execution engine](#execution-engine)
|
||||
- [Request data](#request-data)
|
||||
- [Modified `NewPayloadRequest`](#modified-newpayloadrequest)
|
||||
- [Engine APIs](#engine-apis)
|
||||
- [`is_valid_versioned_hashes`](#is_valid_versioned_hashes)
|
||||
- [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload)
|
||||
- [Block processing](#block-processing)
|
||||
- [Execution payload](#execution-payload)
|
||||
- [`process_execution_payload`](#process_execution_payload)
|
||||
- [Blob KZG commitments](#blob-kzg-commitments)
|
||||
- [Testing](#testing)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
@@ -158,63 +161,65 @@ def kzg_commitment_to_versioned_hash(kzg_commitment: KZGCommitment) -> Versioned
|
||||
return VERSIONED_HASH_VERSION_KZG + hash(kzg_commitment)[1:]
|
||||
```
|
||||
|
||||
#### `tx_peek_blob_versioned_hashes`
|
||||
|
||||
This function retrieves the hashes from the `SignedBlobTransaction` as defined in Deneb, using SSZ offsets.
|
||||
Offsets are little-endian `uint32` values, as defined in the [SSZ specification](../../ssz/simple-serialize.md).
|
||||
See [the full details of `blob_versioned_hashes` offset calculation](https://gist.github.com/protolambda/23bd106b66f6d4bb854ce46044aa3ca3).
|
||||
|
||||
```python
|
||||
def tx_peek_blob_versioned_hashes(opaque_tx: Transaction) -> Sequence[VersionedHash]:
|
||||
assert opaque_tx[0] == BLOB_TX_TYPE
|
||||
message_offset = 1 + uint32.decode_bytes(opaque_tx[1:5])
|
||||
# field offset: 32 + 8 + 32 + 32 + 8 + 4 + 32 + 4 + 4 + 32 = 188
|
||||
blob_versioned_hashes_offset = (
|
||||
message_offset
|
||||
+ uint32.decode_bytes(opaque_tx[(message_offset + 188):(message_offset + 192)])
|
||||
)
|
||||
# `VersionedHash` is a 32-byte object
|
||||
assert (len(opaque_tx) - blob_versioned_hashes_offset) % 32 == 0
|
||||
return [
|
||||
VersionedHash(opaque_tx[x:(x + 32)])
|
||||
for x in range(blob_versioned_hashes_offset, len(opaque_tx), 32)
|
||||
]
|
||||
```
|
||||
|
||||
#### `verify_kzg_commitments_against_transactions`
|
||||
|
||||
```python
|
||||
def verify_kzg_commitments_against_transactions(transactions: Sequence[Transaction],
|
||||
kzg_commitments: Sequence[KZGCommitment]) -> bool:
|
||||
all_versioned_hashes: List[VersionedHash] = []
|
||||
for tx in transactions:
|
||||
if tx[0] == BLOB_TX_TYPE:
|
||||
all_versioned_hashes += tx_peek_blob_versioned_hashes(tx)
|
||||
return all_versioned_hashes == [kzg_commitment_to_versioned_hash(commitment) for commitment in kzg_commitments]
|
||||
```
|
||||
|
||||
## Beacon chain state transition function
|
||||
|
||||
### Block processing
|
||||
### Execution engine
|
||||
|
||||
#### Request data
|
||||
|
||||
##### Modified `NewPayloadRequest`
|
||||
|
||||
```python
|
||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
process_withdrawals(state, block.body.execution_payload)
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Deneb]
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body)
|
||||
process_sync_aggregate(state, block.body.sync_aggregate)
|
||||
process_blob_kzg_commitments(block.body) # [New in Deneb]
|
||||
@dataclass
|
||||
class NewPayloadRequest(object):
|
||||
execution_payload: ExecutionPayload
|
||||
versioned_hashes: Sequence[VersionedHash]
|
||||
```
|
||||
|
||||
#### Engine APIs
|
||||
|
||||
##### `is_valid_versioned_hashes`
|
||||
|
||||
```python
|
||||
def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool:
|
||||
"""
|
||||
Return ``True`` if and only if the version hashes computed by the blob transactions of
|
||||
``new_payload_request.execution_payload`` matches ``new_payload_request.version_hashes``.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
##### Modified `verify_and_notify_new_payload`
|
||||
|
||||
```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``.
|
||||
"""
|
||||
if not self.is_valid_block_hash(new_payload_request.execution_payload):
|
||||
return False
|
||||
|
||||
# [New in Deneb]
|
||||
if not self.is_valid_versioned_hashes(new_payload_request):
|
||||
return False
|
||||
|
||||
if not self.notify_new_payload(new_payload_request.execution_payload):
|
||||
return False
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
### Block processing
|
||||
|
||||
#### Execution payload
|
||||
|
||||
##### `process_execution_payload`
|
||||
|
||||
```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
|
||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||
# Verify prev_randao
|
||||
@@ -222,7 +227,11 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
||||
# Verify timestamp
|
||||
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
|
||||
# Verify the execution payload is valid
|
||||
assert execution_engine.notify_new_payload(payload)
|
||||
# [Modified in Deneb]
|
||||
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)
|
||||
)
|
||||
|
||||
# Cache execution payload header
|
||||
state.latest_execution_payload_header = ExecutionPayloadHeader(
|
||||
@@ -245,13 +254,6 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
||||
)
|
||||
```
|
||||
|
||||
#### Blob KZG commitments
|
||||
|
||||
```python
|
||||
def process_blob_kzg_commitments(body: BeaconBlockBody) -> None:
|
||||
assert verify_kzg_commitments_against_transactions(body.execution_payload.transactions, body.blob_kzg_commitments)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only.
|
||||
|
||||
@@ -101,22 +101,7 @@ All validator responsibilities remain unchanged other than those noted below.
|
||||
1. After retrieving the execution payload from the execution engine as specified in Capella,
|
||||
use the `payload_id` to retrieve `blobs`, `blob_kzg_commitments`, and `blob_kzg_proofs`
|
||||
via `get_payload(payload_id).blobs_bundle`.
|
||||
2. Validate `blobs` and `blob_kzg_commitments`:
|
||||
|
||||
```python
|
||||
def validate_blobs_and_kzg_commitments(execution_payload: ExecutionPayload,
|
||||
blobs: Sequence[Blob],
|
||||
blob_kzg_commitments: Sequence[KZGCommitment],
|
||||
blob_kzg_proofs: Sequence[KZGProof]) -> None:
|
||||
# Optionally sanity-check that the KZG commitments match the versioned hashes in the transactions
|
||||
assert verify_kzg_commitments_against_transactions(execution_payload.transactions, blob_kzg_commitments)
|
||||
|
||||
# Optionally sanity-check that the KZG commitments match the blobs (as produced by the execution engine)
|
||||
assert len(blob_kzg_commitments) == len(blobs) == len(blob_kzg_proofs)
|
||||
assert verify_blob_kzg_proof_batch(blobs, blob_kzg_commitments, blob_kzg_proofs)
|
||||
```
|
||||
|
||||
3. If valid, set `block.body.blob_kzg_commitments = blob_kzg_commitments`.
|
||||
2. Set `block.body.blob_kzg_commitments = blob_kzg_commitments`.
|
||||
|
||||
#### Constructing the `SignedBlobSidecar`s
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ these conditions.*
|
||||
|
||||
To optimistically import a block:
|
||||
|
||||
- The [`notify_new_payload`](../specs/bellatrix/beacon-chain.md#notify_new_payload) function MUST return `True` if the execution
|
||||
- The [`verify_and_notify_new_payload`](../specs/bellatrix/beacon-chain.md#verify_and_notify_new_payload) function MUST return `True` if the execution
|
||||
engine returns `NOT_VALIDATED` or `VALID`. An `INVALIDATED` response MUST return `False`.
|
||||
- The [`validate_merge_block`](../specs/bellatrix/fork-choice.md#validate_merge_block)
|
||||
function MUST NOT raise an assertion if both the
|
||||
@@ -172,7 +172,7 @@ In addition to this change in validation, the consensus engine MUST track which
|
||||
blocks returned `NOT_VALIDATED` and which returned `VALID` for subsequent processing.
|
||||
|
||||
Optimistically imported blocks MUST pass all verifications included in
|
||||
`process_block` (withstanding the modifications to `notify_new_payload`).
|
||||
`process_block` (withstanding the modifications to `verify_and_notify_new_payload`).
|
||||
|
||||
A consensus engine MUST be able to retrospectively (i.e., after import) modify
|
||||
the status of `NOT_VALIDATED` blocks to be either `VALID` or `INVALIDATED` based upon responses
|
||||
|
||||
@@ -27,33 +27,35 @@ def run_execution_payload_processing(spec, state, execution_payload, valid=True,
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
# Before Deneb, only `body.execution_payload` matters. `BeaconBlockBody` is just a wrapper.
|
||||
body = spec.BeaconBlockBody(execution_payload=execution_payload)
|
||||
|
||||
yield 'pre', state
|
||||
yield 'execution', {'execution_valid': execution_valid}
|
||||
yield 'execution_payload', execution_payload
|
||||
yield 'body', body
|
||||
|
||||
called_new_block = False
|
||||
|
||||
class TestEngine(spec.NoopExecutionEngine):
|
||||
def notify_new_payload(self, payload) -> bool:
|
||||
def verify_and_notify_new_payload(self, new_payload_request) -> bool:
|
||||
nonlocal called_new_block, execution_valid
|
||||
called_new_block = True
|
||||
assert payload == execution_payload
|
||||
assert new_payload_request.execution_payload == body.execution_payload
|
||||
return execution_valid
|
||||
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_execution_payload(state, execution_payload, TestEngine()))
|
||||
expect_assertion_error(lambda: spec.process_execution_payload(state, body, TestEngine()))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
spec.process_execution_payload(state, execution_payload, TestEngine())
|
||||
spec.process_execution_payload(state, body, TestEngine())
|
||||
|
||||
# Make sure we called the engine
|
||||
assert called_new_block
|
||||
|
||||
yield 'post', state
|
||||
|
||||
assert state.latest_execution_payload_header == get_execution_payload_header(spec, execution_payload)
|
||||
assert state.latest_execution_payload_header == get_execution_payload_header(spec, body.execution_payload)
|
||||
|
||||
|
||||
def run_success_test(spec, state):
|
||||
|
||||
@@ -56,7 +56,7 @@ def verify_post_state(state, spec, expected_withdrawals,
|
||||
def run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=None,
|
||||
fully_withdrawable_indices=None, partial_withdrawals_indices=None, valid=True):
|
||||
"""
|
||||
Run ``process_execution_payload``, yielding:
|
||||
Run ``process_withdrawals``, yielding:
|
||||
- pre-state ('pre')
|
||||
- execution payload ('execution_payload')
|
||||
- post-state ('post').
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
from random import Random
|
||||
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
build_empty_execution_payload,
|
||||
compute_el_block_hash,
|
||||
get_execution_payload_header,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
expect_assertion_error,
|
||||
with_deneb_and_later
|
||||
)
|
||||
from eth2spec.test.helpers.sharding import (
|
||||
get_sample_opaque_tx,
|
||||
)
|
||||
|
||||
|
||||
def run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments,
|
||||
valid=True, execution_valid=True):
|
||||
"""
|
||||
Run ``process_execution_payload``, yielding:
|
||||
- pre-state ('pre')
|
||||
- execution payload ('execution_payload')
|
||||
- execution details, to mock EVM execution ('execution.yml', a dict with 'execution_valid' key and boolean value)
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
# Before Deneb, only `body.execution_payload` matters. `BeaconBlockBody` is just a wrapper.
|
||||
body = spec.BeaconBlockBody(
|
||||
blob_kzg_commitments=blob_kzg_commitments,
|
||||
execution_payload=execution_payload
|
||||
)
|
||||
|
||||
yield 'pre', state
|
||||
yield 'execution', {'execution_valid': execution_valid}
|
||||
yield 'body', body
|
||||
|
||||
called_new_block = False
|
||||
|
||||
class TestEngine(spec.NoopExecutionEngine):
|
||||
def verify_and_notify_new_payload(self, new_payload_request) -> bool:
|
||||
nonlocal called_new_block, execution_valid
|
||||
called_new_block = True
|
||||
assert new_payload_request.execution_payload == body.execution_payload
|
||||
return execution_valid
|
||||
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_execution_payload(state, body, TestEngine()))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
spec.process_execution_payload(state, body, TestEngine())
|
||||
|
||||
# Make sure we called the engine
|
||||
assert called_new_block
|
||||
|
||||
yield 'post', state
|
||||
|
||||
assert state.latest_execution_payload_header == get_execution_payload_header(spec, body.execution_payload)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_blob_tx_type(spec, state):
|
||||
"""
|
||||
The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default.
|
||||
"""
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
opaque_tx = b'\x04' + opaque_tx[1:] # incorrect tx type
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_transaction_length_1_byte(spec, state):
|
||||
"""
|
||||
The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default.
|
||||
"""
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
opaque_tx = opaque_tx + b'\x12' # incorrect tx length
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_transaction_length_32_bytes(spec, state):
|
||||
"""
|
||||
The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default.
|
||||
"""
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
opaque_tx = opaque_tx + b'\x12' * 32 # incorrect tx length
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_commitment(spec, state):
|
||||
"""
|
||||
The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default.
|
||||
"""
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
blob_kzg_commitments[0] = b'\x12' * 48 # incorrect commitment
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_commitments_order(spec, state):
|
||||
"""
|
||||
The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default.
|
||||
"""
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=2, rng=Random(1111))
|
||||
blob_kzg_commitments = [blob_kzg_commitments[1], blob_kzg_commitments[0]] # incorrect order
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_block_hash(spec, state):
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = b'\x12' * 32 # incorrect block hash
|
||||
|
||||
# CL itself doesn't verify EL block hash
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_zeroed_commitment(spec, state):
|
||||
"""
|
||||
The blob is invalid, but the commitment is in correct form.
|
||||
"""
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=1, is_valid_blob=False)
|
||||
assert all(commitment == b'\x00' * 48 for commitment in blob_kzg_commitments)
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_correct_input__execution_invalid(spec, state):
|
||||
"""
|
||||
The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default.
|
||||
"""
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
|
||||
execution_payload.transactions = [opaque_tx]
|
||||
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments,
|
||||
valid=False, execution_valid=False)
|
||||
@@ -1,5 +1,3 @@
|
||||
import random
|
||||
|
||||
from eth2spec.test.helpers.state import (
|
||||
state_transition_and_sign_block
|
||||
)
|
||||
@@ -49,124 +47,3 @@ def test_one_blob(spec, state):
|
||||
@spec_state_test
|
||||
def test_max_blobs(spec, state):
|
||||
yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_incorrect_blob_tx_type(spec, state):
|
||||
yield 'pre', state
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
opaque_tx = b'\x04' + opaque_tx[1:] # incorrect tx type
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', None
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_incorrect_transaction_length_1_byte(spec, state):
|
||||
yield 'pre', state
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
opaque_tx = opaque_tx + b'\x12' # incorrect tx length
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', None
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_incorrect_transaction_length_32_bytes(spec, state):
|
||||
yield 'pre', state
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
opaque_tx = opaque_tx + b'\x12' * 32 # incorrect tx length
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', None
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_incorrect_commitment(spec, state):
|
||||
yield 'pre', state
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
blob_kzg_commitments[0] = b'\x12' * 48 # incorrect commitment
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', None
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_incorrect_commitments_order(spec, state):
|
||||
yield 'pre', state
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=2, rng=random.Random(1111))
|
||||
block.body.blob_kzg_commitments = [blob_kzg_commitments[1], blob_kzg_commitments[0]] # incorrect order
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', None
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_block_hash(spec, state):
|
||||
yield 'pre', state
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = b'\x12' * 32 # incorrect block hash
|
||||
# CL itself doesn't verify EL block hash
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_zeroed_commitment(spec, state):
|
||||
"""
|
||||
The blob is invalid, but the commitment is in correct form.
|
||||
"""
|
||||
yield 'pre', state
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=1, is_valid_blob=False)
|
||||
assert all(commitment == b'\x00' * 48 for commitment in blob_kzg_commitments)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
from eth2spec.test.helpers.constants import (
|
||||
DENEB,
|
||||
MINIMAL,
|
||||
)
|
||||
from eth2spec.test.helpers.sharding import (
|
||||
get_sample_opaque_tx,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
with_phases,
|
||||
spec_state_test,
|
||||
with_presets,
|
||||
)
|
||||
|
||||
|
||||
@with_phases([DENEB])
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_tx_peek_blob_versioned_hashes(spec, state):
|
||||
otx, _, commitments, _ = get_sample_opaque_tx(spec)
|
||||
data_hashes = spec.tx_peek_blob_versioned_hashes(otx)
|
||||
expected = [spec.kzg_commitment_to_versioned_hash(blob_commitment) for blob_commitment in commitments]
|
||||
assert expected == data_hashes
|
||||
@@ -2,7 +2,6 @@ from eth2spec.test.context import (
|
||||
always_bls,
|
||||
spec_state_test,
|
||||
with_deneb_and_later,
|
||||
expect_assertion_error
|
||||
)
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
compute_el_block_hash,
|
||||
@@ -18,96 +17,6 @@ from eth2spec.test.helpers.keys import (
|
||||
)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_validate_blobs_and_kzg_commitments(spec, state):
|
||||
"""
|
||||
Test `validate_blobs_and_kzg_commitments`
|
||||
"""
|
||||
blob_count = 4
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
spec.validate_blobs_and_kzg_commitments(block.body.execution_payload,
|
||||
blobs,
|
||||
blob_kzg_commitments,
|
||||
proofs)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_validate_blobs_and_kzg_commitments_missing_blob(spec, state):
|
||||
"""
|
||||
Test `validate_blobs_and_kzg_commitments`
|
||||
"""
|
||||
blob_count = 4
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
expect_assertion_error(
|
||||
lambda: spec.validate_blobs_and_kzg_commitments(
|
||||
block.body.execution_payload,
|
||||
blobs[:-1],
|
||||
blob_kzg_commitments,
|
||||
proofs
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_validate_blobs_and_kzg_commitments_missing_proof(spec, state):
|
||||
"""
|
||||
Test `validate_blobs_and_kzg_commitments`
|
||||
"""
|
||||
blob_count = 4
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
expect_assertion_error(
|
||||
lambda: spec.validate_blobs_and_kzg_commitments(
|
||||
block.body.execution_payload,
|
||||
blobs,
|
||||
blob_kzg_commitments,
|
||||
proofs[:-1]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_validate_blobs_and_kzg_commitments_incorrect_blob(spec, state):
|
||||
"""
|
||||
Test `validate_blobs_and_kzg_commitments`
|
||||
"""
|
||||
blob_count = 4
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
|
||||
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||
block.body.execution_payload.transactions = [opaque_tx]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
blobs[1] = spec.Blob(blobs[1][:13] + bytes([(blobs[1][13] + 1) % 256]) + blobs[1][14:])
|
||||
|
||||
expect_assertion_error(
|
||||
lambda: spec.validate_blobs_and_kzg_commitments(
|
||||
block.body.execution_payload,
|
||||
blobs,
|
||||
blob_kzg_commitments,
|
||||
proofs
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@with_deneb_and_later
|
||||
@spec_state_test
|
||||
def test_blob_sidecar_signature(spec, state):
|
||||
|
||||
@@ -91,7 +91,7 @@ def add_optimistic_block(spec, mega_store, signed_block, test_steps,
|
||||
Add a block with optimistic sync logic
|
||||
|
||||
``valid`` indicates if the given ``signed_block.message.body.execution_payload`` is valid/invalid
|
||||
from ``notify_new_payload`` method response.
|
||||
from ``verify_and_notify_new_payload`` method response.
|
||||
"""
|
||||
block = signed_block.message
|
||||
block_root = block.hash_tree_root()
|
||||
|
||||
@@ -143,7 +143,7 @@ def process_and_sign_block_without_header_validations(spec, state, block):
|
||||
)
|
||||
if is_post_bellatrix(spec):
|
||||
if spec.is_execution_enabled(state, block.body):
|
||||
spec.process_execution_payload(state, block.body.execution_payload, spec.EXECUTION_ENGINE)
|
||||
spec.process_execution_payload(state, block.body, spec.EXECUTION_ENGINE)
|
||||
|
||||
# Perform rest of process_block transitions
|
||||
spec.process_randao(state, block.body)
|
||||
|
||||
@@ -42,7 +42,7 @@ Operations:
|
||||
| `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` |
|
||||
| `voluntary_exit` | `SignedVoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` |
|
||||
| `sync_aggregate` | `SyncAggregate` | `sync_aggregate` | `process_sync_aggregate(state, sync_aggregate)` (new in Altair) |
|
||||
| `execution_payload` | `ExecutionPayload` | `execution_payload` | `process_execution_payload(state, execution_payload)` (new in Bellatrix) |
|
||||
| `execution_payload` | `BeaconBlockBody` | **`body`** | `process_execution_payload(state, body)` (new in Bellatrix) |
|
||||
| `withdrawals` | `ExecutionPayload` | `execution_payload` | `process_withdrawals(state, execution_payload)` (new in Capella) |
|
||||
| `bls_to_execution_change` | `SignedBLSToExecutionChange` | `address_change` | `process_bls_to_execution_change(state, address_change)` (new in Capella) |
|
||||
| `deposit_receipt` | `DepositReceipt` | `deposit_receipt` | `process_deposit_receipt(state, deposit_receipt)` (new in EIP6110) |
|
||||
|
||||
@@ -37,7 +37,10 @@ if __name__ == "__main__":
|
||||
]}
|
||||
capella_mods = combine_mods(_new_capella_mods, bellatrix_mods)
|
||||
|
||||
deneb_mods = capella_mods
|
||||
_new_deneb_mods = {key: 'eth2spec.test.deneb.block_processing.test_process_' + key for key in [
|
||||
'execution_payload',
|
||||
]}
|
||||
deneb_mods = combine_mods(_new_deneb_mods, capella_mods)
|
||||
|
||||
_new_eip6110_mods = {key: 'eth2spec.test.eip6110.block_processing.test_process_' + key for key in [
|
||||
'deposit_receipt',
|
||||
|
||||
Reference in New Issue
Block a user