Skip to content

refactor: separate writeBlockInputToDb into parallel block and column writes - #8974

Merged
nflaig merged 9 commits into
unstablefrom
te/refactor_write_block_input_to_db
Mar 9, 2026
Merged

refactor: separate writeBlockInputToDb into parallel block and column writes#8974
nflaig merged 9 commits into
unstablefrom
te/refactor_write_block_input_to_db

Conversation

@twoeths

@twoeths twoeths commented Mar 3, 2026

Copy link
Copy Markdown
Member

Motivation

  • in preparation for gloas, columns and block could/should be written separately
  • the nice thing of having a writeDataColumnsToDb() function is gloas has to come up with the same interface, and reuse the code, especially waitForComputedAllData() to keep the same functionality we introduced in allow block import after 64 columns

Description

  • separatewriteBlockInputToDb() into writeBlockAndBlobsToDb() and writeDataColumnsToDb()
  • new IDataColumnsInput interface, gloas PayloadEnvelopeInput is expected to implement this cc @ensi321
  • only prune this.serializedCache.clear(); for pre-gloas, need to call that after we write PayloadEnvelopeInput in gloas
  • simplify writeDataColumnsToDb() to accept a single IDataColumnsInput instead of an array because that's what the consumer need

AI Assistance Disclosure

🤖 Generated with Claude Code

twoeths and others added 4 commits March 3, 2026 11:03
… writes

Add IDataColumnsInput interface and extract writeDataColumnsToDb() as a
standalone exported function accepting a narrow sub-interface of IBlockInput.
Block+blobs (pre-fulu) and data columns (fulu+) are now written in parallel,
enabling reuse of writeDataColumnsToDb() for the Gloas fork later.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the block input writing process to the database, separating the writing of block and blobs from data columns. This change prepares the codebase for the integration of gloas by introducing a reusable interface and simplifying function signatures, ultimately improving code maintainability and reusability across different forks.

Highlights

  • Refactoring: The writeBlockInputToDb function was separated into writeBlockAndBlobsToDb and writeDataColumnsToDb to allow for parallel writing of blocks/blobs and data columns.
  • New Interface: Introduced a new IDataColumnsInput interface to be implemented by PayloadEnvelopeInput in gloas, promoting code reuse and consistency.
  • Simplified Function Signature: Simplified writeDataColumnsToDb to accept a single IDataColumnsInput instead of an array, aligning with consumer needs.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • packages/beacon-node/src/chain/blocks/blockInput/types.ts
    • Added the IDataColumnsInput interface.
  • packages/beacon-node/src/chain/blocks/importBlock.ts
    • Modified the unfinalizedBlockWrites.push to accept a single blockInput instead of an array.
  • packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts
    • Separated writeBlockInputToDb into writeBlockAndBlobsToDb and writeDataColumnsToDb.
    • Modified writeDataColumnsToDb to accept a single IDataColumnsInput.
  • packages/beacon-node/src/chain/chain.ts
    • Changed persistBlockInputs import to persistBlockInput.
    • Modified unfinalizedBlockWrites to use a queue of single IBlockInput items instead of an array.
    • Updated unfinalizedBlockWrites instantiation to use persistBlockInput.
Activity
  • The pull request separates the writeBlockInputToDb function into parallel block and column writes.
  • A new IDataColumnsInput interface was introduced for reusability across forks.
  • The writeDataColumnsToDb function was simplified to accept a single IDataColumnsInput.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

…Input

For Gloas (BlockInputNoData), the execution payload and columns arrive
separately after the beacon block. The serialized cache must not be
cleared when the block is persisted — it remains available for
writeDataColumnsToDb when the payload arrives later.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request refactors the writeBlockInputToDb function to separate the writing of block and blob data from data columns, allowing for parallel execution and reusability across different forks. It introduces a new IDataColumnsInput interface for handling data columns and simplifies the writeDataColumnsToDb function. The changes aim to improve code modularity and prepare for future extensions like Gloas.

Comment thread packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts
Comment thread packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts
Comment thread packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts
@github-actions

github-actions Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Performance Report

🚀🚀 Significant benchmark improvement detected

