1919 eth/ eip1559, eth/ common/ [eth_types, eth_types_rlp],
2020 eth/ rlp, eth/ trie/ [db, hexary],
2121 # Internal
22- ./ datatypes/ [phase0, altair, bellatrix, capella],
22+ ./ datatypes/ [phase0, altair, bellatrix, capella, eip4844 ],
2323 " ." / [eth2_merkleization, forks, ssz_codec]
2424
2525# TODO although eth2_merkleization already exports ssz_codec, *sometimes* code
@@ -373,7 +373,7 @@ func compute_timestamp_at_slot*(state: ForkyBeaconState, slot: Slot): uint64 =
373373 state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT
374374
375375proc computeTransactionsTrieRoot * (
376- payload: bellatrix. ExecutionPayload | capella. ExecutionPayload ): Hash256 =
376+ payload: ForkyExecutionPayload ): Hash256 =
377377 if payload.transactions.len == 0 :
378378 return EMPTY_ROOT_HASH
379379
@@ -392,13 +392,13 @@ func toExecutionWithdrawal*(
392392 withdrawal: capella.Withdrawal ): ExecutionWithdrawal =
393393 ExecutionWithdrawal (
394394 index: withdrawal.index,
395- validatorIndex: withdrawal.validatorIndex ,
395+ validatorIndex: withdrawal.validator_index ,
396396 address: EthAddress withdrawal.address.data,
397397 amount: gweiToWei withdrawal.amount)
398398
399399# https://eips.ethereum.org/EIPS/eip-4895
400400proc computeWithdrawalsTrieRoot * (
401- payload: capella.ExecutionPayload ): Hash256 =
401+ payload: capella.ExecutionPayload | eip4844. ExecutionPayload ): Hash256 =
402402 if payload.withdrawals.len == 0 :
403403 return EMPTY_ROOT_HASH
404404
@@ -411,19 +411,23 @@ proc computeWithdrawalsTrieRoot*(
411411 tr.rootHash ()
412412
413413proc payloadToBlockHeader * (
414- payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
415- ): ExecutionBlockHeader =
414+ payload: ForkyExecutionPayload ): ExecutionBlockHeader =
416415 static : # `GasInt` is signed. We only use it for hashing.
417416 doAssert sizeof (GasInt ) == sizeof (payload.gas_limit)
418417 doAssert sizeof (GasInt ) == sizeof (payload.gas_used)
419418
420419 let
421420 txRoot = payload.computeTransactionsTrieRoot ()
422421 withdrawalsRoot =
423- when payload is bellatrix.ExecutionPayload :
422+ when typeof (payload).toFork >= BeaconBlockFork .Capella :
423+ some payload.computeWithdrawalsTrieRoot ()
424+ else :
424425 none (Hash256 )
426+ excessDataGas =
427+ when typeof (payload).toFork >= BeaconBlockFork .EIP4844 :
428+ some payload.excess_data_gas
425429 else :
426- some payload. computeWithdrawalsTrieRoot ( )
430+ none ( UInt256 )
427431
428432 ExecutionBlockHeader (
429433 parentHash : payload.parent_hash,
@@ -442,11 +446,11 @@ proc payloadToBlockHeader*(
442446 mixDigest : payload.prev_randao, # EIP-4399 `mixDigest` -> `prevRandao`
443447 nonce : default (BlockNonce ),
444448 fee : some payload.base_fee_per_gas,
445- withdrawalsRoot: withdrawalsRoot)
449+ withdrawalsRoot: withdrawalsRoot,
450+ excessDataGas : excessDataGas)
446451
447452proc compute_execution_block_hash * (
448- payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
449- ): Eth2Digest =
453+ payload: ForkyExecutionPayload ): Eth2Digest =
450454 rlpHash payloadToBlockHeader (payload)
451455
452456proc build_empty_execution_payload * (
@@ -481,7 +485,8 @@ proc build_empty_execution_payload*(
481485proc build_empty_execution_payload * (
482486 state: capella.BeaconState ,
483487 feeRecipient: Eth1Address ,
484- expectedWithdrawals = newSeq [capella.Withdrawal ](0 )): capella.ExecutionPayload =
488+ expectedWithdrawals = newSeq [capella.Withdrawal ](0 )
489+ ): capella.ExecutionPayload =
485490 # # Assuming a pre-state of the same slot, build a valid ExecutionPayload
486491 # # without any transactions.
487492 let
@@ -509,3 +514,52 @@ proc build_empty_execution_payload*(
509514 payload.block_hash = payload.compute_execution_block_hash ()
510515
511516 payload
517+
518+ # https://eips.ethereum.org/EIPS/eip-4844#parameters
519+ const
520+ TARGET_DATA_GAS_PER_BLOCK * = 1 .u256 shl 18
521+ DATA_GAS_PER_BLOB * = 1 .u256 shl 17
522+
523+ # https://eips.ethereum.org/EIPS/eip-4844#header-extension
524+ func calc_excess_data_gas * (
525+ parent: eip4844.ExecutionPayloadHeader , new_blobs: uint ): UInt256 =
526+ let consumed_data_gas = new_blobs.u256 * DATA_GAS_PER_BLOB
527+ return
528+ if parent.excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK :
529+ 0 .u256
530+ else :
531+ parent.excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK
532+
533+ proc build_empty_execution_payload * (
534+ state: eip4844.BeaconState ,
535+ feeRecipient: Eth1Address ,
536+ expectedWithdrawals = newSeq [capella.Withdrawal ](0 )
537+ ): eip4844.ExecutionPayload =
538+ # # Assuming a pre-state of the same slot, build a valid ExecutionPayload
539+ # # without any transactions.
540+ let
541+ latest = state.latest_execution_payload_header
542+ timestamp = compute_timestamp_at_slot (state, state.slot)
543+ randao_mix = get_randao_mix (state, get_current_epoch (state))
544+ base_fee = calcEip1599BaseFee (GasInt .saturate latest.gas_limit,
545+ GasInt .saturate latest.gas_used,
546+ latest.base_fee_per_gas)
547+
548+ var payload = eip4844.ExecutionPayload (
549+ parent_hash: latest.block_hash,
550+ fee_recipient: bellatrix.ExecutionAddress (data: distinctBase (feeRecipient)),
551+ state_root: latest.state_root, # no changes to the state
552+ receipts_root: EMPTY_ROOT_HASH ,
553+ block_number: latest.block_number + 1 ,
554+ prev_randao: randao_mix,
555+ gas_limit: latest.gas_limit, # retain same limit
556+ gas_used: 0 , # empty block, 0 gas
557+ timestamp: timestamp,
558+ base_fee_per_gas: base_fee,
559+ excess_data_gas: latest.calc_excess_data_gas (new_blobs = 0 ))
560+ for withdrawal in expectedWithdrawals:
561+ doAssert payload.withdrawals.add withdrawal
562+
563+ payload.block_hash = payload.compute_execution_block_hash ()
564+
565+ payload
0 commit comments