|
50 | 50 | - [Modified `process_operations`](#modified-process_operations) |
51 | 51 | - [Payload Attestations](#payload-attestations) |
52 | 52 | - [`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) |
55 | 53 | - [Modified `is_merge_transition_complete`](#modified-is_merge_transition_complete) |
56 | 54 | - [Modified `validate_merge_block`](#modified-validate_merge_block) |
| 55 | + - [Execution payload processing](#execution-payload-processing) |
57 | 56 |
|
58 | 57 | <!-- END doctoc generated TOC please keep comment here to allow auto update --> |
59 | 58 | <!-- /TOC --> |
@@ -415,19 +414,49 @@ def get_indexed_payload_attestation(state: BeaconState, slot: Slot, |
415 | 414 |
|
416 | 415 | ## Beacon chain state transition function |
417 | 416 |
|
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` |
419 | 418 |
|
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. |
421 | 420 |
|
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 | +``` |
423 | 451 |
|
424 | 452 | ### Block processing |
425 | 453 |
|
426 | 454 | ```python |
427 | 455 | def process_block(state: BeaconState, block: BeaconBlock) -> None: |
428 | 456 | process_block_header(state, block) |
429 | 457 | 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] |
431 | 460 | process_randao(state, block.body) |
432 | 461 | process_eth1_data(state, block.body) |
433 | 462 | process_operations(state, block.body) # [Modified in EIP-7732] |
@@ -592,27 +621,54 @@ def process_payload_attestation(state: BeaconState, payload_attestation: Payload |
592 | 621 | increase_balance(state, proposer_index, proposer_reward) |
593 | 622 | ``` |
594 | 623 |
|
595 | | -#### Modified `process_execution_payload` |
| 624 | +#### Modified `is_merge_transition_complete` |
596 | 625 |
|
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 |
598 | 627 |
|
599 | 628 | ```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) |
605 | 664 | ``` |
606 | 665 |
|
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 |
608 | 667 |
|
609 | 668 | ```python |
610 | 669 | def process_execution_payload(state: BeaconState, |
611 | 670 | 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: |
616 | 672 | envelope = signed_envelope.message |
617 | 673 | payload = envelope.payload |
618 | 674 | # Cache latest block header state root |
@@ -667,50 +723,4 @@ def process_execution_payload(state: BeaconState, |
667 | 723 | # Cache the execution payload header and proposer |
668 | 724 | state.latest_block_hash = payload.block_hash |
669 | 725 | 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) |
716 | 726 | ``` |
0 commit comments