Benchmark suite Current: a8d42d6 Previous: 66fe43a Ratio
fastMsgIdFn h64 xxhash / 10000 bytes 918.00 ns/op 3.1420 us/op 0.29
Full benchmark results
Benchmark suite Current: a8d42d6 Previous: 66fe43a Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 1.1852 ms/op 1.1043 ms/op 1.07
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 43.137 us/op 37.963 us/op 1.14
BLS verify - blst 934.18 us/op 828.69 us/op 1.13
BLS verifyMultipleSignatures 3 - blst 1.4484 ms/op 1.2526 ms/op 1.16
BLS verifyMultipleSignatures 8 - blst 1.8962 ms/op 1.9753 ms/op 0.96
BLS verifyMultipleSignatures 32 - blst 5.2225 ms/op 5.9422 ms/op 0.88
BLS verifyMultipleSignatures 64 - blst 9.7086 ms/op 11.079 ms/op 0.88
BLS verifyMultipleSignatures 128 - blst 18.706 ms/op 18.928 ms/op 0.99
BLS deserializing 10000 signatures 741.42 ms/op 734.05 ms/op 1.01
BLS deserializing 100000 signatures 7.3708 s/op 7.2306 s/op 1.02
BLS verifyMultipleSignatures - same message - 3 - blst 1.0220 ms/op 900.22 us/op 1.14
BLS verifyMultipleSignatures - same message - 8 - blst 1.1022 ms/op 1.0368 ms/op 1.06
BLS verifyMultipleSignatures - same message - 32 - blst 1.9003 ms/op 1.7066 ms/op 1.11
BLS verifyMultipleSignatures - same message - 64 - blst 2.8308 ms/op 2.5914 ms/op 1.09
BLS verifyMultipleSignatures - same message - 128 - blst 4.6274 ms/op 4.3580 ms/op 1.06
BLS aggregatePubkeys 32 - blst 20.217 us/op 19.378 us/op 1.04
BLS aggregatePubkeys 128 - blst 72.765 us/op 68.694 us/op 1.06
getSlashingsAndExits - default max 73.187 us/op 87.536 us/op 0.84
getSlashingsAndExits - 2k 332.33 us/op 304.36 us/op 1.09
isKnown best case - 1 super set check 220.00 ns/op 257.00 ns/op 0.86
isKnown normal case - 2 super set checks 212.00 ns/op 194.00 ns/op 1.09
isKnown worse case - 16 super set checks 210.00 ns/op 197.00 ns/op 1.07
validate api signedAggregateAndProof - struct 1.6515 ms/op 1.5629 ms/op 1.06
validate gossip signedAggregateAndProof - struct 1.4938 ms/op 1.5610 ms/op 0.96
batch validate gossip attestation - vc 640000 - chunk 32 122.24 us/op 120.69 us/op 1.01
batch validate gossip attestation - vc 640000 - chunk 64 108.25 us/op 106.40 us/op 1.02
batch validate gossip attestation - vc 640000 - chunk 128 103.24 us/op 98.931 us/op 1.04
batch validate gossip attestation - vc 640000 - chunk 256 99.222 us/op 94.602 us/op 1.05
bytes32 toHexString 374.00 ns/op 359.00 ns/op 1.04
bytes32 Buffer.toString(hex) 241.00 ns/op 279.00 ns/op 0.86
bytes32 Buffer.toString(hex) from Uint8Array 331.00 ns/op 479.00 ns/op 0.69
bytes32 Buffer.toString(hex) + 0x 241.00 ns/op 240.00 ns/op 1.00
Return object 10000 times 0.23540 ns/op 0.23080 ns/op 1.02
Throw Error 10000 times 4.2872 us/op 4.1577 us/op 1.03
toHex 154.77 ns/op 131.91 ns/op 1.17
Buffer.from 125.91 ns/op 115.95 ns/op 1.09
shared Buffer 79.123 ns/op 75.278 ns/op 1.05
fastMsgIdFn sha256 / 200 bytes 1.8650 us/op 1.8150 us/op 1.03
fastMsgIdFn h32 xxhash / 200 bytes 203.00 ns/op 234.00 ns/op 0.87
fastMsgIdFn h64 xxhash / 200 bytes 276.00 ns/op 302.00 ns/op 0.91
fastMsgIdFn sha256 / 1000 bytes 6.1710 us/op 5.9560 us/op 1.04
fastMsgIdFn h32 xxhash / 1000 bytes 304.00 ns/op 407.00 ns/op 0.75
fastMsgIdFn h64 xxhash / 1000 bytes 326.00 ns/op 307.00 ns/op 1.06
fastMsgIdFn sha256 / 10000 bytes 53.486 us/op 52.974 us/op 1.01
fastMsgIdFn h32 xxhash / 10000 bytes 1.4000 us/op 3.6120 us/op 0.39
fastMsgIdFn h64 xxhash / 10000 bytes 918.00 ns/op 3.1420 us/op 0.29
send data - 1000 256B messages 5.3110 ms/op 6.3933 ms/op 0.83
send data - 1000 512B messages 4.4371 ms/op 4.8558 ms/op 0.91
send data - 1000 1024B messages 5.1298 ms/op 5.3885 ms/op 0.95
send data - 1000 1200B messages 5.2488 ms/op 5.4000 ms/op 0.97
send data - 1000 2048B messages 5.3185 ms/op 5.9762 ms/op 0.89
send data - 1000 4096B messages 6.5256 ms/op 6.7020 ms/op 0.97
send data - 1000 16384B messages 32.936 ms/op 35.479 ms/op 0.93
send data - 1000 65536B messages 128.62 ms/op 106.61 ms/op 1.21
enrSubnets - fastDeserialize 64 bits 878.00 ns/op 916.00 ns/op 0.96
enrSubnets - ssz BitVector 64 bits 338.00 ns/op 331.00 ns/op 1.02
enrSubnets - fastDeserialize 4 bits 130.00 ns/op 152.00 ns/op 0.86
enrSubnets - ssz BitVector 4 bits 335.00 ns/op 479.00 ns/op 0.70
prioritizePeers score -10:0 att 32-0.1 sync 2-0 228.62 us/op 361.18 us/op 0.63
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 253.90 us/op 262.70 us/op 0.97
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 364.09 us/op 389.91 us/op 0.93
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 675.83 us/op 737.23 us/op 0.92
prioritizePeers score 0:0 att 64-1 sync 4-1 819.33 us/op 1.1703 ms/op 0.70
array of 16000 items push then shift 1.5811 us/op 1.5424 us/op 1.03
LinkedList of 16000 items push then shift 7.1860 ns/op 7.0980 ns/op 1.01
array of 16000 items push then pop 73.355 ns/op 74.340 ns/op 0.99
LinkedList of 16000 items push then pop 7.0130 ns/op 6.8650 ns/op 1.02
array of 24000 items push then shift 3.3390 us/op 2.2973 us/op 1.45
LinkedList of 24000 items push then shift 7.5560 ns/op 7.2840 ns/op 1.04
array of 24000 items push then pop 103.46 ns/op 104.64 ns/op 0.99
LinkedList of 24000 items push then pop 6.9660 ns/op 6.8760 ns/op 1.01
intersect bitArray bitLen 8 5.6210 ns/op 5.5520 ns/op 1.01
intersect array and set length 8 33.100 ns/op 32.349 ns/op 1.02
intersect bitArray bitLen 128 28.673 ns/op 27.684 ns/op 1.04
intersect array and set length 128 542.07 ns/op 535.73 ns/op 1.01
bitArray.getTrueBitIndexes() bitLen 128 969.00 ns/op 1.2960 us/op 0.75
bitArray.getTrueBitIndexes() bitLen 248 1.7060 us/op 1.8260 us/op 0.93
bitArray.getTrueBitIndexes() bitLen 512 3.5540 us/op 3.6500 us/op 0.97
Full columns - reconstruct all 6 blobs 237.48 us/op 267.71 us/op 0.89
Full columns - reconstruct half of the blobs out of 6 105.98 us/op 110.45 us/op 0.96
Full columns - reconstruct single blob out of 6 31.770 us/op 32.204 us/op 0.99
Half columns - reconstruct all 6 blobs 264.74 ms/op 263.53 ms/op 1.00
Half columns - reconstruct half of the blobs out of 6 133.69 ms/op 133.50 ms/op 1.00
Half columns - reconstruct single blob out of 6 48.669 ms/op 48.309 ms/op 1.01
Full columns - reconstruct all 10 blobs 304.63 us/op 372.30 us/op 0.82
Full columns - reconstruct half of the blobs out of 10 176.58 us/op 156.94 us/op 1.13
Full columns - reconstruct single blob out of 10 42.251 us/op 30.805 us/op 1.37
Half columns - reconstruct all 10 blobs 435.19 ms/op 437.86 ms/op 0.99
Half columns - reconstruct half of the blobs out of 10 221.09 ms/op 220.72 ms/op 1.00
Half columns - reconstruct single blob out of 10 48.316 ms/op 48.851 ms/op 0.99
Full columns - reconstruct all 20 blobs 1.1915 ms/op 721.63 us/op 1.65
Full columns - reconstruct half of the blobs out of 20 358.75 us/op 413.44 us/op 0.87
Full columns - reconstruct single blob out of 20 30.543 us/op 45.762 us/op 0.67
Half columns - reconstruct all 20 blobs 887.86 ms/op 875.41 ms/op 1.01
Half columns - reconstruct half of the blobs out of 20 455.58 ms/op 449.79 ms/op 1.01
Half columns - reconstruct single blob out of 20 51.174 ms/op 49.955 ms/op 1.02
Set add up to 64 items then delete first 2.0940 us/op 2.0770 us/op 1.01
OrderedSet add up to 64 items then delete first 3.0882 us/op 3.0886 us/op 1.00
Set add up to 64 items then delete last 2.3526 us/op 2.4361 us/op 0.97
OrderedSet add up to 64 items then delete last 3.5953 us/op 3.6816 us/op 0.98
Set add up to 64 items then delete middle 2.3829 us/op 2.4368 us/op 0.98
OrderedSet add up to 64 items then delete middle 5.2204 us/op 5.2368 us/op 1.00
Set add up to 128 items then delete first 4.8561 us/op 4.8979 us/op 0.99
OrderedSet add up to 128 items then delete first 6.9756 us/op 7.0679 us/op 0.99
Set add up to 128 items then delete last 4.9484 us/op 4.9383 us/op 1.00
OrderedSet add up to 128 items then delete last 7.7263 us/op 7.1921 us/op 1.07
Set add up to 128 items then delete middle 4.6406 us/op 4.7849 us/op 0.97
OrderedSet add up to 128 items then delete middle 14.106 us/op 13.833 us/op 1.02
Set add up to 256 items then delete first 10.043 us/op 9.8553 us/op 1.02
OrderedSet add up to 256 items then delete first 14.990 us/op 14.792 us/op 1.01
Set add up to 256 items then delete last 9.5373 us/op 9.8883 us/op 0.96
OrderedSet add up to 256 items then delete last 14.699 us/op 14.944 us/op 0.98
Set add up to 256 items then delete middle 9.3319 us/op 9.7412 us/op 0.96
OrderedSet add up to 256 items then delete middle 41.949 us/op 41.617 us/op 1.01
pass gossip attestations to forkchoice per slot 497.21 us/op 519.61 us/op 0.96
computeDeltas 1400000 validators 0% inactive 14.439 ms/op 14.508 ms/op 1.00
computeDeltas 1400000 validators 10% inactive 13.562 ms/op 13.519 ms/op 1.00
computeDeltas 1400000 validators 20% inactive 12.569 ms/op 12.580 ms/op 1.00
computeDeltas 1400000 validators 50% inactive 9.7563 ms/op 9.8278 ms/op 0.99
computeDeltas 2100000 validators 0% inactive 21.673 ms/op 22.270 ms/op 0.97
computeDeltas 2100000 validators 10% inactive 20.256 ms/op 20.790 ms/op 0.97
computeDeltas 2100000 validators 20% inactive 18.742 ms/op 18.823 ms/op 1.00
computeDeltas 2100000 validators 50% inactive 14.663 ms/op 14.745 ms/op 0.99
altair processAttestation - 250000 vs - 7PWei normalcase 1.9533 ms/op 1.9926 ms/op 0.98
altair processAttestation - 250000 vs - 7PWei worstcase 2.7697 ms/op 3.5952 ms/op 0.77
altair processAttestation - setStatus - 1/6 committees join 116.69 us/op 120.82 us/op 0.97
altair processAttestation - setStatus - 1/3 committees join 229.70 us/op 243.56 us/op 0.94
altair processAttestation - setStatus - 1/2 committees join 321.41 us/op 331.56 us/op 0.97
altair processAttestation - setStatus - 2/3 committees join 415.53 us/op 423.57 us/op 0.98
altair processAttestation - setStatus - 4/5 committees join 571.50 us/op 589.02 us/op 0.97
altair processAttestation - setStatus - 100% committees join 675.33 us/op 683.42 us/op 0.99
altair processBlock - 250000 vs - 7PWei normalcase 3.4419 ms/op 4.7244 ms/op 0.73
altair processBlock - 250000 vs - 7PWei normalcase hashState 17.629 ms/op 19.633 ms/op 0.90
altair processBlock - 250000 vs - 7PWei worstcase 22.691 ms/op 27.148 ms/op 0.84
altair processBlock - 250000 vs - 7PWei worstcase hashState 50.729 ms/op 59.605 ms/op 0.85
phase0 processBlock - 250000 vs - 7PWei normalcase 1.4775 ms/op 1.8585 ms/op 0.79
phase0 processBlock - 250000 vs - 7PWei worstcase 19.715 ms/op 26.307 ms/op 0.75
altair processEth1Data - 250000 vs - 7PWei normalcase 361.00 us/op 380.80 us/op 0.95
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 11.067 us/op 9.2640 us/op 1.19
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 44.668 us/op 53.540 us/op 0.83
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 12.204 us/op 16.683 us/op 0.73
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 8.7500 us/op 11.137 us/op 0.79
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 171.89 us/op 231.37 us/op 0.74
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.9260 ms/op 1.6949 ms/op 1.14
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 2.4049 ms/op 2.0899 ms/op 1.15
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 2.4042 ms/op 2.0675 ms/op 1.16
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 4.7950 ms/op 4.3920 ms/op 1.09
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.6888 ms/op 2.5195 ms/op 1.07
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 5.1157 ms/op 4.7074 ms/op 1.09
Tree 40 250000 create 381.55 ms/op 389.24 ms/op 0.98
Tree 40 250000 get(125000) 127.65 ns/op 129.06 ns/op 0.99
Tree 40 250000 set(125000) 1.2872 us/op 1.2535 us/op 1.03
Tree 40 250000 toArray() 16.640 ms/op 14.313 ms/op 1.16
Tree 40 250000 iterate all - toArray() + loop 16.613 ms/op 13.031 ms/op 1.27
Tree 40 250000 iterate all - get(i) 47.859 ms/op 43.449 ms/op 1.10
Array 250000 create 2.6314 ms/op 2.5123 ms/op 1.05
Array 250000 clone - spread 877.87 us/op 825.88 us/op 1.06
Array 250000 get(125000) 0.41400 ns/op 0.44400 ns/op 0.93
Array 250000 set(125000) 0.35500 ns/op 0.35800 ns/op 0.99
Array 250000 iterate all - loop 64.317 us/op 62.035 us/op 1.04
phase0 afterProcessEpoch - 250000 vs - 7PWei 43.172 ms/op 43.498 ms/op 0.99
Array.fill - length 1000000 3.0518 ms/op 3.1665 ms/op 0.96
Array push - length 1000000 12.827 ms/op 11.726 ms/op 1.09
Array.get 0.22475 ns/op 0.21920 ns/op 1.03
Uint8Array.get 0.22736 ns/op 0.22293 ns/op 1.02
phase0 beforeProcessEpoch - 250000 vs - 7PWei 14.124 ms/op 13.643 ms/op 1.04
altair processEpoch - mainnet_e81889 294.38 ms/op 309.85 ms/op 0.95
mainnet_e81889 - altair beforeProcessEpoch 17.320 ms/op 19.098 ms/op 0.91
mainnet_e81889 - altair processJustificationAndFinalization 6.2210 us/op 6.6750 us/op 0.93
mainnet_e81889 - altair processInactivityUpdates 4.1789 ms/op 3.8723 ms/op 1.08
mainnet_e81889 - altair processRewardsAndPenalties 18.617 ms/op 18.235 ms/op 1.02
mainnet_e81889 - altair processRegistryUpdates 654.00 ns/op 920.00 ns/op 0.71
mainnet_e81889 - altair processSlashings 167.00 ns/op 188.00 ns/op 0.89
mainnet_e81889 - altair processEth1DataReset 170.00 ns/op 153.00 ns/op 1.11
mainnet_e81889 - altair processEffectiveBalanceUpdates 3.2013 ms/op 1.5394 ms/op 2.08
mainnet_e81889 - altair processSlashingsReset 819.00 ns/op 1.1360 us/op 0.72
mainnet_e81889 - altair processRandaoMixesReset 1.3810 us/op 1.4670 us/op 0.94
mainnet_e81889 - altair processHistoricalRootsUpdate 167.00 ns/op 163.00 ns/op 1.02
mainnet_e81889 - altair processParticipationFlagUpdates 510.00 ns/op 518.00 ns/op 0.98
mainnet_e81889 - altair processSyncCommitteeUpdates 134.00 ns/op 134.00 ns/op 1.00
mainnet_e81889 - altair afterProcessEpoch 45.366 ms/op 43.492 ms/op 1.04
capella processEpoch - mainnet_e217614 727.59 ms/op 817.43 ms/op 0.89
mainnet_e217614 - capella beforeProcessEpoch 62.443 ms/op 61.403 ms/op 1.02
mainnet_e217614 - capella processJustificationAndFinalization 5.4650 us/op 6.0800 us/op 0.90
mainnet_e217614 - capella processInactivityUpdates 13.643 ms/op 15.102 ms/op 0.90
mainnet_e217614 - capella processRewardsAndPenalties 96.324 ms/op 108.41 ms/op 0.89
mainnet_e217614 - capella processRegistryUpdates 5.9280 us/op 5.6730 us/op 1.04
mainnet_e217614 - capella processSlashings 168.00 ns/op 155.00 ns/op 1.08
mainnet_e217614 - capella processEth1DataReset 164.00 ns/op 169.00 ns/op 0.97
mainnet_e217614 - capella processEffectiveBalanceUpdates 14.311 ms/op 11.082 ms/op 1.29
mainnet_e217614 - capella processSlashingsReset 807.00 ns/op 806.00 ns/op 1.00
mainnet_e217614 - capella processRandaoMixesReset 1.1310 us/op 1.8280 us/op 0.62
mainnet_e217614 - capella processHistoricalRootsUpdate 166.00 ns/op 258.00 ns/op 0.64
mainnet_e217614 - capella processParticipationFlagUpdates 514.00 ns/op 752.00 ns/op 0.68
mainnet_e217614 - capella afterProcessEpoch 133.15 ms/op 114.18 ms/op 1.17
phase0 processEpoch - mainnet_e58758 250.96 ms/op 253.94 ms/op 0.99
mainnet_e58758 - phase0 beforeProcessEpoch 55.792 ms/op 46.441 ms/op 1.20
mainnet_e58758 - phase0 processJustificationAndFinalization 5.8070 us/op 5.4380 us/op 1.07
mainnet_e58758 - phase0 processRewardsAndPenalties 18.538 ms/op 20.569 ms/op 0.90
mainnet_e58758 - phase0 processRegistryUpdates 2.7680 us/op 2.7890 us/op 0.99
mainnet_e58758 - phase0 processSlashings 167.00 ns/op 169.00 ns/op 0.99
mainnet_e58758 - phase0 processEth1DataReset 165.00 ns/op 199.00 ns/op 0.83
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 1.2380 ms/op 942.03 us/op 1.31
mainnet_e58758 - phase0 processSlashingsReset 904.00 ns/op 1.1250 us/op 0.80
mainnet_e58758 - phase0 processRandaoMixesReset 1.1530 us/op 1.1970 us/op 0.96
mainnet_e58758 - phase0 processHistoricalRootsUpdate 173.00 ns/op 171.00 ns/op 1.01
mainnet_e58758 - phase0 processParticipationRecordUpdates 862.00 ns/op 835.00 ns/op 1.03
mainnet_e58758 - phase0 afterProcessEpoch 35.878 ms/op 35.588 ms/op 1.01
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.2959 ms/op 1.3510 ms/op 0.96
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 2.0980 ms/op 1.9418 ms/op 1.08
altair processInactivityUpdates - 250000 normalcase 15.842 ms/op 12.479 ms/op 1.27
altair processInactivityUpdates - 250000 worstcase 13.831 ms/op 12.490 ms/op 1.11
phase0 processRegistryUpdates - 250000 normalcase 4.3770 us/op 4.5140 us/op 0.97
phase0 processRegistryUpdates - 250000 badcase_full_deposits 215.13 us/op 361.98 us/op 0.59
phase0 processRegistryUpdates - 250000 worstcase 0.5 67.152 ms/op 68.947 ms/op 0.97
altair processRewardsAndPenalties - 250000 normalcase 17.985 ms/op 23.422 ms/op 0.77
altair processRewardsAndPenalties - 250000 worstcase 16.934 ms/op 20.164 ms/op 0.84
phase0 getAttestationDeltas - 250000 normalcase 6.8305 ms/op 6.7490 ms/op 1.01
phase0 getAttestationDeltas - 250000 worstcase 6.9002 ms/op 6.7900 ms/op 1.02
phase0 processSlashings - 250000 worstcase 87.312 us/op 120.06 us/op 0.73
altair processSyncCommitteeUpdates - 250000 11.021 ms/op 10.940 ms/op 1.01
BeaconState.hashTreeRoot - No change 198.00 ns/op 209.00 ns/op 0.95
BeaconState.hashTreeRoot - 1 full validator 74.572 us/op 89.761 us/op 0.83
BeaconState.hashTreeRoot - 32 full validator 757.60 us/op 848.49 us/op 0.89
BeaconState.hashTreeRoot - 512 full validator 7.4217 ms/op 7.9408 ms/op 0.93
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 105.94 us/op 117.51 us/op 0.90
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.2667 ms/op 1.5246 ms/op 0.83
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 16.384 ms/op 21.800 ms/op 0.75
BeaconState.hashTreeRoot - 1 balances 88.957 us/op 96.508 us/op 0.92
BeaconState.hashTreeRoot - 32 balances 802.24 us/op 989.21 us/op 0.81
BeaconState.hashTreeRoot - 512 balances 5.7952 ms/op 5.8969 ms/op 0.98
BeaconState.hashTreeRoot - 250000 balances 136.88 ms/op 207.50 ms/op 0.66
aggregationBits - 2048 els - zipIndexesInBitList 31.395 us/op 18.320 us/op 1.71
regular array get 100000 times 24.699 us/op 24.852 us/op 0.99
wrappedArray get 100000 times 24.678 us/op 24.752 us/op 1.00
arrayWithProxy get 100000 times 14.017 ms/op 14.872 ms/op 0.94
ssz.Root.equals 23.668 ns/op 23.936 ns/op 0.99
byteArrayEquals 23.175 ns/op 23.504 ns/op 0.99
Buffer.compare 9.8610 ns/op 10.024 ns/op 0.98
processSlot - 1 slots 9.8370 us/op 12.148 us/op 0.81
processSlot - 32 slots 2.4268 ms/op 2.9490 ms/op 0.82
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 4.7053 ms/op 4.2419 ms/op 1.11
getCommitteeAssignments - req 1 vs - 250000 vc 1.8716 ms/op 1.8899 ms/op 0.99
getCommitteeAssignments - req 100 vs - 250000 vc 3.7020 ms/op 3.7342 ms/op 0.99
getCommitteeAssignments - req 1000 vs - 250000 vc 3.9719 ms/op 3.9970 ms/op 0.99
findModifiedValidators - 10000 modified validators 562.58 ms/op 620.88 ms/op 0.91
findModifiedValidators - 1000 modified validators 415.24 ms/op 314.89 ms/op 1.32
findModifiedValidators - 100 modified validators 324.55 ms/op 275.39 ms/op 1.18
findModifiedValidators - 10 modified validators 156.43 ms/op 264.41 ms/op 0.59
findModifiedValidators - 1 modified validators 145.37 ms/op 152.45 ms/op 0.95
findModifiedValidators - no difference 140.05 ms/op 156.84 ms/op 0.89
migrate state 1500000 validators, 3400 modified, 2000 new 987.57 ms/op 1.0933 s/op 0.90
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 4.1800 ns/op 4.1800 ns/op 1.00
state getBlockRootAtSlot - 250000 vs - 7PWei 547.07 ns/op 547.95 ns/op 1.00
computeProposerIndex 100000 validators 1.5329 ms/op 1.5566 ms/op 0.98
getNextSyncCommitteeIndices 1000 validators 118.96 ms/op 119.85 ms/op 0.99
getNextSyncCommitteeIndices 10000 validators 117.99 ms/op 119.92 ms/op 0.98
getNextSyncCommitteeIndices 100000 validators 119.48 ms/op 119.89 ms/op 1.00
computeProposers - vc 250000 605.92 us/op 625.19 us/op 0.97
computeEpochShuffling - vc 250000 41.563 ms/op 42.302 ms/op 0.98
getNextSyncCommittee - vc 250000 10.370 ms/op 10.492 ms/op 0.99
nodejs block root to RootHex using toHex 135.69 ns/op 157.30 ns/op 0.86
nodejs block root to RootHex using toRootHex 90.533 ns/op 91.670 ns/op 0.99
nodejs fromHex(blob) 236.18 us/op 297.38 us/op 0.79
nodejs fromHexInto(blob) 707.28 us/op 733.40 us/op 0.96
nodejs block root to RootHex using the deprecated toHexString 546.85 ns/op 549.98 ns/op 0.99
nodejs byteArrayEquals 32 bytes (block root) 28.187 ns/op 29.000 ns/op 0.97
nodejs byteArrayEquals 48 bytes (pubkey) 40.268 ns/op 41.050 ns/op 0.98
nodejs byteArrayEquals 96 bytes (signature) 41.461 ns/op 41.835 ns/op 0.99
nodejs byteArrayEquals 1024 bytes 46.441 ns/op 48.491 ns/op 0.96
nodejs byteArrayEquals 131072 bytes (blob) 1.8430 us/op 1.8975 us/op 0.97
browser block root to RootHex using toHex 161.43 ns/op 163.50 ns/op 0.99
browser block root to RootHex using toRootHex 151.64 ns/op 184.52 ns/op 0.82
browser fromHex(blob) 1.1864 ms/op 1.2188 ms/op 0.97
browser fromHexInto(blob) 698.52 us/op 717.32 us/op 0.97
browser block root to RootHex using the deprecated toHexString 393.48 ns/op 410.81 ns/op 0.96
browser byteArrayEquals 32 bytes (block root) 31.046 ns/op 31.442 ns/op 0.99
browser byteArrayEquals 48 bytes (pubkey) 43.206 ns/op 43.794 ns/op 0.99
browser byteArrayEquals 96 bytes (signature) 85.074 ns/op 86.296 ns/op 0.99
browser byteArrayEquals 1024 bytes 794.73 ns/op 808.25 ns/op 0.98
browser byteArrayEquals 131072 bytes (blob) 100.61 us/op 101.88 us/op 0.99

by benchmarkbot/action

@twoeths
twoeths marked this pull request as ready for review March 3, 2026 06:58
@twoeths
twoeths requested a review from a team as a code owner March 3, 2026 06:58

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8cef8fd2c9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +128 to +129
if (!isBlockInputNoData(blockInput)) {
this.serializedCache.clear();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore serialized cache clearing for NoData imports

On post-gloas blocks (BlockInputNoData), this new guard skips serializedCache.clear(), but there is currently no alternative clear path in beacon-node, so the cache is left to GC timing instead of being force-pruned after persistence. In sustained sync on a gloas network, serialized block/sidecar objects can accumulate and increase memory pressure (the prior behavior cleared on every persisted block), so this should either clear here with a safe handoff strategy or ensure a guaranteed cleanup in the payload-envelope persistence path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

for gloas that should be called in #8962

slot,
root: blockRootHex,
dataColumnSidecars: dataColumnSidecars.length,
custodyColumns: custodyColumns.length,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks like numBlobs is removed from this log because it's not in IDataColumnsInput. Is it useful to include it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes it's helpful for debug, will get it from the 1st DataColumnSidecar

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I also added numBlobs to other logs to make it consistent

await blockInput.waitForAllData(BLOB_AVAILABILITY_TIMEOUT);
}
const blobSidecars = blockInput.getBlobs();
await this.db.blobSidecars.add({blockRoot, slot, blobSidecars});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In the old code, we have

