Merge pull request #2479 from mkalinin/randao_in_execution_payload

Add randao to execution payload
This commit is contained in:
Danny Ryan 2021-06-23 08:30:21 -06:00 committed by GitHub
commit 00afb341de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 16 deletions

View File

@ -532,7 +532,7 @@ class NoopExecutionEngine(ExecutionEngine):
def finalize_block(self, block_hash: Hash32) -> bool: def finalize_block(self, block_hash: Hash32) -> bool:
return True return True
def assemble_block(self, block_hash: Hash32, timestamp: uint64) -> ExecutionPayload: def assemble_block(self, block_hash: Hash32, timestamp: uint64, random: Bytes32) -> ExecutionPayload:
raise NotImplementedError("no default block production") raise NotImplementedError("no default block production")

View File

@ -92,8 +92,9 @@ class ExecutionPayload(Container):
parent_hash: Hash32 parent_hash: Hash32
coinbase: Bytes20 # 'beneficiary' in the yellow paper coinbase: Bytes20 # 'beneficiary' in the yellow paper
state_root: Bytes32 state_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
receipt_root: Bytes32 # 'receipts root' in the yellow paper receipt_root: Bytes32 # 'receipts root' in the yellow paper
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
random: Bytes32 # 'difficulty' in the yellow paper
block_number: uint64 # 'number' in the yellow paper block_number: uint64 # 'number' in the yellow paper
gas_limit: uint64 gas_limit: uint64
gas_used: uint64 gas_used: uint64
@ -111,8 +112,9 @@ class ExecutionPayloadHeader(Container):
parent_hash: Hash32 parent_hash: Hash32
coinbase: Bytes20 coinbase: Bytes20
state_root: Bytes32 state_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
receipt_root: Bytes32 receipt_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
random: Bytes32
block_number: uint64 block_number: uint64
gas_limit: uint64 gas_limit: uint64
gas_used: uint64 gas_used: uint64
@ -196,12 +198,15 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
#### `process_execution_payload` #### `process_execution_payload`
*Note:* This function depends on `process_randao` function call as it retrieves the most recent randao mix from the `state`. Implementations that are considering parallel processing of execution payload with respect to beacon chain state transition function should work around this dependency.
```python ```python
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None: def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
# Verify consistency of the parent hash and block number # Verify consistency of the parent hash, block number and random
if is_merge_complete(state): if is_merge_complete(state):
assert payload.parent_hash == state.latest_execution_payload_header.block_hash assert payload.parent_hash == state.latest_execution_payload_header.block_hash
assert payload.block_number == state.latest_execution_payload_header.block_number + uint64(1) assert payload.block_number == state.latest_execution_payload_header.block_number + uint64(1)
assert payload.random == 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 the execution payload is valid # Verify the execution payload is valid
@ -211,8 +216,9 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
parent_hash=payload.parent_hash, parent_hash=payload.parent_hash,
coinbase=payload.coinbase, coinbase=payload.coinbase,
state_root=payload.state_root, state_root=payload.state_root,
logs_bloom=payload.logs_bloom,
receipt_root=payload.receipt_root, receipt_root=payload.receipt_root,
logs_bloom=payload.logs_bloom,
random=payload.random,
block_number=payload.block_number, block_number=payload.block_number,
gas_limit=payload.gas_limit, gas_limit=payload.gas_limit,
gas_used=payload.gas_used, gas_used=payload.gas_used,
@ -266,6 +272,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
# [New in Merge] Initialize the execution payload header (with block number set to 0) # [New in Merge] Initialize the execution payload header (with block number set to 0)
state.latest_execution_payload_header.block_hash = eth1_block_hash state.latest_execution_payload_header.block_hash = eth1_block_hash
state.latest_execution_payload_header.timestamp = eth1_timestamp state.latest_execution_payload_header.timestamp = eth1_timestamp
state.latest_execution_payload_header.random = eth1_block_hash
return state return state
``` ```

View File

