Skip to content

Commit 2184fd2

Browse files
authored
bump nim-eth, extend empty block fallback for EIP4844 (#4425)
Implements `emptyPayloadToBlockHeader` for EIP-4844. status-im/nim-eth#570
1 parent c91d9d6 commit 2184fd2

File tree

6 files changed

+108
-16
lines changed

6 files changed

+108
-16
lines changed

AllTests-mainnet.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,11 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
459459
```diff
460460
+ build_empty_execution_payload - Bellatrix OK
461461
+ build_empty_execution_payload - Capella OK
462+
+ build_empty_execution_payload - EIP4844 OK
462463
+ build_proof - BeaconState OK
463464
+ integer_squareroot OK
464465
```
465-
OK: 4/4 Fail: 0/4 Skip: 0/4
466+
OK: 5/5 Fail: 0/5 Skip: 0/5
466467
## Specific field types
467468
```diff
468469
+ root update OK
@@ -614,4 +615,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
614615
OK: 9/9 Fail: 0/9 Skip: 0/9
615616

616617
---TOTAL---
617-
OK: 343/348 Fail: 0/348 Skip: 5/348
618+
OK: 344/349 Fail: 0/349 Skip: 5/349

beacon_chain/spec/forks.nim

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ type
7777
Capella,
7878
EIP4844
7979

80+
ForkyExecutionPayload* =
81+
bellatrix.ExecutionPayload |
82+
capella.ExecutionPayload |
83+
eip4844.ExecutionPayload
84+
8085
ForkyBeaconBlockBody* =
8186
phase0.BeaconBlockBody |
8287
altair.BeaconBlockBody |
@@ -444,6 +449,7 @@ template toFork*[T:
444449
BeaconBlockFork.Altair
445450

446451
template toFork*[T:
452+
bellatrix.ExecutionPayload |
447453
bellatrix.BeaconBlock |
448454
bellatrix.SignedBeaconBlock |
449455
bellatrix.TrustedBeaconBlock |
@@ -454,6 +460,7 @@ template toFork*[T:
454460
BeaconBlockFork.Bellatrix
455461

456462
template toFork*[T:
463+
capella.ExecutionPayload |
457464
capella.BeaconBlock |
458465
capella.SignedBeaconBlock |
459466
capella.TrustedBeaconBlock |
@@ -464,6 +471,7 @@ template toFork*[T:
464471
BeaconBlockFork.Capella
465472

466473
template toFork*[T:
474+
eip4844.ExecutionPayload |
467475
eip4844.BeaconBlock |
468476
eip4844.SignedBeaconBlock |
469477
eip4844.TrustedBeaconBlock |

beacon_chain/spec/helpers.nim

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import
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

375375
proc 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
400400
proc 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

413413
proc 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

447452
proc compute_execution_block_hash*(
448-
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
449-
): Eth2Digest =
453+
payload: ForkyExecutionPayload): Eth2Digest =
450454
rlpHash payloadToBlockHeader(payload)
451455

452456
proc build_empty_execution_payload*(
@@ -481,7 +485,8 @@ proc build_empty_execution_payload*(
481485
proc 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

beacon_chain/validators/validator_duties.nim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ proc getFeeRecipient(node: BeaconNode,
332332

333333
from web3/engine_api_types import PayloadExecutionStatus
334334
from ../spec/datatypes/capella import BeaconBlock, ExecutionPayload
335+
from ../spec/datatypes/eip4844 import BeaconBlock, ExecutionPayload
335336

336337
proc getExecutionPayload[T](
337338
node: BeaconNode, proposalState: ref ForkedHashedBeaconState,
@@ -351,7 +352,9 @@ proc getExecutionPayload[T](
351352
# transmit this information through the Forked types, so this has to
352353
# be re-proven here.
353354
withState(proposalState[]):
354-
when (stateFork == BeaconStateFork.Capella and
355+
when (stateFork == BeaconStateFork.EIP4844 and
356+
T is eip4844.ExecutionPayload) or
357+
(stateFork == BeaconStateFork.Capella and
355358
T is capella.ExecutionPayload) or
356359
(stateFork == BeaconStateFork.Bellatrix and
357360
T is bellatrix.ExecutionPayload):

tests/test_helpers.nim

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,29 @@ suite "Spec helpers":
126126
validatorIndex: 2,
127127
address: bellatrix.ExecutionAddress(data: distinctBase(recipient)),
128128
amount: 2.Gwei)]
129+
130+
test "build_empty_execution_payload - EIP4844":
131+
var cfg = defaultRuntimeConfig
132+
cfg.ALTAIR_FORK_EPOCH = GENESIS_EPOCH
133+
cfg.BELLATRIX_FORK_EPOCH = GENESIS_EPOCH
134+
cfg.CAPELLA_FORK_EPOCH = GENESIS_EPOCH
135+
cfg.EIP4844_FORK_EPOCH = GENESIS_EPOCH
136+
137+
let
138+
state = newClone(initGenesisState(cfg = cfg).eip4844Data)
139+
recipient = Eth1Address.fromHex(
140+
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
141+
withdrawals = @[
142+
capella.Withdrawal(
143+
index: 42,
144+
validatorIndex: 1337,
145+
address: bellatrix.ExecutionAddress(data: distinctBase(recipient)),
146+
amount: 25.Gwei)]
147+
148+
payload = build_empty_execution_payload(
149+
state[].data, recipient, withdrawals)
150+
check:
151+
payload.fee_recipient ==
152+
bellatrix.ExecutionAddress(data: distinctBase(recipient))
153+
payload.withdrawals[0] == withdrawals[0]
154+
payload.excess_data_gas == 0.u256

0 commit comments

Comments
 (0)