Skip to content

Commit bed7616

Browse files
EIP-7332 Refactor Beacon chain state transition function
1 parent ca04b1e commit bed7616

File tree

1 file changed

+74
-64
lines changed

1 file changed

+74
-64
lines changed

specs/_features/eip7732/beacon-chain.md

Lines changed: 74 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,9 @@
5050
- [Modified `process_operations`](#modified-process_operations)
5151
- [Payload Attestations](#payload-attestations)
5252
- [`process_payload_attestation`](#process_payload_attestation)
53-
- [Modified `process_execution_payload`](#modified-process_execution_payload)
54-
- [New `verify_execution_payload_envelope_signature`](#new-verify_execution_payload_envelope_signature)
5553
- [Modified `is_merge_transition_complete`](#modified-is_merge_transition_complete)
5654
- [Modified `validate_merge_block`](#modified-validate_merge_block)
55+
- [Execution payload processing](#execution-payload-processing)
5756

5857
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
5958
<!-- /TOC -->
@@ -415,19 +414,49 @@ def get_indexed_payload_attestation(state: BeaconState, slot: Slot,
415414

416415
## Beacon chain state transition function
417416

418-
*Note*: state transition is fundamentally modified in EIP-7732. The full state transition is broken in two parts, first importing a signed block and then importing an execution payload.
417+
### Modified `state_transition`
419418

420-
The post-state corresponding to a pre-state `state` and a signed beacon block `signed_block` is defined as `state_transition(state, signed_block)`. State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid. State transitions that cause a `uint64` overflow or underflow are also considered invalid.
419+
**Note:** This is modified to accept `signed_envelope` as an additional parameter. The state transition has been broken in two parts, first importing a signed block and then importing an execution payload. Even though the order must be followed, importing of the signed block and the execution payload can be done indepedently.
421420

422-
The post-state corresponding to a pre-state `state` and a signed execution payload envelope `signed_envelope` is defined as `process_execution_payload(state, signed_envelope)`. State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid. State transitions that cause an `uint64` overflow or underflow are also considered invalid.
421+
```python
422+
def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, signed_envelope: SignedExecutionPayloadEnvelope, validate_result: bool=True) -> None:
423+
block = signed_block.message
424+
# Process slots (including those with no blocks) since block
425+
process_slots(state, block.slot)
426+
# Verify block signature
427+
if validate_result:
428+
assert verify_block_signature(state, signed_block)
429+
# Process block
430+
process_block(state, block)
431+
# Verify state root
432+
if validate_result:
433+
assert block.state_root == hash_tree_root(state)
434+
# Verify execution payload signature
435+
if validate_result:
436+
assert verify_execution_payload_envelope_signature(state, signed_envelope) # [New in EIP-7732]
437+
# Process execution payload
438+
process_execution_payload(state, signed_envelope, EXECUTION_ENGINE) # [New in EIP-7732]
439+
# Verify state root
440+
if validate_result:
441+
assert signed_envelope.message.state_root == hash_tree_root(state) # [New in EIP-7732]
442+
```
443+
444+
```python
445+
def verify_execution_payload_envelope_signature(
446+
state: BeaconState, signed_envelope: SignedExecutionPayloadEnvelope) -> bool:
447+
builder = state.validators[signed_envelope.message.builder_index]
448+
signing_root = compute_signing_root(signed_envelope.message, get_domain(state, DOMAIN_BEACON_BUILDER))
449+
return bls.Verify(builder.pubkey, signing_root, signed_envelope.signature)
450+
```
423451

424452
### Block processing
425453

426454
```python
427455
def process_block(state: BeaconState, block: BeaconBlock) -> None:
428456
process_block_header(state, block)
429457
process_withdrawals(state) # [Modified in EIP-7732]
430-
process_execution_payload_header(state, block) # [Modified in EIP-7732, removed process_execution_payload]
458+
# Removed `process_execution_payload` in EIP-7732
459+
process_execution_payload_header(state, block) # [New in EIP-7732]
431460
process_randao(state, block.body)
432461
process_eth1_data(state, block.body)
433462
process_operations(state, block.body) # [Modified in EIP-7732]
@@ -592,27 +621,54 @@ def process_payload_attestation(state: BeaconState, payload_attestation: Payload
592621
increase_balance(state, proposer_index, proposer_reward)
593622
```
594623

595-
#### Modified `process_execution_payload`
624+
#### Modified `is_merge_transition_complete`
596625

597-
##### New `verify_execution_payload_envelope_signature`
626+
`is_merge_transition_complete` is modified only for testing purposes to add the blob kzg commitments root for an empty list
598627

599628
```python
600-
def verify_execution_payload_envelope_signature(
601-
state: BeaconState, signed_envelope: SignedExecutionPayloadEnvelope) -> bool:
602-
builder = state.validators[signed_envelope.message.builder_index]
603-
signing_root = compute_signing_root(signed_envelope.message, get_domain(state, DOMAIN_BEACON_BUILDER))
604-
return bls.Verify(builder.pubkey, signing_root, signed_envelope.signature)
629+
def is_merge_transition_complete(state: BeaconState) -> bool:
630+
header = ExecutionPayloadHeader()
631+
kzgs = List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]()
632+
header.blob_kzg_commitments_root = kzgs.hash_tree_root()
633+
634+
return state.latest_execution_payload_header != header
635+
```
636+
637+
#### Modified `validate_merge_block`
638+
`validate_merge_block` is modified to use the new `signed_execution_payload_header` message in the Beacon Block Body
639+
640+
```python
641+
def validate_merge_block(block: BeaconBlock) -> None:
642+
"""
643+
Check the parent PoW block of execution payload is a valid terminal PoW block.
644+
645+
Note: Unavailable PoW block(s) may later become available,
646+
and a client software MAY delay a call to ``validate_merge_block``
647+
until the PoW block(s) become available.
648+
"""
649+
if TERMINAL_BLOCK_HASH != Hash32():
650+
# If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
651+
assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
652+
assert block.body.signed_execution_payload_header.message.parent_block_hash == TERMINAL_BLOCK_HASH
653+
return
654+
655+
# Modified in EIP-7732
656+
pow_block = get_pow_block(block.body.signed_execution_payload_header.message.parent_block_hash)
657+
# Check if `pow_block` is available
658+
assert pow_block is not None
659+
pow_parent = get_pow_block(pow_block.parent_hash)
660+
# Check if `pow_parent` is available
661+
assert pow_parent is not None
662+
# Check if `pow_block` is a valid terminal PoW block
663+
assert is_valid_terminal_pow_block(pow_block, pow_parent)
605664
```
606665

607-
*Note*: `process_execution_payload` is now an independent check in state transition. It is called when importing a signed execution payload proposed by the builder of the current slot.
666+
### Execution payload processing
608667

609668
```python
610669
def process_execution_payload(state: BeaconState,
611670
signed_envelope: SignedExecutionPayloadEnvelope,
612-
execution_engine: ExecutionEngine, verify: bool = True) -> None:
613-
# Verify signature
614-
if verify:
615-
assert verify_execution_payload_envelope_signature(state, signed_envelope)
671+
execution_engine: ExecutionEngine) -> None:
616672
envelope = signed_envelope.message
617673
payload = envelope.payload
618674
# Cache latest block header state root
@@ -667,50 +723,4 @@ def process_execution_payload(state: BeaconState,
667723
# Cache the execution payload header and proposer
668724
state.latest_block_hash = payload.block_hash
669725
state.latest_full_slot = state.slot
670-
671-
# Verify the state root
672-
if verify:
673-
assert envelope.state_root == hash_tree_root(state)
674-
```
675-
676-
#### Modified `is_merge_transition_complete`
677-
678-
`is_merge_transition_complete` is modified only for testing purposes to add the blob kzg commitments root for an empty list
679-
680-
```python
681-
def is_merge_transition_complete(state: BeaconState) -> bool:
682-
header = ExecutionPayloadHeader()
683-
kzgs = List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]()
684-
header.blob_kzg_commitments_root = kzgs.hash_tree_root()
685-
686-
return state.latest_execution_payload_header != header
687-
```
688-
689-
#### Modified `validate_merge_block`
690-
`validate_merge_block` is modified to use the new `signed_execution_payload_header` message in the Beacon Block Body
691-
692-
```python
693-
def validate_merge_block(block: BeaconBlock) -> None:
694-
"""
695-
Check the parent PoW block of execution payload is a valid terminal PoW block.
696-
697-
Note: Unavailable PoW block(s) may later become available,
698-
and a client software MAY delay a call to ``validate_merge_block``
699-
until the PoW block(s) become available.
700-
"""
701-
if TERMINAL_BLOCK_HASH != Hash32():
702-
# If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
703-
assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
704-
assert block.body.signed_execution_payload_header.message.parent_block_hash == TERMINAL_BLOCK_HASH
705-
return
706-
707-
# Modified in EIP-7732
708-
pow_block = get_pow_block(block.body.signed_execution_payload_header.message.parent_block_hash)
709-
# Check if `pow_block` is available
710-
assert pow_block is not None
711-
pow_parent = get_pow_block(pow_block.parent_hash)
712-
# Check if `pow_parent` is available
713-
assert pow_parent is not None
714-
# Check if `pow_block` is a valid terminal PoW block
715-
assert is_valid_terminal_pow_block(pow_block, pow_parent)
716726
```

0 commit comments

Comments
 (0)