Skip to content

Separate BAL from block body#9629

Merged
matkt merged 15 commits intobesu-eth:mainfrom
mirgee:separate-bals-from-block-body
Jan 22, 2026
Merged

Separate BAL from block body#9629
matkt merged 15 commits intobesu-eth:mainfrom
mirgee:separate-bals-from-block-body

Conversation

@mirgee
Copy link
Copy Markdown
Contributor

@mirgee mirgee commented Jan 13, 2026

With these changes, BALs are removed from the block body, stored and handled separately for both PoS and PoA networks.

The follow up PRs will:

  • add a CLI option to allow configurable retention policy for BALs (we must make sure to never prune BALs younger than WSP)
  • remove method overloads w/o BALs to make BALs an explicit argument (optional)

Testing was done by running pandoras-box against QBFT network with and without BALs and by running a local devnet across Amsterdam fork boundary using Ethereum Kurtosis package with tx_fuzz and spamoor.

Reference tests bal@v2.0.0 are passing, bal@v3.0.1 are not (due to incorrect state roots - maybe a problem with BPO config?).

Closes: #9589

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
…rgument

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
… QBFT is active

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
@mirgee mirgee force-pushed the separate-bals-from-block-body branch from 3d91f05 to 9fe66cf Compare January 13, 2026 11:17
Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
@mirgee mirgee force-pushed the separate-bals-from-block-body branch from 9fe66cf to 4872e93 Compare January 13, 2026 18:10
@mirgee mirgee force-pushed the separate-bals-from-block-body branch from fc60c5e to cec133c Compare January 15, 2026 09:27
Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
@mirgee mirgee force-pushed the separate-bals-from-block-body branch from cec133c to 0e2dd4a Compare January 15, 2026 15:21
Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
Signed-off-by: Karim Taam <karim.t2am@gmail.com>
Signed-off-by: Karim Taam <karim.t2am@gmail.com>
@matkt
Copy link
Copy Markdown
Contributor

matkt commented Jan 19, 2026

Started 2 nodes on mainnet to check if there is performance or stability issue with this PR
and also 1 fullsync on hoodi

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
public void multicastProposal(
final ConsensusRoundIdentifier roundIdentifier,
final QbftBlock block,
final Optional<BlockAccessList> blockAccessList,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I could do with a little more context/background to the PR that would help me understand the changes here.

So my understanding of BALs is they are a new field in the block header? But your PR separates them out from the block.

In your PR you've said stored and handled separately for both PoS and PoA networks. I think I understand storing them separately on disk - to have different retention policies etc. But I'm not sure why the code needs to pass them around separately to the block? We currently pass around QbftBlock - is there a reason this can't just contain an Optional BAL field rather than changing all of the internal function signatures?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

So my understanding of BALs is they are a new field in the block header? But your PR separates them out from the block.

There is a new BAL-related field in the block header called balHash. BALs used to be part of the block body (and hence stored together). This PR mainly separates BALs from the block body.

Passing BALs in the block was actually an intermediate stage when working on this PR, but then I invested into passing it around as a separate argument, because, conceptually, a block consists of only body + header, not body + header + BAL. BAL is a data structure separate from the block.

I don't fully understand the intended purpose of QbftBlock, but currently its only implementation simply wraps a Besu block (body + header) and wrapped Besu header (again). If that is the case, not coupling QbftBlock with BALs makes it potentially easier to remove (and thus simplify the code).

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>

# Conflicts:
#	consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/ProposalTest.java
#	ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java
@macfarla macfarla moved this to Open PRs in 26.1.0 Release Jan 22, 2026
@mirgee
Copy link
Copy Markdown
Contributor Author

mirgee commented Jan 22, 2026

Tested last version via kurtosis again, seems running fine. However currently there does seem to be a regression in QBFT.

EDIT: Fixed in fe37907

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
Copy link
Copy Markdown
Contributor

@matkt matkt left a comment

Choose a reason for hiding this comment

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

LGTM,

Tested on mainnet, hoodi and also tried to produce block on hoodi with a validator

@matkt matkt enabled auto-merge (squash) January 22, 2026 10:28
@matkt matkt merged commit a07c7bf into besu-eth:main Jan 22, 2026
46 of 61 checks passed
@github-project-automation github-project-automation bot moved this from Open PRs to Done in 26.1.0 Release Jan 22, 2026
macfarla pushed a commit to CPerezz/besu that referenced this pull request Feb 6, 2026
Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
Co-authored-by: Karim Taam <karim.t2am@gmail.com>
ghostant-1017 pushed a commit to ghostant-1017/besu that referenced this pull request Apr 9, 2026
…nodes

PR besu-eth#9629 added blockAccessList to QBFT/IBFT consensus messages but
broke backward compatibility with older nodes that do not include this
field.

PR besu-eth#9977 partially fixed this for QBFT ProposalPayload (where
blockAccessList is the last field, so isEndOfCurrentList() suffices),
but missed QBFT RoundChange where blockAccessList sits *before* the
Prepares list. In that position isEndOfCurrentList() returns false
(because Prepares is still there), causing the decoder to consume
the Prepares list as a BlockAccessList and then fail with:

  RLPException: Cannot enter a lists, input is fully consumed

Fix: use the enterList() item count to detect old (3-item) vs new
(4-item) format in QBFT RoundChange.decode().

Also add the missing isEndOfCurrentList() guard to IBFT RoundChange
and IBFT Proposal (where blockAccessList is the last field).

Signed-off-by: qinglin <qinglin@example.com>

🤖 Generated with [Qoder][https://qoder.com]
ghostant-1017 pushed a commit to ghostant-1017/besu that referenced this pull request Apr 9, 2026
…nodes

PR besu-eth#9629 added blockAccessList to QBFT/IBFT consensus messages but
broke backward compatibility with older nodes that do not include this
field.

PR besu-eth#9977 partially fixed this for QBFT ProposalPayload (where
blockAccessList is the last field, so isEndOfCurrentList() suffices),
but missed QBFT RoundChange where blockAccessList sits *before* the
Prepares list. In that position isEndOfCurrentList() returns false
(because Prepares is still there), causing the decoder to consume
the Prepares list as a BlockAccessList and then fail with:

  RLPException: Cannot enter a lists, input is fully consumed

Fix: use the enterList() item count to detect old (3-item) vs new
(4-item) format in QBFT RoundChange.decode().

Also add the missing isEndOfCurrentList() guard to IBFT RoundChange
and IBFT Proposal (where blockAccessList is the last field).

Signed-off-by: qinglin <qinglin@example.com>

🤖 Generated with [Qoder][https://qoder.com]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EIP-7928 - Block-level Access Lists : remove BAL from Body

4 participants