set fee recipient in empty payload fallback (#4291)

When the EL/Builder fails to produce an execution payload, we fall back
to an empty `ExecutionPayload`. Even though it contains no transactions
it should refer to the configured fee recipient. This is useful for
privacy reasons (do not reveal the reason for the empty payload) and for
compliance with additional fee recipient rules by staking pools.
This commit is contained in:
Etan Kissling 2022-11-08 15:19:56 +01:00 committed by GitHub
parent 02b48fafad
commit 7ad610f6d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 12 deletions

View File

@ -440,10 +440,11 @@ OK: 12/12 Fail: 0/12 Skip: 0/12
OK: 1/1 Fail: 0/1 Skip: 0/1
## Spec helpers
```diff
+ build_empty_execution_payload OK
+ build_proof - BeaconState OK
+ integer_squareroot OK
```
OK: 2/2 Fail: 0/2 Skip: 0/2
OK: 3/3 Fail: 0/3 Skip: 0/3
## Specific field types
```diff
+ root update OK
@ -604,4 +605,4 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
OK: 9/9 Fail: 0/9 Skip: 0/9
---TOTAL---
OK: 333/338 Fail: 0/338 Skip: 5/338
OK: 334/339 Fail: 0/339 Skip: 5/339

View File

@ -385,7 +385,8 @@ proc emptyPayloadToBlockHeader*(
)
func build_empty_execution_payload*(
state: bellatrix.BeaconState): bellatrix.ExecutionPayload =
state: bellatrix.BeaconState,
feeRecipient: Eth1Address): bellatrix.ExecutionPayload =
## Assuming a pre-state of the same slot, build a valid ExecutionPayload
## without any transactions.
let
@ -398,6 +399,7 @@ func build_empty_execution_payload*(
var payload = bellatrix.ExecutionPayload(
parent_hash: latest.block_hash,
fee_recipient: bellatrix.ExecutionAddress(data: distinctBase(feeRecipient)),
state_root: latest.state_root, # no changes to the state
receipts_root: EMPTY_ROOT_HASH,
block_number: latest.block_number + 1,

View File

@ -348,12 +348,20 @@ proc getExecutionPayload[T](
epoch: Epoch, validator_index: ValidatorIndex): Future[Opt[T]] {.async.} =
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/validator.md#executionpayload
let feeRecipient = block:
let pubkey = node.dag.validatorKey(validator_index)
if pubkey.isNone():
error "Cannot get proposer pubkey, bug?", validator_index
default(Eth1Address)
else:
node.getFeeRecipient(pubkey.get().toPubKey(), validator_index, epoch)
template empty_execution_payload(): auto =
withState(proposalState[]):
when stateFork >= BeaconStateFork.Capella:
raiseAssert $capellaImplementationMissing
elif stateFork >= BeaconStateFork.Bellatrix:
build_empty_execution_payload(forkyState.data)
build_empty_execution_payload(forkyState.data, feeRecipient)
else:
default(T)
@ -381,13 +389,6 @@ proc getExecutionPayload[T](
default(Eth2Digest)
latestSafe = beaconHead.safeExecutionPayloadHash
latestFinalized = beaconHead.finalizedExecutionPayloadHash
feeRecipient = block:
let pubkey = node.dag.validatorKey(validator_index)
if pubkey.isNone():
error "Cannot get proposer pubkey, bug?", validator_index
default(Eth1Address)
else:
node.getFeeRecipient(pubkey.get().toPubKey(), validator_index, epoch)
lastFcU = node.consensusManager.forkchoiceUpdatedInfo
timestamp = withState(proposalState[]):
compute_timestamp_at_slot(forkyState.data, forkyState.data.slot)

View File

@ -10,8 +10,10 @@
import
# Status libraries
stew/bitops2,
web3/ethtypes,
# Beacon chain internals
../beacon_chain/spec/[forks, helpers, state_transition],
../beacon_chain/spec/datatypes/bellatrix,
# Test utilities
./unittest2, mocking/mock_genesis
@ -58,3 +60,19 @@ suite "Spec helpers":
process(fieldVar, i shl childDepth)
i += 1
process(state, state.numLeaves)
test "build_empty_execution_payload":
var cfg = defaultRuntimeConfig
cfg.ALTAIR_FORK_EPOCH = GENESIS_EPOCH
cfg.BELLATRIX_FORK_EPOCH = GENESIS_EPOCH
let state = newClone(initGenesisState(cfg = cfg).bellatrixData)
template testCase(recipient: Eth1Address): untyped =
block:
let payload = build_empty_execution_payload(state[].data, recipient)
check payload.fee_recipient ==
bellatrix.ExecutionAddress(data: distinctBase(recipient))
testCase default(Eth1Address)
testCase Eth1Address.fromHex("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")

View File

@ -145,7 +145,8 @@ proc addTestBlock*(
if forkyState.data.slot >
cfg.BELLATRIX_FORK_EPOCH * SLOTS_PER_EPOCH + 10:
if is_merge_transition_complete(forkyState.data):
build_empty_execution_payload(forkyState.data)
const feeRecipient = default(Eth1Address)
build_empty_execution_payload(forkyState.data, feeRecipient)
else:
build_empty_merge_execution_payload(forkyState.data)
else: