Skip to content
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

feat: add 4844 header fields and consensus checks #3972

Merged
merged 7 commits into from
Jul 29, 2023

Conversation

Rjected
Copy link
Member

@Rjected Rjected commented Jul 27, 2023

This adds EIP-4844 header fields:

  • blob_gas_used
  • excess_blob_gas

And their according consensus header validation checks. The method calculate_excess_blob_gas is 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

@Rjected Rjected added C-enhancement New feature or request M-changelog This change should be included in the changelog A-consensus Related to the consensus engine E-cancun Related to the Cancun network upgrade labels Jul 27, 2023
@Rjected Rjected requested a review from gakonst as a code owner July 27, 2023 17:17
@Rjected Rjected requested a review from mattsse July 27, 2023 17:18
@Rjected
Copy link
Member Author

Rjected commented Jul 27, 2023

failing proptest cases, needs an encoding / decoding fix - working on it

@codecov
Copy link

codecov bot commented Jul 27, 2023

Codecov Report

Merging #3972 (1385c79) into main (717bad8) will decrease coverage by 0.30%.
Report is 19 commits behind head on main.
The diff coverage is 70.86%.

Impacted file tree graph

Files Changed Coverage Δ
crates/consensus/auto-seal/src/lib.rs 0.00% <0.00%> (ø)
crates/interfaces/src/consensus.rs 100.00% <ø> (ø)
crates/payload/basic/src/lib.rs 0.00% <0.00%> (ø)
crates/primitives/src/blobfee.rs 0.00% <0.00%> (ø)
crates/primitives/src/lib.rs 100.00% <ø> (ø)
crates/rpc/rpc-types/src/eth/block.rs 38.84% <0.00%> (-0.46%) ⬇️
crates/rpc/rpc/src/eth/api/pending_block.rs 0.00% <0.00%> (ø)
crates/consensus/common/src/validation.rs 72.52% <13.84%> (-6.94%) ⬇️
crates/primitives/src/header.rs 95.55% <98.15%> (+0.95%) ⬆️
crates/net/eth-wire/src/types/blocks.rs 97.25% <100.00%> (+0.05%) ⬆️
... and 1 more

... and 44 files with indirect coverage changes

Flag Coverage Δ
integration-tests 16.32% <12.59%> (+0.77%) ⬆️
unit-tests 64.26% <70.07%> (-0.28%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
reth binary 26.18% <ø> (-1.01%) ⬇️
blockchain tree 83.04% <ø> (ø)
pipeline 89.82% <ø> (ø)
storage (db) 74.30% <ø> (ø)
trie 94.70% <ø> (ø)
txpool 46.00% <ø> (+<0.01%) ⬆️
networking 77.66% <100.00%> (-0.04%) ⬇️
rpc 58.47% <37.50%> (-0.29%) ⬇️
consensus 63.51% <13.43%> (-0.96%) ⬇️
revm 33.08% <ø> (-0.61%) ⬇️
payload builder 6.58% <0.00%> (-0.04%) ⬇️
primitives 87.93% <95.80%> (+0.10%) ⬆️

Comment on lines 303 to 333
// 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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should think of how to make this less horrible, since it's possible there will be even more header extensions in the future

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe different header types? like we do with transactions?

Copy link
Member Author

@Rjected Rjected Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment on lines 51 to 52
if chain_spec.fork(Hardfork::Cancun).active_at_timestamp(header.timestamp) {
let blob_gas_used = header.blob_gas_used.ok_or(ConsensusError::BlobGasUsedMissing)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so yes they need to be updated

Copy link
Member Author

@Rjected Rjected Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ 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:

let withdrawals = block.withdrawals.as_deref().unwrap_or(&[]);
if let Some(header_withdrawals_root) = header.withdrawals_root {
let withdrawals_root = reth_primitives::proofs::calculate_withdrawals_root(withdrawals);
if withdrawals_root != header_withdrawals_root {
return Err(ConsensusError::BodyWithdrawalsRootDiff {
got: withdrawals_root,
expected: header_withdrawals_root,
})
}
return Ok(())
}
if !withdrawals.is_empty() {
return Err(ConsensusError::WithdrawalsRootUnexpected)
}

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.

Comment on lines 11 to 15
if excess_blob_gas < TARGET_DATA_GAS_PER_BLOCK {
return 0
}

excess_blob_gas - TARGET_DATA_GAS_PER_BLOCK
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just saturating_sub, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, not sure how i missed this

Comment on lines +329 to +333
// 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this is a bit horrible, but still managable

Comment on lines +270 to +272
// TODO: add header fields to the rpc header
blob_gas_used: _,
excess_blob_gas: _,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will add an issue for this

@Rjected
Copy link
Member Author

Rjected commented Jul 28, 2023

will find some reference RLP data, may have to generate it using geth code

@Rjected
Copy link
Member Author

Rjected commented Jul 28, 2023

Added RLP tests from devnet-7 and EF tests

@Rjected Rjected requested a review from mattsse July 28, 2023 20:16
Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mattsse mattsse added this pull request to the merge queue Jul 29, 2023
Merged via the queue into main with commit 334d606 Jul 29, 2023
24 checks passed
@mattsse mattsse deleted the dan/blob-header-field-validation branch July 29, 2023 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-consensus Related to the consensus engine C-enhancement New feature or request E-cancun Related to the Cancun network upgrade M-changelog This change should be included in the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add cancun header fields and validate checks
2 participants