bump `nim-eth`, extend empty block fallback for EIP4844 (#4425)

Implements `emptyPayloadToBlockHeader` for EIP-4844.
https://github.com/status-im/nim-eth/pull/570
This commit is contained in:
Etan Kissling 2022-12-20 20:00:56 +01:00 committed by GitHub
parent c91d9d61e2
commit 2184fd2322
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 17 deletions

View File

@ -459,10 +459,11 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
```diff
+ build_empty_execution_payload - Bellatrix OK
+ build_empty_execution_payload - Capella OK
+ build_empty_execution_payload - EIP4844 OK
+ build_proof - BeaconState OK
+ integer_squareroot OK
```
OK: 4/4 Fail: 0/4 Skip: 0/4
OK: 5/5 Fail: 0/5 Skip: 0/5
## Specific field types
```diff
+ root update OK
@ -614,4 +615,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
OK: 9/9 Fail: 0/9 Skip: 0/9
---TOTAL---
OK: 343/348 Fail: 0/348 Skip: 5/348
OK: 344/349 Fail: 0/349 Skip: 5/349

View File

@ -77,6 +77,11 @@ type
Capella,
EIP4844
ForkyExecutionPayload* =
bellatrix.ExecutionPayload |
capella.ExecutionPayload |
eip4844.ExecutionPayload
ForkyBeaconBlockBody* =
phase0.BeaconBlockBody |
altair.BeaconBlockBody |
@ -444,6 +449,7 @@ template toFork*[T:
BeaconBlockFork.Altair
template toFork*[T:
bellatrix.ExecutionPayload |
bellatrix.BeaconBlock |
bellatrix.SignedBeaconBlock |
bellatrix.TrustedBeaconBlock |
@ -454,6 +460,7 @@ template toFork*[T:
BeaconBlockFork.Bellatrix
template toFork*[T:
capella.ExecutionPayload |
capella.BeaconBlock |
capella.SignedBeaconBlock |
capella.TrustedBeaconBlock |
@ -464,6 +471,7 @@ template toFork*[T:
BeaconBlockFork.Capella
template toFork*[T:
eip4844.ExecutionPayload |
eip4844.BeaconBlock |
eip4844.SignedBeaconBlock |
eip4844.TrustedBeaconBlock |

View File

@ -19,7 +19,7 @@ import
eth/eip1559, eth/common/[eth_types, eth_types_rlp],
eth/rlp, eth/trie/[db, hexary],
# Internal
./datatypes/[phase0, altair, bellatrix, capella],
./datatypes/[phase0, altair, bellatrix, capella, eip4844],
"."/[eth2_merkleization, forks, ssz_codec]
# TODO although eth2_merkleization already exports ssz_codec, *sometimes* code
@ -373,7 +373,7 @@ func compute_timestamp_at_slot*(state: ForkyBeaconState, slot: Slot): uint64 =
state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT
proc computeTransactionsTrieRoot*(
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload): Hash256 =
payload: ForkyExecutionPayload): Hash256 =
if payload.transactions.len == 0:
return EMPTY_ROOT_HASH
@ -392,13 +392,13 @@ func toExecutionWithdrawal*(
withdrawal: capella.Withdrawal): ExecutionWithdrawal =
ExecutionWithdrawal(
index: withdrawal.index,
validatorIndex: withdrawal.validatorIndex,
validatorIndex: withdrawal.validator_index,
address: EthAddress withdrawal.address.data,
amount: gweiToWei withdrawal.amount)
# https://eips.ethereum.org/EIPS/eip-4895
proc computeWithdrawalsTrieRoot*(
payload: capella.ExecutionPayload): Hash256 =
payload: capella.ExecutionPayload | eip4844.ExecutionPayload): Hash256 =
if payload.withdrawals.len == 0:
return EMPTY_ROOT_HASH
@ -411,8 +411,7 @@ proc computeWithdrawalsTrieRoot*(
tr.rootHash()
proc payloadToBlockHeader*(
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
): ExecutionBlockHeader =
payload: ForkyExecutionPayload): ExecutionBlockHeader =
static: # `GasInt` is signed. We only use it for hashing.
doAssert sizeof(GasInt) == sizeof(payload.gas_limit)
doAssert sizeof(GasInt) == sizeof(payload.gas_used)
@ -420,10 +419,15 @@ proc payloadToBlockHeader*(
let
txRoot = payload.computeTransactionsTrieRoot()
withdrawalsRoot =
when payload is bellatrix.ExecutionPayload:
none(Hash256)
else:
when typeof(payload).toFork >= BeaconBlockFork.Capella:
some payload.computeWithdrawalsTrieRoot()
else:
none(Hash256)
excessDataGas =
when typeof(payload).toFork >= BeaconBlockFork.EIP4844:
some payload.excess_data_gas
else:
none(UInt256)
ExecutionBlockHeader(
parentHash : payload.parent_hash,
@ -442,11 +446,11 @@ proc payloadToBlockHeader*(
mixDigest : payload.prev_randao, # EIP-4399 `mixDigest` -> `prevRandao`
nonce : default(BlockNonce),
fee : some payload.base_fee_per_gas,
withdrawalsRoot: withdrawalsRoot)
withdrawalsRoot: withdrawalsRoot,
excessDataGas : excessDataGas)
proc compute_execution_block_hash*(
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
): Eth2Digest =
payload: ForkyExecutionPayload): Eth2Digest =
rlpHash payloadToBlockHeader(payload)
proc build_empty_execution_payload*(
@ -481,7 +485,8 @@ proc build_empty_execution_payload*(
proc build_empty_execution_payload*(
state: capella.BeaconState,
feeRecipient: Eth1Address,
expectedWithdrawals = newSeq[capella.Withdrawal](0)): capella.ExecutionPayload =
expectedWithdrawals = newSeq[capella.Withdrawal](0)
): capella.ExecutionPayload =
## Assuming a pre-state of the same slot, build a valid ExecutionPayload
## without any transactions.
let
@ -509,3 +514,52 @@ proc build_empty_execution_payload*(
payload.block_hash = payload.compute_execution_block_hash()
payload
# https://eips.ethereum.org/EIPS/eip-4844#parameters
const
TARGET_DATA_GAS_PER_BLOCK* = 1.u256 shl 18
DATA_GAS_PER_BLOB* = 1.u256 shl 17
# https://eips.ethereum.org/EIPS/eip-4844#header-extension
func calc_excess_data_gas*(
parent: eip4844.ExecutionPayloadHeader, new_blobs: uint): UInt256 =
let consumed_data_gas = new_blobs.u256 * DATA_GAS_PER_BLOB
return
if parent.excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK:
0.u256
else:
parent.excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK
proc build_empty_execution_payload*(
state: eip4844.BeaconState,
feeRecipient: Eth1Address,
expectedWithdrawals = newSeq[capella.Withdrawal](0)
): eip4844.ExecutionPayload =
## Assuming a pre-state of the same slot, build a valid ExecutionPayload
## without any transactions.
let
latest = state.latest_execution_payload_header
timestamp = compute_timestamp_at_slot(state, state.slot)
randao_mix = get_randao_mix(state, get_current_epoch(state))
base_fee = calcEip1599BaseFee(GasInt.saturate latest.gas_limit,
GasInt.saturate latest.gas_used,
latest.base_fee_per_gas)
var payload = eip4844.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,
prev_randao: randao_mix,
gas_limit: latest.gas_limit, # retain same limit
gas_used: 0, # empty block, 0 gas
timestamp: timestamp,
base_fee_per_gas: base_fee,
excess_data_gas: latest.calc_excess_data_gas(new_blobs = 0))
for withdrawal in expectedWithdrawals:
doAssert payload.withdrawals.add withdrawal
payload.block_hash = payload.compute_execution_block_hash()
payload

View File

@ -332,6 +332,7 @@ proc getFeeRecipient(node: BeaconNode,
from web3/engine_api_types import PayloadExecutionStatus
from ../spec/datatypes/capella import BeaconBlock, ExecutionPayload
from ../spec/datatypes/eip4844 import BeaconBlock, ExecutionPayload
proc getExecutionPayload[T](
node: BeaconNode, proposalState: ref ForkedHashedBeaconState,
@ -351,7 +352,9 @@ proc getExecutionPayload[T](
# transmit this information through the Forked types, so this has to
# be re-proven here.
withState(proposalState[]):
when (stateFork == BeaconStateFork.Capella and
when (stateFork == BeaconStateFork.EIP4844 and
T is eip4844.ExecutionPayload) or
(stateFork == BeaconStateFork.Capella and
T is capella.ExecutionPayload) or
(stateFork == BeaconStateFork.Bellatrix and
T is bellatrix.ExecutionPayload):

View File

@ -126,3 +126,29 @@ suite "Spec helpers":
validatorIndex: 2,
address: bellatrix.ExecutionAddress(data: distinctBase(recipient)),
amount: 2.Gwei)]
test "build_empty_execution_payload - EIP4844":
var cfg = defaultRuntimeConfig
cfg.ALTAIR_FORK_EPOCH = GENESIS_EPOCH
cfg.BELLATRIX_FORK_EPOCH = GENESIS_EPOCH
cfg.CAPELLA_FORK_EPOCH = GENESIS_EPOCH
cfg.EIP4844_FORK_EPOCH = GENESIS_EPOCH
let
state = newClone(initGenesisState(cfg = cfg).eip4844Data)
recipient = Eth1Address.fromHex(
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
withdrawals = @[
capella.Withdrawal(
index: 42,
validatorIndex: 1337,
address: bellatrix.ExecutionAddress(data: distinctBase(recipient)),
amount: 25.Gwei)]
payload = build_empty_execution_payload(
state[].data, recipient, withdrawals)
check:
payload.fee_recipient ==
bellatrix.ExecutionAddress(data: distinctBase(recipient))
payload.withdrawals[0] == withdrawals[0]
payload.excess_data_gas == 0.u256

2
vendor/nim-eth vendored

@ -1 +1 @@
Subproject commit 571b98d7f77ad58294c4ba7c100b145a466c8fae
Subproject commit 2b5f2a27e303b13127bb525b0c7a309eaa7fbed9