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:
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")

View File

@ -92,8 +92,9 @@ class ExecutionPayload(Container):
parent_hash: Hash32
coinbase: Bytes20 # 'beneficiary' in the yellow paper
state_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
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
gas_limit: uint64
gas_used: uint64
@ -111,8 +112,9 @@ class ExecutionPayloadHeader(Container):
parent_hash: Hash32
coinbase: Bytes20
state_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
receipt_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
random: Bytes32
block_number: uint64
gas_limit: uint64
gas_used: uint64
@ -196,12 +198,15 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
#### `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
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):
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.random == get_randao_mix(state, get_current_epoch(state))
# Verify timestamp
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
# Verify the execution payload is valid
@ -211,8 +216,9 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
parent_hash=payload.parent_hash,
coinbase=payload.coinbase,
state_root=payload.state_root,
logs_bloom=payload.logs_bloom,
receipt_root=payload.receipt_root,
logs_bloom=payload.logs_bloom,
random=payload.random,
block_number=payload.block_number,
gas_limit=payload.gas_limit,
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)
state.latest_execution_payload_header.block_hash = eth1_block_hash
state.latest_execution_payload_header.timestamp = eth1_timestamp
state.latest_execution_payload_header.random = eth1_block_hash
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.
```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:
```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,
transition_store: TransitionStore,
randao_reveal: BLSSignature,
execution_engine: ExecutionEngine) -> ExecutionPayload:
if not is_merge_complete(state):
pow_block = get_pow_chain_head()
@ -80,11 +95,9 @@ def get_execution_payload(state: BeaconState,
return ExecutionPayload()
else:
# Signify merge via producing on top of the last PoW block
timestamp = compute_time_at_slot(state, state.slot)
return execution_engine.assemble_block(pow_block.block_hash, timestamp)
return produce_execution_payload(state, pow_block.block_hash, randao_reveal, execution_engine)
# Post-merge, normal payload
execution_parent_hash = state.latest_execution_payload_header.block_hash
timestamp = compute_time_at_slot(state, state.slot)
return execution_engine.assemble_block(execution_parent_hash, timestamp)
parent_hash = state.latest_execution_payload_header.block_hash
return produce_execution_payload(state, parent_hash, randao_reveal, execution_engine)
```

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.parent_root = parent_block_root
apply_randao_reveal(spec, state, empty_block)
if is_post_altair(spec):
empty_block.body.sync_aggregate.sync_committee_signature = spec.G2_POINT_AT_INFINITY
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

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.
"""
@ -6,13 +6,17 @@ def build_empty_execution_payload(spec, state):
timestamp = spec.compute_time_at_slot(state, state.slot)
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(
parent_hash=latest.block_hash,
coinbase=spec.Bytes20(),
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.
logs_bloom=spec.ByteVector[spec.BYTES_PER_LOGS_BLOOM](), # TODO: zeroed logs bloom for empty logs ok?
block_number=latest.block_number + 1,
random=randao_mix,
gas_limit=latest.gas_limit, # retain same limit
gas_used=0, # empty block, 0 gas
timestamp=timestamp,
@ -30,8 +34,9 @@ def get_execution_payload_header(spec, execution_payload):
parent_hash=execution_payload.parent_hash,
coinbase=execution_payload.coinbase,
state_root=execution_payload.state_root,
logs_bloom=execution_payload.logs_bloom,
receipt_root=execution_payload.receipt_root,
logs_bloom=execution_payload.logs_bloom,
random=execution_payload.random,
block_number=execution_payload.block_number,
gas_limit=execution_payload.gas_limit,
gas_used=execution_payload.gas_used,