feat: add 4844 header fields and consensus checks#3972
Conversation
|
failing proptest cases, needs an encoding / decoding fix - working on it |
Codecov Report
... and 44 files with indirect coverage changes
Flags with carried forward coverage won't be shown. Click here to find out more.
|
| // but withdrawals root is present. | ||
| if let Some(ref base_fee) = self.base_fee_per_gas { | ||
| U256::from(*base_fee).encode(out); | ||
| } else if self.withdrawals_root.is_some() { | ||
| } else if self.withdrawals_root.is_some() || | ||
| self.blob_gas_used.is_some() || | ||
| self.excess_blob_gas.is_some() | ||
| { | ||
| out.put_u8(EMPTY_STRING_CODE); | ||
| } | ||
|
|
||
| // Encode withdrawals root. Put empty string if withdrawals root is missing, | ||
| // but blob gas used is present. | ||
| if let Some(ref root) = self.withdrawals_root { | ||
| root.encode(out); | ||
| } else if self.blob_gas_used.is_some() || self.excess_blob_gas.is_some() { | ||
| out.put_u8(EMPTY_STRING_CODE); | ||
| } | ||
|
|
||
| // Encode blob gas used. Put empty string if blob gas used is missing, | ||
| // but excess blob gas is present. | ||
| if let Some(ref blob_gas_used) = self.blob_gas_used { | ||
| U256::from(*blob_gas_used).encode(out); | ||
| } else if self.excess_blob_gas.is_some() { | ||
| out.put_u8(EMPTY_STRING_CODE); | ||
| } | ||
|
|
||
| // Encode excess blob gas. If new fields are added, the above pattern will need to be | ||
| // repeated and placeholders added. Otherwise, it's impossible to tell _which_ fields | ||
| // are missing. This is mainly relevant for contrived cases where a header is created | ||
| // at random, for example: | ||
| // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are |
There was a problem hiding this comment.
we should think of how to make this less horrible, since it's possible there will be even more header extensions in the future
There was a problem hiding this comment.
maybe different header types? like we do with transactions?
There was a problem hiding this comment.
ah, this wouldn't work because we don't have a tx type byte like we do for transactions - we'd need to know in advance (before decoding) which type of header it is
mattsse
left a comment
There was a problem hiding this comment.
this looks pretty good already, less horrible than expected actually.
we should add a few checks:
- consensus sanity checks
- rlp checks with some reference rlp data
| if chain_spec.fork(Hardfork::Cancun).active_at_timestamp(header.timestamp) { | ||
| let blob_gas_used = header.blob_gas_used.ok_or(ConsensusError::BlobGasUsedMissing)?; |
There was a problem hiding this comment.
I'd like to extract these into a standalone function
we also need to check the full block downloaders whether we need to update the checks there
There was a problem hiding this comment.
just realized our full block client enforces that the header has a withdrawals root, which is not true for pre-shanghai. but we can only perform these checks properly if we have the Arc<ChainSpec>, so it will need to be added
There was a problem hiding this comment.
so yes they need to be updated
There was a problem hiding this comment.
^ nevermind, I misread the code and this is completely wrong.
We currently only validate the body w.r.t the header, and do no other checks:
reth/crates/interfaces/src/p2p/full_block.rs
Lines 316 to 331 in be8797d
so, if there is no withdrawals root, but withdrawals exist in the body, an error is returned. And vice versa for non-empty withdrawals roots.
I'm not sure what we would check here, we perform header validation in the tree, so maybe we can keep the checks as-is.
crates/primitives/src/blobfee.rs
Outdated
| if excess_blob_gas < TARGET_DATA_GAS_PER_BLOCK { | ||
| return 0 | ||
| } | ||
|
|
||
| excess_blob_gas - TARGET_DATA_GAS_PER_BLOCK |
There was a problem hiding this comment.
this is just saturating_sub, right?
There was a problem hiding this comment.
right, not sure how i missed this
| // Encode excess blob gas. If new fields are added, the above pattern will need to be | ||
| // repeated and placeholders added. Otherwise, it's impossible to tell _which_ fields | ||
| // are missing. This is mainly relevant for contrived cases where a header is created | ||
| // at random, for example: | ||
| // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are |
There was a problem hiding this comment.
yeah this is a bit horrible, but still managable
| // TODO: add header fields to the rpc header | ||
| blob_gas_used: _, | ||
| excess_blob_gas: _, |
There was a problem hiding this comment.
will add an issue for this
|
will find some reference RLP data, may have to generate it using geth code |
|
Added RLP tests from devnet-7 and EF tests |
This adds EIP-4844 header fields:
blob_gas_usedexcess_blob_gasAnd their according consensus header validation checks. The method
calculate_excess_blob_gasis added which is specified in the EIP-4844 header extension section.RLP encoding and decoding are updated in a similar way to the withdrawals root.
Fixes #3941