fnPromises.push(this.db.block.putBinary(this.db.block.getId(block), blockBytes));
...
fnPromises.push(this.db.blobSidecars.add({blockRoot, slot: block.message.slot, blobSidecars}));
...
await Promise.all(fnPromises);

So block and blob write happen in parallel in the old code. Here we do it sequentially. Is this intended?

@twoeths twoeths Mar 9, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

good catch, fixed it in 81ba7dd

@nflaig nflaig left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@nflaig
nflaig merged commit dce096d into unstable Mar 9, 2026
18 checks passed
@nflaig
nflaig deleted the te/refactor_write_block_input_to_db branch March 9, 2026 11:30
@codecov

codecov Bot commented Mar 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.35%. Comparing base (09945f6) to head (40b89d1).
⚠️ Report is 6 commits behind head on unstable.

Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #8974      +/-   ##
============================================
+ Coverage     52.30%   52.35%   +0.04%     
============================================
  Files           848      848              
  Lines         62689    62626      -63     
  Branches       4615     4615              
============================================
- Hits          32790    32788       -2     
+ Misses        29833    29772      -61     
  Partials         66       66              
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

lodekeeper pushed a commit to lodekeeper/lodestar that referenced this pull request Mar 13, 2026
… writes (ChainSafe#8974)

**Motivation**

- in preparation for
[gloas](https://github.com/ChainSafe/lodestar/pull/8962/changes#diff-31556a76147b927f6429470ca658ba8ea013b8a869566247b9410f791988454fR32),
columns and block could/should be written separately
- the nice thing of having a `writeDataColumnsToDb()` function is gloas
has to come up with the same interface, and reuse the code, especially
`waitForComputedAllData()` to keep the same functionality we introduced
in [allow block import after 64
columns](ChainSafe#8818)

**Description**

- separate`writeBlockInputToDb()` into `writeBlockAndBlobsToDb()` and
`writeDataColumnsToDb()`
- new `IDataColumnsInput` interface, gloas
[PayloadEnvelopeInput](https://github.com/ChainSafe/lodestar/pull/8962/changes#diff-39f10cf452f670b2fe7018b493ee4c550bb6bf19d0eac2fed0a238ed7511cf36R54)
is expected to implement this cc @ensi321
- only prune `this.serializedCache.clear();` for pre-gloas, need to call
that after we write `PayloadEnvelopeInput` in gloas
- simplify `writeDataColumnsToDb()` to accept a single
`IDataColumnsInput` instead of an array because that's what the consumer
need



**AI Assistance Disclosure**

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Tuyen Nguyen <twoeths@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: NC <17676176+ensi321@users.noreply.github.com>
@wemeetagain

Copy link
Copy Markdown
Member

🎉 This PR is included in v1.41.0 🎉

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.

4 participants