update to devnet-4-compatible engine API (#6657)

This commit is contained in:
tersec 2024-10-17 14:53:37 +00:00 committed by GitHub
parent 6df8f92092
commit 2d3614ff69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 124 additions and 267 deletions

View File

@ -235,7 +235,7 @@ local-testnet-minimal:
--remote-validators-count 512 \ --remote-validators-count 512 \
--signer-type $(SIGNER_TYPE) \ --signer-type $(SIGNER_TYPE) \
--deneb-fork-epoch 0 \ --deneb-fork-epoch 0 \
--electra-fork-epoch 5 \ --electra-fork-epoch 50 \
--stop-at-epoch 6 \ --stop-at-epoch 6 \
--disable-htop \ --disable-htop \
--enable-payload-builder \ --enable-payload-builder \
@ -264,7 +264,7 @@ local-testnet-mainnet:
--data-dir $@ \ --data-dir $@ \
--nodes 2 \ --nodes 2 \
--deneb-fork-epoch 0 \ --deneb-fork-epoch 0 \
--electra-fork-epoch 5 \ --electra-fork-epoch 50 \
--stop-at-epoch 6 \ --stop-at-epoch 6 \
--disable-htop \ --disable-htop \
--base-port $$(( $(MAINNET_TESTNET_BASE_PORT) + EXECUTOR_NUMBER * 400 + 0 )) \ --base-port $$(( $(MAINNET_TESTNET_BASE_PORT) + EXECUTOR_NUMBER * 400 + 0 )) \

View File

@ -821,13 +821,15 @@ proc sendNewPayloadToSingleEL(
proc sendNewPayloadToSingleEL( proc sendNewPayloadToSingleEL(
connection: ELConnection, connection: ELConnection,
payload: engine_api.ExecutionPayloadV4, payload: engine_api.ExecutionPayloadV3,
versioned_hashes: seq[engine_api.VersionedHash], versioned_hashes: seq[engine_api.VersionedHash],
parent_beacon_block_root: FixedBytes[32] parent_beacon_block_root: FixedBytes[32],
executionRequests: array[3, seq[byte]]
): Future[PayloadStatusV1] {.async: (raises: [CatchableError]).} = ): Future[PayloadStatusV1] {.async: (raises: [CatchableError]).} =
let rpcClient = await connection.connectedRpcClient() let rpcClient = await connection.connectedRpcClient()
await rpcClient.engine_newPayloadV4( await rpcClient.engine_newPayloadV4(
payload, versioned_hashes, Hash32 parent_beacon_block_root) payload, versioned_hashes, Hash32 parent_beacon_block_root,
executionRequests)
type type
StatusRelation = enum StatusRelation = enum
@ -954,8 +956,18 @@ proc sendNewPayload*(
let let
requests = m.elConnections.mapIt: requests = m.elConnections.mapIt:
let req = let req =
when payload is engine_api.ExecutionPayloadV3 or when typeof(blck).kind == ConsensusFork.Electra:
payload is engine_api.ExecutionPayloadV4: # https://github.com/ethereum/execution-apis/blob/4140e528360fea53c34a766d86a000c6c039100e/src/engine/prague.md#engine_newpayloadv4
let versioned_hashes = mapIt(
blck.body.blob_kzg_commitments,
engine_api.VersionedHash(kzg_commitment_to_versioned_hash(it)))
sendNewPayloadToSingleEL(
it, payload, versioned_hashes,
FixedBytes[32] blck.parent_root.data,
[SSZ.encode(blck.body.execution_requests.deposits),
SSZ.encode(blck.body.execution_requests.withdrawals),
SSZ.encode(blck.body.execution_requests.consolidations)])
elif typeof(blck).kind == ConsensusFork.Deneb:
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.1/specs/deneb/beacon-chain.md#process_execution_payload # https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.1/specs/deneb/beacon-chain.md#process_execution_payload
# Verify the execution payload is valid # Verify the execution payload is valid
# [Modified in Deneb] Pass `versioned_hashes` to Execution Engine # [Modified in Deneb] Pass `versioned_hashes` to Execution Engine
@ -965,8 +977,7 @@ proc sendNewPayload*(
sendNewPayloadToSingleEL( sendNewPayloadToSingleEL(
it, payload, versioned_hashes, it, payload, versioned_hashes,
FixedBytes[32] blck.parent_root.data) FixedBytes[32] blck.parent_root.data)
elif payload is engine_api.ExecutionPayloadV1 or elif typeof(blck).kind in [ConsensusFork.Bellatrix, ConsensusFork.Capella]:
payload is engine_api.ExecutionPayloadV2:
sendNewPayloadToSingleEL(it, payload) sendNewPayloadToSingleEL(it, payload)
else: else:
static: doAssert false static: doAssert false

View File

@ -129,6 +129,33 @@ func asConsensusType*(rpcExecutionPayload: ExecutionPayloadV3):
blob_gas_used: rpcExecutionPayload.blobGasUsed.uint64, blob_gas_used: rpcExecutionPayload.blobGasUsed.uint64,
excess_blob_gas: rpcExecutionPayload.excessBlobGas.uint64) excess_blob_gas: rpcExecutionPayload.excessBlobGas.uint64)
func asElectraConsensusPayload(rpcExecutionPayload: ExecutionPayloadV3):
electra.ExecutionPayload =
template getTransaction(tt: TypedTransaction): bellatrix.Transaction =
bellatrix.Transaction.init(tt.distinctBase)
electra.ExecutionPayload(
parent_hash: rpcExecutionPayload.parentHash.asEth2Digest,
feeRecipient:
ExecutionAddress(data: rpcExecutionPayload.feeRecipient.distinctBase),
state_root: rpcExecutionPayload.stateRoot.asEth2Digest,
receipts_root: rpcExecutionPayload.receiptsRoot.asEth2Digest,
logs_bloom: BloomLogs(data: rpcExecutionPayload.logsBloom.distinctBase),
prev_randao: rpcExecutionPayload.prevRandao.asEth2Digest,
block_number: rpcExecutionPayload.blockNumber.uint64,
gas_limit: rpcExecutionPayload.gasLimit.uint64,
gas_used: rpcExecutionPayload.gasUsed.uint64,
timestamp: rpcExecutionPayload.timestamp.uint64,
extra_data: List[byte, MAX_EXTRA_DATA_BYTES].init(rpcExecutionPayload.extraData.data),
base_fee_per_gas: rpcExecutionPayload.baseFeePerGas,
block_hash: rpcExecutionPayload.blockHash.asEth2Digest,
transactions: List[bellatrix.Transaction, MAX_TRANSACTIONS_PER_PAYLOAD].init(
mapIt(rpcExecutionPayload.transactions, it.getTransaction)),
withdrawals: List[capella.Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD].init(
mapIt(rpcExecutionPayload.withdrawals, it.asConsensusWithdrawal)),
blob_gas_used: rpcExecutionPayload.blobGasUsed.uint64,
excess_blob_gas: rpcExecutionPayload.excessBlobGas.uint64)
func asConsensusType*(payload: engine_api.GetPayloadV3Response): func asConsensusType*(payload: engine_api.GetPayloadV3Response):
deneb.ExecutionPayloadForSigning = deneb.ExecutionPayloadForSigning =
deneb.ExecutionPayloadForSigning( deneb.ExecutionPayloadForSigning(
@ -148,61 +175,11 @@ func asConsensusType*(payload: engine_api.GetPayloadV3Response):
blobs: Blobs.init( blobs: Blobs.init(
payload.blobsBundle.blobs.mapIt(it.data)))) payload.blobsBundle.blobs.mapIt(it.data))))
func asConsensusType*(rpcExecutionPayload: ExecutionPayloadV4): func asConsensusType*(
electra.ExecutionPayload = payload: engine_api.GetPayloadV4Response):
template getTransaction(tt: TypedTransaction): bellatrix.Transaction =
bellatrix.Transaction.init(tt.distinctBase)
template getDepositRequest(
dr: DepositRequestV1): electra.DepositRequest =
electra.DepositRequest(
pubkey: ValidatorPubKey(blob: dr.pubkey.distinctBase),
withdrawal_credentials: dr.withdrawalCredentials.asEth2Digest,
amount: dr.amount.Gwei,
signature: ValidatorSig(blob: dr.signature.distinctBase),
index: dr.index.uint64)
template getWithdrawalRequest(
wr: WithdrawalRequestV1): electra.WithdrawalRequest =
electra.WithdrawalRequest(
source_address: ExecutionAddress(data: wr.sourceAddress.distinctBase),
validator_pubkey: ValidatorPubKey(blob: wr.validatorPubkey.distinctBase),
amount: wr.amount.Gwei)
template getConsolidationRequest(
cr: ConsolidationRequestV1): electra.ConsolidationRequest =
electra.ConsolidationRequest(
source_address: ExecutionAddress(data: cr.sourceAddress.distinctBase),
source_pubkey: ValidatorPubKey(blob: cr.sourcePubkey.distinctBase),
target_pubkey: ValidatorPubKey(blob: cr.targetPubkey.distinctBase))
electra.ExecutionPayload(
parent_hash: rpcExecutionPayload.parentHash.asEth2Digest,
feeRecipient:
ExecutionAddress(data: rpcExecutionPayload.feeRecipient.distinctBase),
state_root: rpcExecutionPayload.stateRoot.asEth2Digest,
receipts_root: rpcExecutionPayload.receiptsRoot.asEth2Digest,
logs_bloom: BloomLogs(data: rpcExecutionPayload.logsBloom.distinctBase),
prev_randao: rpcExecutionPayload.prevRandao.asEth2Digest,
block_number: rpcExecutionPayload.blockNumber.uint64,
gas_limit: rpcExecutionPayload.gasLimit.uint64,
gas_used: rpcExecutionPayload.gasUsed.uint64,
timestamp: rpcExecutionPayload.timestamp.uint64,
extra_data: List[byte, MAX_EXTRA_DATA_BYTES].init(
rpcExecutionPayload.extraData.data),
base_fee_per_gas: rpcExecutionPayload.baseFeePerGas,
block_hash: rpcExecutionPayload.blockHash.asEth2Digest,
transactions: List[bellatrix.Transaction, MAX_TRANSACTIONS_PER_PAYLOAD].init(
mapIt(rpcExecutionPayload.transactions, it.getTransaction)),
withdrawals: List[capella.Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD].init(
mapIt(rpcExecutionPayload.withdrawals, it.asConsensusWithdrawal)),
blob_gas_used: rpcExecutionPayload.blobGasUsed.uint64,
excess_blob_gas: rpcExecutionPayload.excessBlobGas.uint64)
func asConsensusType*(payload: engine_api.GetPayloadV4Response):
electra.ExecutionPayloadForSigning = electra.ExecutionPayloadForSigning =
electra.ExecutionPayloadForSigning( electra.ExecutionPayloadForSigning(
executionPayload: payload.executionPayload.asConsensusType, executionPayload: payload.executionPayload.asElectraConsensusPayload,
blockValue: payload.blockValue, blockValue: payload.blockValue,
# TODO # TODO
# The `mapIt` calls below are necessary only because we use different distinct # The `mapIt` calls below are necessary only because we use different distinct
@ -216,7 +193,8 @@ func asConsensusType*(payload: engine_api.GetPayloadV4Response):
payload.blobsBundle.proofs.mapIt( payload.blobsBundle.proofs.mapIt(
kzg_abi.KzgProof(bytes: it.data))), kzg_abi.KzgProof(bytes: it.data))),
blobs: Blobs.init( blobs: Blobs.init(
payload.blobsBundle.blobs.mapIt(it.data)))) payload.blobsBundle.blobs.mapIt(it.data))),
executionRequests: payload.executionRequests)
func asEngineExecutionPayload*(blockBody: bellatrix.BeaconBlockBody): func asEngineExecutionPayload*(blockBody: bellatrix.BeaconBlockBody):
ExecutionPayloadV1 = ExecutionPayloadV1 =
@ -273,7 +251,8 @@ func asEngineExecutionPayload*(blockBody: capella.BeaconBlockBody):
transactions: mapIt(executionPayload.transactions, it.getTypedTransaction), transactions: mapIt(executionPayload.transactions, it.getTypedTransaction),
withdrawals: mapIt(executionPayload.withdrawals, it.toEngineWithdrawal)) withdrawals: mapIt(executionPayload.withdrawals, it.toEngineWithdrawal))
func asEngineExecutionPayload*(blockBody: deneb.BeaconBlockBody): func asEngineExecutionPayload*(
blockBody: deneb.BeaconBlockBody | electra.BeaconBlockBody):
ExecutionPayloadV3 = ExecutionPayloadV3 =
template executionPayload(): untyped = blockBody.execution_payload template executionPayload(): untyped = blockBody.execution_payload
@ -299,59 +278,3 @@ func asEngineExecutionPayload*(blockBody: deneb.BeaconBlockBody):
withdrawals: mapIt(executionPayload.withdrawals, it.asEngineWithdrawal), withdrawals: mapIt(executionPayload.withdrawals, it.asEngineWithdrawal),
blobGasUsed: Quantity(executionPayload.blob_gas_used), blobGasUsed: Quantity(executionPayload.blob_gas_used),
excessBlobGas: Quantity(executionPayload.excess_blob_gas)) excessBlobGas: Quantity(executionPayload.excess_blob_gas))
func asEngineExecutionPayload*(blockBody: electra.BeaconBlockBody):
ExecutionPayloadV4 =
template executionPayload(): untyped = blockBody.execution_payload
template getTypedTransaction(tt: bellatrix.Transaction): TypedTransaction =
TypedTransaction(tt.distinctBase)
template getDepositRequest(
dr: electra.DepositRequest): DepositRequestV1 =
DepositRequestV1(
pubkey: FixedBytes[RawPubKeySize](dr.pubkey.blob),
withdrawalCredentials: FixedBytes[32](dr.withdrawal_credentials.data),
amount: dr.amount.Quantity,
signature: FixedBytes[RawSigSize](dr.signature.blob),
index: dr.index.Quantity)
template getWithdrawalRequest(
wr: electra.WithdrawalRequest): WithdrawalRequestV1 =
WithdrawalRequestV1(
sourceAddress: Address(wr.source_address.data),
validatorPubkey: FixedBytes[RawPubKeySize](wr.validator_pubkey.blob),
amount: wr.amount.Quantity)
template getConsolidationRequest(
cr: electra.ConsolidationRequest): ConsolidationRequestV1 =
ConsolidationRequestV1(
sourceAddress: Address(cr.source_address.data),
sourcePubkey: FixedBytes[RawPubKeySize](cr.source_pubkey.blob),
targetPubkey: FixedBytes[RawPubKeySize](cr.target_pubkey.blob))
engine_api.ExecutionPayloadV4(
parentHash: executionPayload.parent_hash.asBlockHash,
feeRecipient: Address(executionPayload.fee_recipient.data),
stateRoot: executionPayload.state_root.asBlockHash,
receiptsRoot: executionPayload.receipts_root.asBlockHash,
logsBloom:
FixedBytes[BYTES_PER_LOGS_BLOOM](executionPayload.logs_bloom.data),
prevRandao: executionPayload.prev_randao.data.to(Bytes32),
blockNumber: Quantity(executionPayload.block_number),
gasLimit: Quantity(executionPayload.gas_limit),
gasUsed: Quantity(executionPayload.gas_used),
timestamp: Quantity(executionPayload.timestamp),
extraData: DynamicBytes[0, MAX_EXTRA_DATA_BYTES](executionPayload.extra_data),
baseFeePerGas: executionPayload.base_fee_per_gas,
blockHash: executionPayload.block_hash.asBlockHash,
transactions: mapIt(executionPayload.transactions, it.getTypedTransaction),
withdrawals: mapIt(executionPayload.withdrawals, it.asEngineWithdrawal),
blobGasUsed: Quantity(executionPayload.blob_gas_used),
excessBlobGas: Quantity(executionPayload.excess_blob_gas),
depositRequests:
mapIt(blockBody.execution_requests.deposits, it.getDepositRequest),
withdrawalRequests: mapIt(
blockBody.execution_requests.withdrawals, it.getWithdrawalRequest),
consolidationRequests: mapIt(
blockBody.execution_requests.consolidations, it.getConsolidationRequest))