@ -49,7 +49,7 @@ The body of this function is implementation dependent.
The Consensus API may be used to implement this with an external execution engine. The Consensus API may be used to implement this with an external execution engine.
```python ```python
def assemble_block(self: ExecutionEngine, block_hash: Hash32, timestamp: uint64) -> ExecutionPayload: def assemble_block(self: ExecutionEngine, block_hash: Hash32, timestamp: uint64, random: Bytes32) -> ExecutionPayload:
... ...
``` ```
@ -70,8 +70,23 @@ Let `get_pow_chain_head() -> PowBlock` be the function that returns the head of
* Set `block.body.execution_payload = get_execution_payload(state, transition_store, execution_engine)` where: * Set `block.body.execution_payload = get_execution_payload(state, transition_store, execution_engine)` where:
```python ```python
def compute_randao_mix(state: BeaconState, randao_reveal: BLSSignature) -> Bytes32:
epoch = get_current_epoch(state)
return xor(get_randao_mix(state, epoch), hash(randao_reveal))
def produce_execution_payload(state: BeaconState,
parent_hash: Hash32,
randao_reveal: BLSSignature,
execution_engine: ExecutionEngine) -> ExecutionPayload:
timestamp = compute_timestamp_at_slot(state, state.slot)
randao_mix = compute_randao_mix(state, randao_reveal)
return execution_engine.assemble_block(parent_hash, timestamp, randao_mix)
def get_execution_payload(state: BeaconState, def get_execution_payload(state: BeaconState,
transition_store: TransitionStore, transition_store: TransitionStore,
randao_reveal: BLSSignature,
execution_engine: ExecutionEngine) -> ExecutionPayload: execution_engine: ExecutionEngine) -> ExecutionPayload:
if not is_merge_complete(state): if not is_merge_complete(state):
pow_block = get_pow_chain_head() pow_block = get_pow_chain_head()
@ -80,11 +95,9 @@ def get_execution_payload(state: BeaconState,
return ExecutionPayload() return ExecutionPayload()
else: else:
# Signify merge via producing on top of the last PoW block # Signify merge via producing on top of the last PoW block
timestamp = compute_time_at_slot(state, state.slot) return produce_execution_payload(state, pow_block.block_hash, randao_reveal, execution_engine)
return execution_engine.assemble_block(pow_block.block_hash, timestamp)
# Post-merge, normal payload # Post-merge, normal payload
execution_parent_hash = state.latest_execution_payload_header.block_hash parent_hash = state.latest_execution_payload_header.block_hash
timestamp = compute_time_at_slot(state, state.slot) return produce_execution_payload(state, parent_hash, randao_reveal, execution_engine)
return execution_engine.assemble_block(execution_parent_hash, timestamp)
``` ```

View File

@ -93,13 +93,15 @@ def build_empty_block(spec, state, slot=None):
empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index
empty_block.parent_root = parent_block_root empty_block.parent_root = parent_block_root
apply_randao_reveal(spec, state, empty_block)
if is_post_altair(spec): if is_post_altair(spec):
empty_block.body.sync_aggregate.sync_committee_signature = spec.G2_POINT_AT_INFINITY empty_block.body.sync_aggregate.sync_committee_signature = spec.G2_POINT_AT_INFINITY
if is_post_merge(spec): if is_post_merge(spec):
empty_block.body.execution_payload = build_empty_execution_payload(spec, state) randao_mix = spec.compute_randao_mix(state, empty_block.body.randao_reveal)
empty_block.body.execution_payload = build_empty_execution_payload(spec, state, randao_mix)
apply_randao_reveal(spec, state, empty_block)
return empty_block return empty_block

View File

@ -1,4 +1,4 @@
def build_empty_execution_payload(spec, state): def build_empty_execution_payload(spec, state, randao_mix=None):
""" """
Assuming a pre-state of the same slot, build a valid ExecutionPayload without any transactions. Assuming a pre-state of the same slot, build a valid ExecutionPayload without any transactions.
""" """
@ -6,13 +6,17 @@ def build_empty_execution_payload(spec, state):
timestamp = spec.compute_time_at_slot(state, state.slot) timestamp = spec.compute_time_at_slot(state, state.slot)
empty_txs = spec.List[spec.Transaction, spec.MAX_TRANSACTIONS_PER_PAYLOAD]() empty_txs = spec.List[spec.Transaction, spec.MAX_TRANSACTIONS_PER_PAYLOAD]()
if randao_mix is None:
randao_mix = spec.get_randao_mix(state, spec.get_current_epoch(state))
payload = spec.ExecutionPayload( payload = spec.ExecutionPayload(
parent_hash=latest.block_hash, parent_hash=latest.block_hash,
coinbase=spec.Bytes20(), coinbase=spec.Bytes20(),
state_root=latest.state_root, # no changes to the state state_root=latest.state_root, # no changes to the state
logs_bloom=spec.ByteVector[spec.BYTES_PER_LOGS_BLOOM](), # TODO: zeroed logs bloom for empty logs ok?
receipt_root=b"no receipts here" + b"\x00" * 16, # TODO: root of empty MPT may be better. receipt_root=b"no receipts here" + b"\x00" * 16, # TODO: root of empty MPT may be better.
logs_bloom=spec.ByteVector[spec.BYTES_PER_LOGS_BLOOM](), # TODO: zeroed logs bloom for empty logs ok?
block_number=latest.block_number + 1, block_number=latest.block_number + 1,
random=randao_mix,
gas_limit=latest.gas_limit, # retain same limit gas_limit=latest.gas_limit, # retain same limit
gas_used=0, # empty block, 0 gas gas_used=0, # empty block, 0 gas
timestamp=timestamp, timestamp=timestamp,
@ -30,8 +34,9 @@ def get_execution_payload_header(spec, execution_payload):
parent_hash=execution_payload.parent_hash, parent_hash=execution_payload.parent_hash,
coinbase=execution_payload.coinbase, coinbase=execution_payload.coinbase,
state_root=execution_payload.state_root, state_root=execution_payload.state_root,
logs_bloom=execution_payload.logs_bloom,
receipt_root=execution_payload.receipt_root, receipt_root=execution_payload.receipt_root,
logs_bloom=execution_payload.logs_bloom,
random=execution_payload.random,
block_number=execution_payload.block_number, block_number=execution_payload.block_number,
gas_limit=execution_payload.gas_limit, gas_limit=execution_payload.gas_limit,
gas_used=execution_payload.gas_used, gas_used=execution_payload.gas_used,