-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
extend BlockHeader
for Capella
#562
Conversation
Adds `Withdrawal` type according to EIP-4895, and extends `BlockHeader` accordingly. Also adds RLP encoding support for `Withdrawal` to enable building `BlockHeader` (used by Nimbus-CL in empty block prod fallback).
|
Tested on Mainnet (Bellatrix) with doAssert payload.block_hash == rlpHash payload.toBlockHeader() Also tested on Bellatrix / Capella against ethereum/consensus-specs#3126 by validating all sample block files against the Nimbus implementation. From consensus-specs PR checkout: make install_test && doctoc specs && doctoc ssz && make lint && \
make citest && make test && make clean && make generate_tests Test tool (adjust path in bottom): # beacon_chain
# Copyright (c) 2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
# Standard library
std/[os, sequtils, streams],
# Status libraries
stew/[bitops2, saturation_arith], snappy, unittest2,
eth/common/[eth_types, eth_types_rlp],
eth/trie/[db, hexary],
eth/rlp,
chronicles,
# Third-party
yaml,
# Beacon chain internals
beacon_chain/eth1/eth1_monitor,
beacon_chain/spec/datatypes/[altair, bellatrix, capella],
beacon_chain/spec/helpers,
# Test utilities
tests/testutil,
tests/consensus_spec/fixtures_utils
proc calcRootHashRlp*(items: openArray[seq[byte]]): Hash256 =
var tr = initHexaryTrie(newMemoryDB())
for i, t in items:
tr.put(rlp.encode(i), t)
return tr.rootHash()
func gweiToWei*(gwei: Gwei): UInt256 =
gwei.u256 * 1_000_000_000.u256
func toExecutionWithdrawal*(
withdrawal: capella.Withdrawal): eth_types.Withdrawal =
eth_types.Withdrawal(
index: withdrawal.index,
validatorIndex: withdrawal.validatorIndex,
address: EthAddress withdrawal.address.data,
amount: gweiToWei withdrawal.amount)
# https://eips.ethereum.org/EIPS/eip-4895
proc computeWithdrawalsTrieRoot*(
payload: capella.ExecutionPayload): Hash256 =
if payload.withdrawals.len == 0:
return EMPTY_ROOT_HASH
var tr = initHexaryTrie(newMemoryDB())
for i, withdrawal in payload.withdrawals:
try:
tr.put(rlp.encode(i), rlp.encode(toExecutionWithdrawal(withdrawal)))
except RlpError as exc:
doAssert false, "HexaryTrie.put failed: " & $exc.msg
tr.rootHash()
proc toBlockHeader*(
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
): eth_types.BlockHeader =
let
txRoot = calcRootHashRlp(seq[seq[byte]](payload.transactions))
withdrawalsRoot =
when payload is bellatrix.ExecutionPayload:
none(Hash256)
else:
some payload.computeWithdrawalsTrieRoot()
eth_types.BlockHeader(
parentHash : payload.parent_hash,
ommersHash : EMPTY_UNCLE_HASH,
coinbase : EthAddress payload.fee_recipient.data,
stateRoot : payload.state_root,
txRoot : txRoot,
receiptRoot : payload.receipts_root,
bloom : payload.logs_bloom.data,
difficulty : default(DifficultyInt),
blockNumber : payload.block_number.u256,
gasLimit : cast[GasInt](payload.gas_limit),
gasUsed : cast[GasInt](payload.gas_used),
timestamp : fromUnix(int64.saturate payload.timestamp),
extraData : payload.extra_data.asSeq,
mixDigest : payload.prev_randao, # EIP-4399 `mixDigest` -> `prevRandao`
nonce : default(BlockNonce),
fee : some payload.base_fee_per_gas,
withdrawalsRoot: withdrawalsRoot)
proc goBlck(path: string, blck: auto) =
if not blck.message.is_execution_block:
return
test path:
let
consensusPayload = blck.message.body.execution_payload
elBlockHeader = consensusPayload.toBlockHeader()
expectedBlockHash = rlpHash elBlockHeader
check consensusPayload.block_hash == expectedBlockHash
proc goFile(path: string) =
try:
goBlck path, sszDecodeEntireInput(
snappy.decode(readFileBytes(path), MaxObjectSize),
bellatrix.SignedBeaconBlock)
except SerializationError:
discard
try:
goBlck path, sszDecodeEntireInput(
snappy.decode(readFileBytes(path), MaxObjectSize),
capella.SignedBeaconBlock)
except SerializationError:
discard
proc goDir(dir: string) =
for kind, path in walkDir(dir, relative = true, checkDir = true):
if kind == pcDir:
goDir(dir/path)
else:
goFile(dir/path)
suite "Payload tests":
goDir("/path/to/consensus-spec-tests") |
let abytes = rlp.encode(a) | ||
let aa = rlp.decode(abytes, Withdrawal) | ||
check aa == a | ||
|
||
proc suite2() = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to remark to also add an additional test for a header with the withdrawalsRoot
but it looks like we don't have header at all covered here (neither with the fee addition EIP in the past apparently), so never mind.
This probably (?) does get tested on nimbus-eth1 level, and you've got it covered on the consensus test part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, hence the additional test against the EF consensus-specs-tests, which includes withdrawals. It is a bit suboptimal as I wrote both sides (the implementation on consensus-specs, as well as the nimbus one), but this is a feature not currently being used, so problems would be discovered in internal devnets the latest.
Yes, can be ignored for now. We need to resolve some issue with the p2p macro for nim-devel. |
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
The `BlockHeader` structure in `nim-eth` was updated with support for EIP-4895 (withdrawals). To enable the `nim-eth` bump, the ingress of `BlockHeader` structures has been hardened to reject headers that have the new `withdrawalsRoot` field until proper withdrawals support exists. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
The `BlockHeader` structure in `nim-eth` was updated with support for EIP-4895 (withdrawals). To enable the `nim-eth` bump, the ingress of `BlockHeader` structures has been hardened to reject headers that have the new `withdrawalsRoot` field until proper withdrawals support exists. status-im/nim-eth#562
Implements `emptyPayloadToBlockHeader` for Capella. status-im/nim-eth#562
Adds
Withdrawal
type according to EIP-4895, and extendsBlockHeader
accordingly. Also adds RLP encoding support forWithdrawal
to enable buildingBlockHeader
(used by Nimbus-CL in empty block prod fallback).