View File

@ -1255,31 +1255,23 @@ proc ETHExecutionBlockHeaderCreateFromJson(
return nil return nil
# Check fork consistency # Check fork consistency
static: doAssert totalSerializedFields(BlockObject) == 30, static: doAssert totalSerializedFields(BlockObject) == 27,
"Only update this number once code is adjusted to check new fields!" "Only update this number once code is adjusted to check new fields!"
if data.baseFeePerGas.isNone and ( if data.baseFeePerGas.isNone and (
data.withdrawals.isSome or data.withdrawalsRoot.isSome or data.withdrawals.isSome or data.withdrawalsRoot.isSome or
data.blobGasUsed.isSome or data.excessBlobGas.isSome or data.blobGasUsed.isSome or data.excessBlobGas.isSome or
data.depositRequests.isSome or data.withdrawalRequests.isSome or data.requestsHash.isSome):
data.consolidationRequests.isSome or data.requestsRoot.isSome):
return nil return nil
if data.withdrawalsRoot.isNone and ( if data.withdrawalsRoot.isNone and (
data.blobGasUsed.isSome or data.excessBlobGas.isSome or data.blobGasUsed.isSome or data.excessBlobGas.isSome or
data.depositRequests.isSome or data.withdrawalRequests.isSome or data.requestsHash.isSome):
data.consolidationRequests.isSome or data.requestsRoot.isSome):
return nil return nil
if data.blobGasUsed.isNone and ( if data.blobGasUsed.isNone and data.requestsHash.isSome:
data.depositRequests.isSome or data.withdrawalRequests.isSome or
data.consolidationRequests.isSome or data.requestsRoot.isSome):
return nil return nil
if data.withdrawals.isSome != data.withdrawalsRoot.isSome: if data.withdrawals.isSome != data.withdrawalsRoot.isSome:
return nil return nil
if data.blobGasUsed.isSome != data.excessBlobGas.isSome: if data.blobGasUsed.isSome != data.excessBlobGas.isSome:
return nil return nil
if data.depositRequests.isSome != data.requestsRoot.isSome or
data.withdrawalRequests.isSome != data.requestsRoot.isSome or
data.consolidationRequests.isSome != data.requestsRoot.isSome:
return nil
# Construct block header # Construct block header
static: # `GasInt` is signed. We only use it for hashing. static: # `GasInt` is signed. We only use it for hashing.
@ -1325,8 +1317,8 @@ proc ETHExecutionBlockHeaderCreateFromJson(
else: else:
Opt.none(Hash32), Opt.none(Hash32),
requestsHash: requestsHash:
if data.requestsRoot.isSome: if data.requestsHash.isSome:
Opt.some(data.requestsRoot.get.asEth2Digest.to(Hash32)) Opt.some data.requestsHash.get.asEth2Digest.to(Hash32)
else: else:
Opt.none(Hash32)) Opt.none(Hash32))
if rlpHash(blockHeader) != executionHash[]: if rlpHash(blockHeader) != executionHash[]:
@ -1367,119 +1359,12 @@ proc ETHExecutionBlockHeaderCreateFromJson(
if tr != data.withdrawalsRoot.get.asEth2Digest: if tr != data.withdrawalsRoot.get.asEth2Digest:
return nil return nil
# Construct deposit requests
var depositRequests: seq[ETHDepositRequest]
if data.depositRequests.isSome:
depositRequests = newSeqOfCap[ETHDepositRequest](
data.depositRequests.get.len)
for data in data.depositRequests.get:
# Check fork consistency
static: doAssert totalSerializedFields(DepositRequestObject) == 5,
"Only update this number once code is adjusted to check new fields!"
# Construct deposit request
let
req = eth_types.EthDepositRequest(
pubkey: distinctBase(data.pubkey).to(Bytes48),
withdrawalCredentials: distinctBase(data.withdrawalCredentials).to(Bytes32),
amount: distinctBase(data.amount),
signature: distinctBase(data.signature).to(Bytes96),
index: distinctBase(data.index))
rlpBytes =
try:
rlp.encode(req)
except RlpError:
raiseAssert "Unreachable"
depositRequests.add ETHDepositRequest(
pubkey: ValidatorPubKey(blob: req.pubkey.data),
withdrawalCredentials: req.withdrawalCredentials.data,
amount: req.amount,
signature: ValidatorSig(blob: req.signature.data),
index: req.index,
bytes: rlpBytes)
# Construct withdrawal requests
var withdrawalRequests: seq[ETHWithdrawalRequest]
if data.withdrawalRequests.isSome:
withdrawalRequests = newSeqOfCap[ETHWithdrawalRequest](
data.withdrawalRequests.get.len)
for data in data.withdrawalRequests.get:
# Check fork consistency
static: doAssert totalSerializedFields(WithdrawalRequestObject) == 3,
"Only update this number once code is adjusted to check new fields!"
# Construct withdrawal request
let
req = eth_types.EthWithdrawalRequest(
sourceAddress: distinctBase(data.sourceAddress).to(EthAddress),
validatorPubkey: distinctBase(data.validatorPubkey).to(Bytes48),
amount: distinctBase(data.amount))
rlpBytes =
try:
rlp.encode(req)
except RlpError:
raiseAssert "Unreachable"
withdrawalRequests.add ETHWithdrawalRequest(
sourceAddress: ExecutionAddress(data: req.sourceAddress.data),
validatorPubkey: ValidatorPubKey(blob: req.validatorPubkey.data),
amount: req.amount,
bytes: rlpBytes)
# Construct consolidation requests
var consolidationRequests: seq[ETHConsolidationRequest]
if data.consolidationRequests.isSome:
consolidationRequests = newSeqOfCap[ETHConsolidationRequest](
data.consolidationRequests.get.len)
for data in data.consolidationRequests.get:
# Check fork consistency
static: doAssert totalSerializedFields(ConsolidationRequestObject) == 3,
"Only update this number once code is adjusted to check new fields!"
# Construct consolidation request
let
req = eth_types.EthConsolidationRequest(
sourceAddress: distinctBase(data.sourceAddress).to(EthAddress),
sourcePubkey: distinctBase(data.sourcePubkey).to(Bytes48),
targetPubkey: distinctBase(data.targetPubkey).to(Bytes48))
rlpBytes =
try:
rlp.encode(req)
except RlpError:
raiseAssert "Unreachable"
consolidationRequests.add ETHConsolidationRequest(
sourceAddress: ExecutionAddress(data: req.sourceAddress.data),
sourcePubkey: ValidatorPubKey(blob: req.sourcePubkey.data),
targetPubkey: ValidatorPubKey(blob: req.targetPubkey.data),
bytes: rlpBytes)
# Verify requests hash
if data.depositRequests.isSome or
data.withdrawalRequests.isSome or
data.consolidationRequests.isSome:
doAssert data.requestsRoot.isSome # Checked above
var b = OrderedTrieRootBuilder.init(
depositRequests.len + withdrawalRequests.len + consolidationRequests.len)
b.add(depositRequests)
b.add(withdrawalRequests)
b.add(consolidationRequests)
if b.rootHash() != data.requestsRoot.get.asEth2Digest:
return nil
let executionBlockHeader = ETHExecutionBlockHeader.new() let executionBlockHeader = ETHExecutionBlockHeader.new()
executionBlockHeader[] = ETHExecutionBlockHeader( executionBlockHeader[] = ETHExecutionBlockHeader(
transactionsRoot: blockHeader.txRoot, transactionsRoot: blockHeader.txRoot,
withdrawalsRoot: blockHeader.withdrawalsRoot.get(zeroHash32), withdrawalsRoot: blockHeader.withdrawalsRoot.get(zeroHash32),
withdrawals: wds, withdrawals: wds,
requestsHash: blockHeader.requestsHash.get(zeroHash32), requestsHash: blockHeader.requestsHash.get(zeroHash32))
depositRequests: depositRequests,
withdrawalRequests: withdrawalRequests,
consolidationRequests: consolidationRequests)
executionBlockHeader.toUnmanagedPtr() executionBlockHeader.toUnmanagedPtr()
proc ETHExecutionBlockHeaderDestroy( proc ETHExecutionBlockHeaderDestroy(

View File

@ -119,6 +119,7 @@ type
executionPayload*: ExecutionPayload executionPayload*: ExecutionPayload
blockValue*: Wei blockValue*: Wei
blobsBundle*: BlobsBundle blobsBundle*: BlobsBundle
executionRequests*: array[3, seq[byte]]
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/deneb/beacon-chain.md#executionpayloadheader # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/deneb/beacon-chain.md#executionpayloadheader
ExecutionPayloadHeader* = object ExecutionPayloadHeader* = object

View File

@ -361,8 +361,8 @@ func partialBeaconBlock*(
deposits: seq[Deposit], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
execution_payload: ForkyExecutionPayloadForSigning execution_payload: ForkyExecutionPayloadForSigning,
): auto = _: ExecutionRequests): auto =
const consensusFork = typeof(state).kind const consensusFork = typeof(state).kind
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/validator.md#preparing-for-a-beaconblock # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/phase0/validator.md#preparing-for-a-beaconblock
@ -411,8 +411,8 @@ func partialBeaconBlock*(
deposits: seq[Deposit], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
execution_payload: ForkyExecutionPayloadForSigning execution_payload: ForkyExecutionPayloadForSigning,
): auto = execution_requests: ExecutionRequests): auto =
const consensusFork = typeof(state).kind const consensusFork = typeof(state).kind
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#preparing-for-a-beaconblock # https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#preparing-for-a-beaconblock
@ -433,7 +433,8 @@ func partialBeaconBlock*(
sync_aggregate: sync_aggregate, sync_aggregate: sync_aggregate,
execution_payload: execution_payload.executionPayload, execution_payload: execution_payload.executionPayload,
bls_to_execution_changes: validator_changes.bls_to_execution_changes, bls_to_execution_changes: validator_changes.bls_to_execution_changes,
blob_kzg_commitments: execution_payload.blobsBundle.commitments)) blob_kzg_commitments: execution_payload.blobsBundle.commitments,
execution_requests: execution_requests))
proc makeBeaconBlockWithRewards*( proc makeBeaconBlockWithRewards*(
cfg: RuntimeConfig, cfg: RuntimeConfig,
@ -455,7 +456,8 @@ proc makeBeaconBlockWithRewards*(
verificationFlags: UpdateFlags, verificationFlags: UpdateFlags,
transactions_root: Opt[Eth2Digest], transactions_root: Opt[Eth2Digest],
execution_payload_root: Opt[Eth2Digest], execution_payload_root: Opt[Eth2Digest],
kzg_commitments: Opt[KzgCommitments]): kzg_commitments: Opt[KzgCommitments],
execution_requests: ExecutionRequests):
Result[tuple[blck: ForkedBeaconBlock, rewards: BlockRewards], cstring] = Result[tuple[blck: ForkedBeaconBlock, rewards: BlockRewards], cstring] =
## Create a block for the given state. The latest block applied to it will ## Create a block for the given state. The latest block applied to it will
## be used for the parent_root value, and the slot will be take from ## be used for the parent_root value, and the slot will be take from
@ -473,7 +475,7 @@ proc makeBeaconBlockWithRewards*(
partialBeaconBlock( partialBeaconBlock(
cfg, state.`kind Data`, proposer_index, randao_reveal, eth1_data, cfg, state.`kind Data`, proposer_index, randao_reveal, eth1_data,
graffiti, attestations, deposits, validator_changes, sync_aggregate, graffiti, attestations, deposits, validator_changes, sync_aggregate,
executionPayload)) executionPayload, execution_requests))
let res = process_block( let res = process_block(
cfg, state.`kind Data`.data, blck.`kind Data`.asSigVerified(), cfg, state.`kind Data`.data, blck.`kind Data`.asSigVerified(),
@ -516,6 +518,7 @@ proc makeBeaconBlockWithRewards*(
forkyState.data.latest_execution_payload_header.transactions_root = forkyState.data.latest_execution_payload_header.transactions_root =
transactions_root.get transactions_root.get
debugComment "verify (again) that this is what builder API needs"
when executionPayload is electra.ExecutionPayloadForSigning: when executionPayload is electra.ExecutionPayloadForSigning:
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/electra/beacon-chain.md#beaconblockbody # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.3/specs/electra/beacon-chain.md#beaconblockbody
forkyState.data.latest_block_header.body_root = hash_tree_root( forkyState.data.latest_block_header.body_root = hash_tree_root(
@ -579,14 +582,16 @@ proc makeBeaconBlock*(
verificationFlags: UpdateFlags, verificationFlags: UpdateFlags,
transactions_root: Opt[Eth2Digest], transactions_root: Opt[Eth2Digest],
execution_payload_root: Opt[Eth2Digest], execution_payload_root: Opt[Eth2Digest],
kzg_commitments: Opt[KzgCommitments]): kzg_commitments: Opt[KzgCommitments],
execution_requests: ExecutionRequests):
Result[ForkedBeaconBlock, cstring] = Result[ForkedBeaconBlock, cstring] =
let blockAndRewards = let blockAndRewards =
? makeBeaconBlockWithRewards( ? makeBeaconBlockWithRewards(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, validator_changes, sync_aggregate, attestations, deposits, validator_changes, sync_aggregate,
executionPayload, rollback, cache, verificationFlags, executionPayload, rollback, cache, verificationFlags,
transactions_root, execution_payload_root, kzg_commitments) transactions_root, execution_payload_root, kzg_commitments,
execution_requests)
ok(blockAndRewards.blck) ok(blockAndRewards.blck)
proc makeBeaconBlock*( proc makeBeaconBlock*(
@ -606,7 +611,8 @@ proc makeBeaconBlock*(
executionPayload, rollback, cache, executionPayload, rollback, cache,
verificationFlags = {}, transactions_root = Opt.none Eth2Digest, verificationFlags = {}, transactions_root = Opt.none Eth2Digest,
execution_payload_root = Opt.none Eth2Digest, execution_payload_root = Opt.none Eth2Digest,
kzg_commitments = Opt.none KzgCommitments) kzg_commitments = Opt.none KzgCommitments,
execution_requests = default(ExecutionRequests))
proc makeBeaconBlock*( proc makeBeaconBlock*(
cfg: RuntimeConfig, state: var ForkedHashedBeaconState, cfg: RuntimeConfig, state: var ForkedHashedBeaconState,
@ -627,4 +633,5 @@ proc makeBeaconBlock*(
verificationFlags = verificationFlags, verificationFlags = verificationFlags,
transactions_root = Opt.none Eth2Digest, transactions_root = Opt.none Eth2Digest,
execution_payload_root = Opt.none Eth2Digest, execution_payload_root = Opt.none Eth2Digest,
kzg_commitments = Opt.none KzgCommitments) kzg_commitments = Opt.none KzgCommitments,
execution_requests = default(ExecutionRequests))

View File

@ -76,7 +76,7 @@ declarePublicGauge(attached_validator_balance_total,
logScope: topics = "beacval" logScope: topics = "beacval"
type type
EngineBid* = object EngineBid = object
blck*: ForkedBeaconBlock blck*: ForkedBeaconBlock
executionPayloadValue*: Wei executionPayloadValue*: Wei
consensusBlockValue*: UInt256 consensusBlockValue*: UInt256
@ -457,7 +457,8 @@ proc makeBeaconBlockForHeadAndSlot*(
transactions_root: Opt[Eth2Digest], transactions_root: Opt[Eth2Digest],
execution_payload_root: Opt[Eth2Digest], execution_payload_root: Opt[Eth2Digest],
withdrawals_root: Opt[Eth2Digest], withdrawals_root: Opt[Eth2Digest],
kzg_commitments: Opt[KzgCommitments]): kzg_commitments: Opt[KzgCommitments],
execution_requests: ExecutionRequests): # TODO probably need this for builder API, otherwise remove, maybe needs to be Opt
Future[ForkedBlockResult] {.async: (raises: [CancelledError]).} = Future[ForkedBlockResult] {.async: (raises: [CancelledError]).} =
# Advance state to the slot that we're proposing for # Advance state to the slot that we're proposing for
var cache = StateCache() var cache = StateCache()
@ -536,6 +537,26 @@ proc makeBeaconBlockForHeadAndSlot*(
slot, validator_index slot, validator_index
return err("Unable to get execution payload") return err("Unable to get execution payload")
# Don't use the requests passed in, TODO remove that
let execution_requests_actual =
when PayloadType.kind >= ConsensusFork.Electra:
# Don't want un-decoded SSZ going any further/deeper
try:
ExecutionRequests(
deposits: SSZ.decode(
payload.executionRequests[0],
List[DepositRequest, Limit MAX_DEPOSIT_REQUESTS_PER_PAYLOAD]),
withdrawals: SSZ.decode(
payload.executionRequests[1],
List[WithdrawalRequest, Limit MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD]),
consolidations: SSZ.decode(
payload.executionRequests[2],
List[ConsolidationRequest, Limit MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD]))
except CatchableError:
return err("Unable to deserialize execution layer requests")
else:
default(ExecutionRequests) # won't be used by block builder
let res = makeBeaconBlockWithRewards( let res = makeBeaconBlockWithRewards(
node.dag.cfg, node.dag.cfg,
state[], state[],
@ -553,7 +574,8 @@ proc makeBeaconBlockForHeadAndSlot*(
verificationFlags = {}, verificationFlags = {},
transactions_root = transactions_root, transactions_root = transactions_root,
execution_payload_root = execution_payload_root, execution_payload_root = execution_payload_root,
kzg_commitments = kzg_commitments).mapErr do (error: cstring) -> string: kzg_commitments = kzg_commitments,
execution_requests = execution_requests_actual).mapErr do (error: cstring) -> string:
# This is almost certainly a bug, but it's complex enough that there's a # This is almost certainly a bug, but it's complex enough that there's a
# small risk it might happen even when most proposals succeed - thus we # small risk it might happen even when most proposals succeed - thus we
# log instead of asserting # log instead of asserting
@ -571,11 +593,12 @@ proc makeBeaconBlockForHeadAndSlot*(
blck: res.get().blck, blck: res.get().blck,
executionPayloadValue: payload.blockValue, executionPayloadValue: payload.blockValue,
consensusBlockValue: res.get().rewards.blockConsensusValue(), consensusBlockValue: res.get().rewards.blockConsensusValue(),
blobsBundleOpt: blobsBundleOpt blobsBundleOpt: blobsBundleOpt,
)) ))
else: else:
err(res.error) err(res.error)
# TODO what is this for
proc makeBeaconBlockForHeadAndSlot*( proc makeBeaconBlockForHeadAndSlot*(
PayloadType: type ForkyExecutionPayloadForSigning, node: BeaconNode, randao_reveal: ValidatorSig, PayloadType: type ForkyExecutionPayloadForSigning, node: BeaconNode, randao_reveal: ValidatorSig,
validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef, validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef,
@ -587,7 +610,8 @@ proc makeBeaconBlockForHeadAndSlot*(
transactions_root = Opt.none(Eth2Digest), transactions_root = Opt.none(Eth2Digest),
execution_payload_root = Opt.none(Eth2Digest), execution_payload_root = Opt.none(Eth2Digest),
withdrawals_root = Opt.none(Eth2Digest), withdrawals_root = Opt.none(Eth2Digest),
kzg_commitments = Opt.none(KzgCommitments)) kzg_commitments = Opt.none(KzgCommitments),
execution_requests = static(default(ExecutionRequests)))
proc getBlindedExecutionPayload[ proc getBlindedExecutionPayload[
EPH: deneb_mev.BlindedExecutionPayloadAndBlobsBundle | EPH: deneb_mev.BlindedExecutionPayloadAndBlobsBundle |
@ -861,6 +885,7 @@ proc getBlindedBlockParts[
copyFields( copyFields(
shimExecutionPayload.executionPayload, actualEPH, getFieldNames(DenebEPH)) shimExecutionPayload.executionPayload, actualEPH, getFieldNames(DenebEPH))
elif EPH is electra_mev.BlindedExecutionPayloadAndBlobsBundle: elif EPH is electra_mev.BlindedExecutionPayloadAndBlobsBundle:
debugComment "verify (again, after change) this is what builder API needs"
type PayloadType = electra.ExecutionPayloadForSigning type PayloadType = electra.ExecutionPayloadForSigning
template actualEPH: untyped = template actualEPH: untyped =
executionPayloadHeader.get.blindedBlckPart.execution_payload_header executionPayloadHeader.get.blindedBlckPart.execution_payload_header
@ -877,13 +902,15 @@ proc getBlindedBlockParts[
else: else:
static: doAssert false static: doAssert false
debugComment "the electra builder API bids have these requests"
let newBlock = await makeBeaconBlockForHeadAndSlot( let newBlock = await makeBeaconBlockForHeadAndSlot(
PayloadType, node, randao, validator_index, graffiti, head, slot, PayloadType, node, randao, validator_index, graffiti, head, slot,
execution_payload = Opt.some shimExecutionPayload, execution_payload = Opt.some shimExecutionPayload,
transactions_root = Opt.some actualEPH.transactions_root, transactions_root = Opt.some actualEPH.transactions_root,
execution_payload_root = Opt.some hash_tree_root(actualEPH), execution_payload_root = Opt.some hash_tree_root(actualEPH),
withdrawals_root = withdrawals_root, withdrawals_root = withdrawals_root,
kzg_commitments = kzg_commitments) kzg_commitments = kzg_commitments,
execution_requests = default(ExecutionRequests))
if newBlock.isErr(): if newBlock.isErr():
# Haven't committed to the MEV block, so allow EL fallback. # Haven't committed to the MEV block, so allow EL fallback.
@ -1058,6 +1085,7 @@ proc collectBids(
let let
payloadBuilderBidFut = payloadBuilderBidFut =
if usePayloadBuilder: if usePayloadBuilder:
# TODO apparently some capella support still here?
when not (EPS is bellatrix.ExecutionPayloadForSigning): when not (EPS is bellatrix.ExecutionPayloadForSigning):
getBuilderBid[SBBB](node, payloadBuilderClient, head, getBuilderBid[SBBB](node, payloadBuilderClient, head,
validator_pubkey, slot, randao, graffitiBytes, validator_pubkey, slot, randao, graffitiBytes,
@ -2057,11 +2085,11 @@ proc makeMaybeBlindedBeaconBlockForHeadAndSlotImpl[ResultType](
collectedBids = collectedBids =
await collectBids(consensusFork.SignedBlindedBeaconBlock, await collectBids(consensusFork.SignedBlindedBeaconBlock,
consensusFork.ExecutionPayloadForSigning, consensusFork.ExecutionPayloadForSigning,
node, node,
payloadBuilderClient, proposerKey, payloadBuilderClient, proposerKey,
proposer, graffiti, head, slot, proposer, graffiti, head, slot,
randao_reveal) randao_reveal)
useBuilderBlock = useBuilderBlock =
if collectedBids.builderBid.isSome(): if collectedBids.builderBid.isSome():
collectedBids.engineBid.isNone() or builderBetterBid( collectedBids.engineBid.isNone() or builderBetterBid(

View File

@ -85,7 +85,8 @@ proc makeSimulationBlock(
var blck = partialBeaconBlock( var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload) attestations, deposits, exits, sync_aggregate, execution_payload,
default(ExecutionRequests))
let res = process_block( let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache) cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
@ -128,7 +129,8 @@ proc makeSimulationBlock(
var blck = partialBeaconBlock( var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload) attestations, deposits, exits, sync_aggregate, execution_payload,
default(ExecutionRequests))
let res = process_block( let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache) cfg, state.data, blck.asSigVerified(), verificationFlags, cache)

2
vendor/nim-web3 vendored

@ -1 +1 @@
Subproject commit c38791832cac2d23eab57cdc32decdd8123e5d36 Subproject commit a2710222060de4936ca582ef677614dc4585ff12