Skip to content

Conversation

nazarhussain
Copy link
Contributor

Motivation

Support single db operation to delete/put in a single repository. Will partially covers #8244 and enable next step for the across db repositories atomic write.

Description

  • Allow bundle put and delete in a single batch

Steps to test or reproduce

  • Run all tests

@nazarhussain nazarhussain requested a review from a team as a code owner August 26, 2025 10:15
Copy link
Contributor

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

Choose a reason for hiding this comment

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

Summary of Changes

Hello @nazarhussain, 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 introduces a new batch operation for database repositories, enabling atomic put and delete operations within a single transaction. This enhancement is a crucial step towards implementing atomic writes across multiple database repositories, addressing a part of issue #8244.

Highlights

  • Unified Batch Operations: Implemented a new batch method across the database interfaces (DatabaseController, Repository, PrefixedRepository) and their LevelDbController implementation, allowing put and delete operations to be bundled and executed atomically.
  • New DbBatch Type: Introduced a DbBatch type to formally define the structure for combined put and delete operations, improving type safety and clarity.
  • Refactored persistDiff Function: The persistDiff utility in opPool.ts was updated to leverage the new atomic batch operation, replacing separate batchPut and batchDelete calls for improved data consistency.
  • Comprehensive Testing: A new unit test was added to level.test.ts to thoroughly validate the functionality of the new batch operation, ensuring its reliability.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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.

Copy link
Contributor

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

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 introduces support for atomic batch operations (put and delete) on a single database repository. This is achieved by adding a new batch method to the database controller and repository layers, which is then used to refactor persistDiff in opPool.ts for more efficient and atomic database updates. The changes are well-structured and include corresponding type definitions and tests. My review includes a few suggestions to improve code conciseness using functional patterns and points out a testing configuration that should be corrected before merging.

Comment on lines +144 to +158
async batch(prefix: P, batch: DbBatch<I, T>): Promise<void> {
const batchWithKeys = [];
for (const b of batch) {
if (b.type === "del") {
batchWithKeys.push({type: b.type, key: this.wrapKey(this.encodeKeyRaw(prefix, b.key))});
} else {
batchWithKeys.push({
type: b.type,
key: this.wrapKey(this.encodeKeyRaw(prefix, b.key)),
value: this.encodeValue(b.value),
});
}
}
await this.db.batch(batchWithKeys, this.dbReqOpts);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The for loop with if/else can be simplified by using the map function on the batch array. This would make the code more concise and functional. Also, it's good practice to type batchWithKeys.

  async batch(prefix: P, batch: DbBatch<I, T>): Promise<void> {
    const batchWithKeys: DbBatch<Uint8Array, Uint8Array> = batch.map((b) => {
      const key = this.wrapKey(this.encodeKeyRaw(prefix, b.key));
      if (b.type === "del") {
        return {type: "del", key};
      } else {
        return {type: "put", key, value: this.encodeValue(b.value)};
      }
    });
    await this.db.batch(batchWithKeys, this.dbReqOpts);
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We prefer using for off instead of map iterators because of performance.

Comment on lines +160 to +166
async batchBinary(prefix: P, batch: DbBatch<I, Uint8Array>): Promise<void> {
const batchWithKeys = [];
for (const b of batch) {
batchWithKeys.push({...b, key: this.wrapKey(this.encodeKeyRaw(prefix, b.key))});
}
await this.db.batch(batchWithKeys, this.dbReqOpts);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This for loop can be simplified by using the map function on the batch array, which is more concise. It's also good practice to type batchWithKeys.

  async batchBinary(prefix: P, batch: DbBatch<I, Uint8Array>): Promise<void> {
    const batchWithKeys: DbBatch<Uint8Array, Uint8Array> = batch.map((b) => ({
      ...b,
      key: this.wrapKey(this.encodeKeyRaw(prefix, b.key)),
    }));
    await this.db.batch(batchWithKeys, this.dbReqOpts);
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We prefer using for off instead of map iterators because of performance.

Comment on lines +133 to +143
async batch(batch: DbBatch<I, T>): Promise<void> {
const batchWithKeys: DbBatch<Uint8Array, Uint8Array> = [];
for (const b of batch) {
if (b.type === "del") {
batchWithKeys.push({...b, key: this.encodeKey(b.key)});
} else {
batchWithKeys.push({...b, key: this.encodeKey(b.key), value: this.encodeValue(b.value)});
}
}
await this.db.batch(batchWithKeys, this.dbReqOpts);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The for loop with if/else can be simplified by using the map function on the batch array. This would make the code more concise, functional, and arguably more readable by explicitly constructing the new objects rather than using spread syntax with property overrides.

  async batch(batch: DbBatch<I, T>): Promise<void> {
    const batchWithKeys: DbBatch<Uint8Array, Uint8Array> = batch.map((b) => {
      if (b.type === "del") {
        return {type: "del", key: this.encodeKey(b.key)};
      } else {
        return {type: "put", key: this.encodeKey(b.key), value: this.encodeValue(b.value)};
      }
    });
    await this.db.batch(batchWithKeys, this.dbReqOpts);
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We prefer using for off instead of map iterators because of performance.

Comment on lines +145 to +151
async batchBinary(batch: DbBatch<I, Uint8Array>): Promise<void> {
const batchWithKeys: DbBatch<Uint8Array, Uint8Array> = [];
for (const b of batch) {
batchWithKeys.push({...b, key: this.encodeKey(b.key)});
}
await this.db.batch(batchWithKeys, this.dbReqOpts);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This for loop can be simplified by using the map function on the batch array, which is more concise and follows a functional programming style.

  async batchBinary(batch: DbBatch<I, Uint8Array>): Promise<void> {
    const batchWithKeys: DbBatch<Uint8Array, Uint8Array> = batch.map((b) => ({
      ...b,
      key: this.encodeKey(b.key),
    }));
    await this.db.batch(batchWithKeys, this.dbReqOpts);
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We prefer using for off instead of map iterators because of performance.

Copy link
Contributor

Performance Report

🚀🚀 Significant benchmark improvement detected

Benchmark suite Current: 88cdfd4 Previous: 5a20065 Ratio
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.8523 ms/op 8.2429 ms/op 0.22
Full benchmark results
Benchmark suite Current: 88cdfd4 Previous: 5a20065 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 990.87 us/op 1.0518 ms/op 0.94
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 35.774 us/op 36.729 us/op 0.97
BLS verify - blst 881.49 us/op 1.2190 ms/op 0.72
BLS verifyMultipleSignatures 3 - blst 1.2556 ms/op 1.3414 ms/op 0.94
BLS verifyMultipleSignatures 8 - blst 1.6818 ms/op 2.1368 ms/op 0.79
BLS verifyMultipleSignatures 32 - blst 4.9711 ms/op 6.8282 ms/op 0.73
BLS verifyMultipleSignatures 64 - blst 9.1791 ms/op 11.491 ms/op 0.80
BLS verifyMultipleSignatures 128 - blst 18.435 ms/op 19.177 ms/op 0.96
BLS deserializing 10000 signatures 700.62 ms/op 704.89 ms/op 0.99
BLS deserializing 100000 signatures 7.0115 s/op 7.1706 s/op 0.98
BLS verifyMultipleSignatures - same message - 3 - blst 951.91 us/op 926.79 us/op 1.03
BLS verifyMultipleSignatures - same message - 8 - blst 1.1786 ms/op 1.2113 ms/op 0.97
BLS verifyMultipleSignatures - same message - 32 - blst 1.9416 ms/op 1.8034 ms/op 1.08
BLS verifyMultipleSignatures - same message - 64 - blst 2.7610 ms/op 2.6793 ms/op 1.03
BLS verifyMultipleSignatures - same message - 128 - blst 4.6599 ms/op 4.5348 ms/op 1.03
BLS aggregatePubkeys 32 - blst 20.079 us/op 19.784 us/op 1.01
BLS aggregatePubkeys 128 - blst 71.128 us/op 71.917 us/op 0.99
notSeenSlots=1 numMissedVotes=1 numBadVotes=10 56.850 ms/op 60.944 ms/op 0.93
notSeenSlots=1 numMissedVotes=0 numBadVotes=4 55.862 ms/op 72.696 ms/op 0.77
notSeenSlots=2 numMissedVotes=1 numBadVotes=10 40.849 ms/op 50.757 ms/op 0.80
getSlashingsAndExits - default max 76.606 us/op 135.20 us/op 0.57
getSlashingsAndExits - 2k 366.89 us/op 396.30 us/op 0.93
proposeBlockBody type=full, size=empty 8.0214 ms/op 7.8014 ms/op 1.03
isKnown best case - 1 super set check 229.00 ns/op 261.00 ns/op 0.88
isKnown normal case - 2 super set checks 221.00 ns/op 222.00 ns/op 1.00
isKnown worse case - 16 super set checks 226.00 ns/op 235.00 ns/op 0.96
InMemoryCheckpointStateCache - add get delete 2.5010 us/op 3.2330 us/op 0.77
validate api signedAggregateAndProof - struct 1.7235 ms/op 1.6092 ms/op 1.07
validate gossip signedAggregateAndProof - struct 1.5894 ms/op 1.7236 ms/op 0.92
batch validate gossip attestation - vc 640000 - chunk 32 117.82 us/op 146.27 us/op 0.81
batch validate gossip attestation - vc 640000 - chunk 64 105.33 us/op 121.27 us/op 0.87
batch validate gossip attestation - vc 640000 - chunk 128 99.886 us/op 123.85 us/op 0.81
batch validate gossip attestation - vc 640000 - chunk 256 105.94 us/op 121.33 us/op 0.87
pickEth1Vote - no votes 997.91 us/op 1.0627 ms/op 0.94
pickEth1Vote - max votes 7.9629 ms/op 8.8902 ms/op 0.90
pickEth1Vote - Eth1Data hashTreeRoot value x2048 13.753 ms/op 15.353 ms/op 0.90
pickEth1Vote - Eth1Data hashTreeRoot tree x2048 19.538 ms/op 25.622 ms/op 0.76
pickEth1Vote - Eth1Data fastSerialize value x2048 460.12 us/op 472.95 us/op 0.97
pickEth1Vote - Eth1Data fastSerialize tree x2048 2.6101 ms/op 5.0740 ms/op 0.51
bytes32 toHexString 390.00 ns/op 386.00 ns/op 1.01
bytes32 Buffer.toString(hex) 268.00 ns/op 270.00 ns/op 0.99
bytes32 Buffer.toString(hex) from Uint8Array 352.00 ns/op 362.00 ns/op 0.97
bytes32 Buffer.toString(hex) + 0x 267.00 ns/op 274.00 ns/op 0.97
Object access 1 prop 0.12600 ns/op 0.13100 ns/op 0.96
Map access 1 prop 0.13100 ns/op 0.13200 ns/op 0.99
Object get x1000 5.9190 ns/op 6.3480 ns/op 0.93
Map get x1000 6.6610 ns/op 7.2970 ns/op 0.91
Object set x1000 31.317 ns/op 32.797 ns/op 0.95
Map set x1000 20.350 ns/op 22.288 ns/op 0.91
Return object 10000 times 0.29180 ns/op 0.30940 ns/op 0.94
Throw Error 10000 times 4.4886 us/op 5.6809 us/op 0.79
toHex 136.47 ns/op 141.96 ns/op 0.96
Buffer.from 123.86 ns/op 126.83 ns/op 0.98
shared Buffer 83.946 ns/op 87.658 ns/op 0.96
fastMsgIdFn sha256 / 200 bytes 2.2170 us/op 2.3720 us/op 0.93
fastMsgIdFn h32 xxhash / 200 bytes 214.00 ns/op 241.00 ns/op 0.89
fastMsgIdFn h64 xxhash / 200 bytes 270.00 ns/op 297.00 ns/op 0.91
fastMsgIdFn sha256 / 1000 bytes 7.5530 us/op 8.2660 us/op 0.91
fastMsgIdFn h32 xxhash / 1000 bytes 347.00 ns/op 458.00 ns/op 0.76
fastMsgIdFn h64 xxhash / 1000 bytes 345.00 ns/op 498.00 ns/op 0.69
fastMsgIdFn sha256 / 10000 bytes 65.214 us/op 69.245 us/op 0.94
fastMsgIdFn h32 xxhash / 10000 bytes 1.8490 us/op 1.9550 us/op 0.95
fastMsgIdFn h64 xxhash / 10000 bytes 1.3040 us/op 1.4340 us/op 0.91
send data - 1000 256B messages 19.572 ms/op 22.679 ms/op 0.86
send data - 1000 512B messages 25.687 ms/op 24.277 ms/op 1.06
send data - 1000 1024B messages 30.798 ms/op 31.327 ms/op 0.98
send data - 1000 1200B messages 26.559 ms/op 29.327 ms/op 0.91
send data - 1000 2048B messages 28.314 ms/op 28.545 ms/op 0.99
send data - 1000 4096B messages 30.677 ms/op 32.080 ms/op 0.96
send data - 1000 16384B messages 54.620 ms/op 57.729 ms/op 0.95
send data - 1000 65536B messages 131.25 ms/op 131.44 ms/op 1.00
enrSubnets - fastDeserialize 64 bits 902.00 ns/op 942.00 ns/op 0.96
enrSubnets - ssz BitVector 64 bits 334.00 ns/op 381.00 ns/op 0.88
enrSubnets - fastDeserialize 4 bits 143.00 ns/op 160.00 ns/op 0.89
enrSubnets - ssz BitVector 4 bits 334.00 ns/op 425.00 ns/op 0.79
prioritizePeers score -10:0 att 32-0.1 sync 2-0 124.52 us/op 153.58 us/op 0.81
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 143.43 us/op 193.73 us/op 0.74
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 206.27 us/op 224.89 us/op 0.92
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 388.02 us/op 441.25 us/op 0.88
prioritizePeers score 0:0 att 64-1 sync 4-1 482.23 us/op 501.45 us/op 0.96
array of 16000 items push then shift 1.6381 us/op 1.7528 us/op 0.93
LinkedList of 16000 items push then shift 7.5660 ns/op 10.289 ns/op 0.74
array of 16000 items push then pop 85.462 ns/op 91.723 ns/op 0.93
LinkedList of 16000 items push then pop 7.6010 ns/op 8.3770 ns/op 0.91
array of 24000 items push then shift 2.4217 us/op 2.6193 us/op 0.92
LinkedList of 24000 items push then shift 8.7380 ns/op 10.162 ns/op 0.86
array of 24000 items push then pop 115.71 ns/op 125.54 ns/op 0.92
LinkedList of 24000 items push then pop 7.1920 ns/op 8.0170 ns/op 0.90
intersect bitArray bitLen 8 6.3660 ns/op 6.7070 ns/op 0.95
intersect array and set length 8 38.064 ns/op 43.590 ns/op 0.87
intersect bitArray bitLen 128 29.910 ns/op 32.833 ns/op 0.91
intersect array and set length 128 593.33 ns/op 703.78 ns/op 0.84
bitArray.getTrueBitIndexes() bitLen 128 1.0470 us/op 1.3190 us/op 0.79
bitArray.getTrueBitIndexes() bitLen 248 1.9010 us/op 2.0410 us/op 0.93
bitArray.getTrueBitIndexes() bitLen 512 3.8030 us/op 4.3990 us/op 0.86
Buffer.concat 32 items 614.00 ns/op 721.00 ns/op 0.85
Uint8Array.set 32 items 1.7420 us/op 1.4270 us/op 1.22
Buffer.copy 2.1790 us/op 4.2780 us/op 0.51
Uint8Array.set - with subarray 1.7940 us/op 3.6380 us/op 0.49
Uint8Array.set - without subarray 931.00 ns/op 2.2410 us/op 0.42
getUint32 - dataview 197.00 ns/op 222.00 ns/op 0.89
getUint32 - manual 124.00 ns/op 138.00 ns/op 0.90
Set add up to 64 items then delete first 2.1296 us/op 3.1460 us/op 0.68
OrderedSet add up to 64 items then delete first 3.6501 us/op 5.5147 us/op 0.66
Set add up to 64 items then delete last 2.5422 us/op 2.4963 us/op 1.02
OrderedSet add up to 64 items then delete last 4.4931 us/op 4.9222 us/op 0.91
Set add up to 64 items then delete middle 2.4727 us/op 3.3173 us/op 0.75
OrderedSet add up to 64 items then delete middle 5.1939 us/op 6.8126 us/op 0.76
Set add up to 128 items then delete first 4.9652 us/op 7.0599 us/op 0.70
OrderedSet add up to 128 items then delete first 7.2114 us/op 11.315 us/op 0.64
Set add up to 128 items then delete last 4.9125 us/op 7.0145 us/op 0.70
OrderedSet add up to 128 items then delete last 8.2513 us/op 11.085 us/op 0.74
Set add up to 128 items then delete middle 4.8117 us/op 7.0064 us/op 0.69
OrderedSet add up to 128 items then delete middle 15.187 us/op 18.436 us/op 0.82
Set add up to 256 items then delete first 10.039 us/op 14.109 us/op 0.71
OrderedSet add up to 256 items then delete first 14.684 us/op 24.847 us/op 0.59
Set add up to 256 items then delete last 9.9276 us/op 14.860 us/op 0.67
OrderedSet add up to 256 items then delete last 15.294 us/op 22.147 us/op 0.69
Set add up to 256 items then delete middle 9.6926 us/op 13.492 us/op 0.72
OrderedSet add up to 256 items then delete middle 40.081 us/op 50.250 us/op 0.80
transfer serialized Status (84 B) 2.2300 us/op 3.2270 us/op 0.69
copy serialized Status (84 B) 1.1940 us/op 1.9680 us/op 0.61
transfer serialized SignedVoluntaryExit (112 B) 2.2000 us/op 3.7260 us/op 0.59
copy serialized SignedVoluntaryExit (112 B) 1.1960 us/op 1.8860 us/op 0.63
transfer serialized ProposerSlashing (416 B) 2.2450 us/op 3.8240 us/op 0.59
copy serialized ProposerSlashing (416 B) 1.6560 us/op 2.6270 us/op 0.63
transfer serialized Attestation (485 B) 2.3320 us/op 3.9540 us/op 0.59
copy serialized Attestation (485 B) 1.3410 us/op 2.8160 us/op 0.48
transfer serialized AttesterSlashing (33232 B) 2.6550 us/op 3.9480 us/op 0.67
copy serialized AttesterSlashing (33232 B) 3.6960 us/op 6.4110 us/op 0.58
transfer serialized Small SignedBeaconBlock (128000 B) 3.3090 us/op 4.3340 us/op 0.76
copy serialized Small SignedBeaconBlock (128000 B) 8.9070 us/op 20.134 us/op 0.44
transfer serialized Avg SignedBeaconBlock (200000 B) 3.7760 us/op 6.3110 us/op 0.60
copy serialized Avg SignedBeaconBlock (200000 B) 12.822 us/op 34.559 us/op 0.37
transfer serialized BlobsSidecar (524380 B) 3.6160 us/op 6.1280 us/op 0.59
copy serialized BlobsSidecar (524380 B) 60.484 us/op 116.27 us/op 0.52
transfer serialized Big SignedBeaconBlock (1000000 B) 3.6500 us/op 6.4480 us/op 0.57
copy serialized Big SignedBeaconBlock (1000000 B) 117.00 us/op 190.92 us/op 0.61
pass gossip attestations to forkchoice per slot 2.7648 ms/op 3.1772 ms/op 0.87
forkChoice updateHead vc 100000 bc 64 eq 0 451.53 us/op 481.27 us/op 0.94
forkChoice updateHead vc 600000 bc 64 eq 0 2.8562 ms/op 3.6452 ms/op 0.78
forkChoice updateHead vc 1000000 bc 64 eq 0 4.8243 ms/op 6.3341 ms/op 0.76
forkChoice updateHead vc 600000 bc 320 eq 0 2.9435 ms/op 3.7301 ms/op 0.79
forkChoice updateHead vc 600000 bc 1200 eq 0 2.8743 ms/op 3.8439 ms/op 0.75
forkChoice updateHead vc 600000 bc 7200 eq 0 3.1258 ms/op 4.5367 ms/op 0.69
forkChoice updateHead vc 600000 bc 64 eq 1000 10.144 ms/op 11.362 ms/op 0.89
forkChoice updateHead vc 600000 bc 64 eq 10000 10.085 ms/op 11.540 ms/op 0.87
forkChoice updateHead vc 600000 bc 64 eq 300000 13.655 ms/op 28.882 ms/op 0.47
computeDeltas 500000 validators 300 proto nodes 4.0100 ms/op 4.7537 ms/op 0.84
computeDeltas 500000 validators 1200 proto nodes 3.9664 ms/op 4.6661 ms/op 0.85
computeDeltas 500000 validators 7200 proto nodes 4.1448 ms/op 4.5209 ms/op 0.92
computeDeltas 750000 validators 300 proto nodes 6.1906 ms/op 6.5660 ms/op 0.94
computeDeltas 750000 validators 1200 proto nodes 6.8502 ms/op 7.2261 ms/op 0.95
computeDeltas 750000 validators 7200 proto nodes 6.3255 ms/op 7.3806 ms/op 0.86
computeDeltas 1400000 validators 300 proto nodes 11.486 ms/op 14.017 ms/op 0.82
computeDeltas 1400000 validators 1200 proto nodes 12.653 ms/op 14.111 ms/op 0.90
computeDeltas 1400000 validators 7200 proto nodes 11.320 ms/op 13.805 ms/op 0.82
computeDeltas 2100000 validators 300 proto nodes 17.434 ms/op 19.857 ms/op 0.88
computeDeltas 2100000 validators 1200 proto nodes 16.826 ms/op 19.387 ms/op 0.87
computeDeltas 2100000 validators 7200 proto nodes 16.788 ms/op 19.824 ms/op 0.85
altair processAttestation - 250000 vs - 7PWei normalcase 2.5799 ms/op 2.3006 ms/op 1.12
altair processAttestation - 250000 vs - 7PWei worstcase 3.8178 ms/op 4.6542 ms/op 0.82
altair processAttestation - setStatus - 1/6 committees join 147.09 us/op 156.06 us/op 0.94
altair processAttestation - setStatus - 1/3 committees join 245.75 us/op 274.39 us/op 0.90
altair processAttestation - setStatus - 1/2 committees join 342.52 us/op 376.70 us/op 0.91
altair processAttestation - setStatus - 2/3 committees join 472.95 us/op 478.87 us/op 0.99
altair processAttestation - setStatus - 4/5 committees join 643.65 us/op 689.26 us/op 0.93
altair processAttestation - setStatus - 100% committees join 780.56 us/op 817.51 us/op 0.95
altair processBlock - 250000 vs - 7PWei normalcase 6.4264 ms/op 10.324 ms/op 0.62
altair processBlock - 250000 vs - 7PWei normalcase hashState 32.161 ms/op 38.862 ms/op 0.83
altair processBlock - 250000 vs - 7PWei worstcase 38.906 ms/op 46.685 ms/op 0.83
altair processBlock - 250000 vs - 7PWei worstcase hashState 80.233 ms/op 95.548 ms/op 0.84
phase0 processBlock - 250000 vs - 7PWei normalcase 1.6836 ms/op 2.3972 ms/op 0.70
phase0 processBlock - 250000 vs - 7PWei worstcase 23.837 ms/op 29.849 ms/op 0.80
altair processEth1Data - 250000 vs - 7PWei normalcase 349.51 us/op 362.81 us/op 0.96
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:15 6.7350 us/op 7.5710 us/op 0.89
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:219 50.826 us/op 52.625 us/op 0.97
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:42 13.090 us/op 13.821 us/op 0.95
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:18 7.0430 us/op 8.5540 us/op 0.82
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1020 175.95 us/op 203.47 us/op 0.86
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11777 1.8889 ms/op 2.5793 ms/op 0.73
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 2.4133 ms/op 2.6345 ms/op 0.92
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 2.4246 ms/op 2.5243 ms/op 0.96
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 5.1653 ms/op 6.6540 ms/op 0.78
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.4191 ms/op 2.7769 ms/op 0.87
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.9201 ms/op 5.9908 ms/op 0.82
Tree 40 250000 create 439.17 ms/op 605.87 ms/op 0.72
Tree 40 250000 get(125000) 140.53 ns/op 147.45 ns/op 0.95
Tree 40 250000 set(125000) 1.5442 us/op 1.8794 us/op 0.82
Tree 40 250000 toArray() 18.266 ms/op 23.405 ms/op 0.78
Tree 40 250000 iterate all - toArray() + loop 18.370 ms/op 23.679 ms/op 0.78
Tree 40 250000 iterate all - get(i) 53.115 ms/op 62.946 ms/op 0.84
Array 250000 create 2.5717 ms/op 4.4596 ms/op 0.58
Array 250000 clone - spread 1.3981 ms/op 1.7981 ms/op 0.78
Array 250000 get(125000) 0.41500 ns/op 0.47800 ns/op 0.87
Array 250000 set(125000) 0.44100 ns/op 0.46700 ns/op 0.94
Array 250000 iterate all - loop 99.926 us/op 89.982 us/op 1.11
phase0 afterProcessEpoch - 250000 vs - 7PWei 42.646 ms/op 44.837 ms/op 0.95
Array.fill - length 1000000 3.4542 ms/op 5.1340 ms/op 0.67
Array push - length 1000000 14.658 ms/op 23.221 ms/op 0.63
Array.get 0.28637 ns/op 0.29900 ns/op 0.96
Uint8Array.get 0.43731 ns/op 0.47273 ns/op 0.93
phase0 beforeProcessEpoch - 250000 vs - 7PWei 19.704 ms/op 25.246 ms/op 0.78
altair processEpoch - mainnet_e81889 243.81 ms/op 349.71 ms/op 0.70
mainnet_e81889 - altair beforeProcessEpoch 17.749 ms/op 20.955 ms/op 0.85
mainnet_e81889 - altair processJustificationAndFinalization 5.3600 us/op 6.4590 us/op 0.83
mainnet_e81889 - altair processInactivityUpdates 4.1166 ms/op 6.3697 ms/op 0.65
mainnet_e81889 - altair processRewardsAndPenalties 40.287 ms/op 53.290 ms/op 0.76
mainnet_e81889 - altair processRegistryUpdates 703.00 ns/op 882.00 ns/op 0.80
mainnet_e81889 - altair processSlashings 186.00 ns/op 277.00 ns/op 0.67
mainnet_e81889 - altair processEth1DataReset 181.00 ns/op 191.00 ns/op 0.95
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.1708 ms/op 1.2735 ms/op 0.92
mainnet_e81889 - altair processSlashingsReset 867.00 ns/op 1.1190 us/op 0.77
mainnet_e81889 - altair processRandaoMixesReset 1.1210 us/op 1.4000 us/op 0.80
mainnet_e81889 - altair processHistoricalRootsUpdate 186.00 ns/op 192.00 ns/op 0.97
mainnet_e81889 - altair processParticipationFlagUpdates 527.00 ns/op 778.00 ns/op 0.68
mainnet_e81889 - altair processSyncCommitteeUpdates 147.00 ns/op 162.00 ns/op 0.91
mainnet_e81889 - altair afterProcessEpoch 44.368 ms/op 48.025 ms/op 0.92
capella processEpoch - mainnet_e217614 792.72 ms/op 972.47 ms/op 0.82
mainnet_e217614 - capella beforeProcessEpoch 62.709 ms/op 68.121 ms/op 0.92
mainnet_e217614 - capella processJustificationAndFinalization 6.6040 us/op 7.5450 us/op 0.88
mainnet_e217614 - capella processInactivityUpdates 14.133 ms/op 16.699 ms/op 0.85
mainnet_e217614 - capella processRewardsAndPenalties 175.48 ms/op 213.50 ms/op 0.82
mainnet_e217614 - capella processRegistryUpdates 6.3480 us/op 6.9120 us/op 0.92
mainnet_e217614 - capella processSlashings 177.00 ns/op 211.00 ns/op 0.84
mainnet_e217614 - capella processEth1DataReset 175.00 ns/op 275.00 ns/op 0.64
mainnet_e217614 - capella processEffectiveBalanceUpdates 4.1518 ms/op 4.4888 ms/op 0.92
mainnet_e217614 - capella processSlashingsReset 876.00 ns/op 993.00 ns/op 0.88
mainnet_e217614 - capella processRandaoMixesReset 1.1520 us/op 1.4360 us/op 0.80
mainnet_e217614 - capella processHistoricalRootsUpdate 176.00 ns/op 246.00 ns/op 0.72
mainnet_e217614 - capella processParticipationFlagUpdates 502.00 ns/op 641.00 ns/op 0.78
mainnet_e217614 - capella afterProcessEpoch 111.96 ms/op 122.12 ms/op 0.92
phase0 processEpoch - mainnet_e58758 276.96 ms/op 492.38 ms/op 0.56
mainnet_e58758 - phase0 beforeProcessEpoch 72.337 ms/op 162.04 ms/op 0.45
mainnet_e58758 - phase0 processJustificationAndFinalization 5.3340 us/op 11.265 us/op 0.47
mainnet_e58758 - phase0 processRewardsAndPenalties 38.287 ms/op 55.570 ms/op 0.69
mainnet_e58758 - phase0 processRegistryUpdates 3.1440 us/op 4.3240 us/op 0.73
mainnet_e58758 - phase0 processSlashings 208.00 ns/op 235.00 ns/op 0.89
mainnet_e58758 - phase0 processEth1DataReset 180.00 ns/op 285.00 ns/op 0.63
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 1.1661 ms/op 5.5738 ms/op 0.21
mainnet_e58758 - phase0 processSlashingsReset 954.00 ns/op 1.9190 us/op 0.50
mainnet_e58758 - phase0 processRandaoMixesReset 1.1910 us/op 1.8220 us/op 0.65
mainnet_e58758 - phase0 processHistoricalRootsUpdate 176.00 ns/op 375.00 ns/op 0.47
mainnet_e58758 - phase0 processParticipationRecordUpdates 893.00 ns/op 1.3660 us/op 0.65
mainnet_e58758 - phase0 afterProcessEpoch 36.196 ms/op 41.264 ms/op 0.88
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.3686 ms/op 3.0523 ms/op 0.45
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.8523 ms/op 8.2429 ms/op 0.22
altair processInactivityUpdates - 250000 normalcase 17.282 ms/op 30.944 ms/op 0.56
altair processInactivityUpdates - 250000 worstcase 18.525 ms/op 32.820 ms/op 0.56
phase0 processRegistryUpdates - 250000 normalcase 6.3650 us/op 14.984 us/op 0.42
phase0 processRegistryUpdates - 250000 badcase_full_deposits 266.06 us/op 381.76 us/op 0.70
phase0 processRegistryUpdates - 250000 worstcase 0.5 101.76 ms/op 180.51 ms/op 0.56
altair processRewardsAndPenalties - 250000 normalcase 27.026 ms/op 31.051 ms/op 0.87
altair processRewardsAndPenalties - 250000 worstcase 26.775 ms/op 36.066 ms/op 0.74
phase0 getAttestationDeltas - 250000 normalcase 5.9770 ms/op 9.3311 ms/op 0.64
phase0 getAttestationDeltas - 250000 worstcase 6.0708 ms/op 18.014 ms/op 0.34
phase0 processSlashings - 250000 worstcase 96.000 us/op 139.77 us/op 0.69
altair processSyncCommitteeUpdates - 250000 11.222 ms/op 14.042 ms/op 0.80
BeaconState.hashTreeRoot - No change 216.00 ns/op 284.00 ns/op 0.76
BeaconState.hashTreeRoot - 1 full validator 82.215 us/op 115.86 us/op 0.71
BeaconState.hashTreeRoot - 32 full validator 1.1009 ms/op 1.7794 ms/op 0.62
BeaconState.hashTreeRoot - 512 full validator 12.874 ms/op 16.660 ms/op 0.77
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 104.81 us/op 182.78 us/op 0.57
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.4336 ms/op 2.2270 ms/op 0.64
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 19.768 ms/op 36.200 ms/op 0.55
BeaconState.hashTreeRoot - 1 balances 71.453 us/op 130.12 us/op 0.55
BeaconState.hashTreeRoot - 32 balances 650.47 us/op 1.3724 ms/op 0.47
BeaconState.hashTreeRoot - 512 balances 6.7526 ms/op 12.986 ms/op 0.52
BeaconState.hashTreeRoot - 250000 balances 142.98 ms/op 241.91 ms/op 0.59
aggregationBits - 2048 els - zipIndexesInBitList 21.271 us/op 30.863 us/op 0.69
byteArrayEquals 32 52.544 ns/op 58.796 ns/op 0.89
Buffer.compare 32 16.654 ns/op 18.873 ns/op 0.88
byteArrayEquals 1024 1.5503 us/op 1.6989 us/op 0.91
Buffer.compare 1024 24.899 ns/op 28.120 ns/op 0.89
byteArrayEquals 16384 24.783 us/op 28.138 us/op 0.88
Buffer.compare 16384 189.02 ns/op 236.54 ns/op 0.80
byteArrayEquals 123687377 191.11 ms/op 220.56 ms/op 0.87
Buffer.compare 123687377 9.5871 ms/op 13.008 ms/op 0.74
byteArrayEquals 32 - diff last byte 52.250 ns/op 83.590 ns/op 0.63
Buffer.compare 32 - diff last byte 16.907 ns/op 18.251 ns/op 0.93
byteArrayEquals 1024 - diff last byte 1.5946 us/op 2.4627 us/op 0.65
Buffer.compare 1024 - diff last byte 24.818 ns/op 28.200 ns/op 0.88
byteArrayEquals 16384 - diff last byte 25.849 us/op 27.403 us/op 0.94
Buffer.compare 16384 - diff last byte 210.27 ns/op 294.11 ns/op 0.71
byteArrayEquals 123687377 - diff last byte 198.25 ms/op 214.94 ms/op 0.92
Buffer.compare 123687377 - diff last byte 7.4944 ms/op 13.621 ms/op 0.55
byteArrayEquals 32 - random bytes 5.2730 ns/op 6.1750 ns/op 0.85
Buffer.compare 32 - random bytes 18.033 ns/op 27.152 ns/op 0.66
byteArrayEquals 1024 - random bytes 5.2630 ns/op 7.5240 ns/op 0.70
Buffer.compare 1024 - random bytes 18.026 ns/op 18.529 ns/op 0.97
byteArrayEquals 16384 - random bytes 5.1440 ns/op 5.4940 ns/op 0.94
Buffer.compare 16384 - random bytes 17.089 ns/op 22.303 ns/op 0.77
byteArrayEquals 123687377 - random bytes 6.4900 ns/op 8.5900 ns/op 0.76
Buffer.compare 123687377 - random bytes 23.400 ns/op 21.740 ns/op 1.08
regular array get 100000 times 33.702 us/op 65.533 us/op 0.51
wrappedArray get 100000 times 33.080 us/op 55.239 us/op 0.60
arrayWithProxy get 100000 times 16.127 ms/op 13.978 ms/op 1.15
ssz.Root.equals 50.340 ns/op 49.778 ns/op 1.01
byteArrayEquals 47.424 ns/op 50.593 ns/op 0.94
Buffer.compare 10.760 ns/op 11.366 ns/op 0.95
processSlot - 1 slots 11.004 us/op 12.373 us/op 0.89
processSlot - 32 slots 2.2450 ms/op 2.7242 ms/op 0.82
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 3.3479 ms/op 5.9885 ms/op 0.56
getCommitteeAssignments - req 1 vs - 250000 vc 2.1260 ms/op 2.3472 ms/op 0.91
getCommitteeAssignments - req 100 vs - 250000 vc 4.1455 ms/op 4.8238 ms/op 0.86
getCommitteeAssignments - req 1000 vs - 250000 vc 4.4058 ms/op 5.0232 ms/op 0.88
findModifiedValidators - 10000 modified validators 775.92 ms/op 1.0746 s/op 0.72
findModifiedValidators - 1000 modified validators 753.19 ms/op 868.45 ms/op 0.87
findModifiedValidators - 100 modified validators 292.46 ms/op 307.46 ms/op 0.95
findModifiedValidators - 10 modified validators 208.45 ms/op 278.61 ms/op 0.75
findModifiedValidators - 1 modified validators 153.76 ms/op 324.27 ms/op 0.47
findModifiedValidators - no difference 158.20 ms/op 339.05 ms/op 0.47
compare ViewDUs 6.8219 s/op 6.7342 s/op 1.01
compare each validator Uint8Array 2.0336 s/op 1.6136 s/op 1.26
compare ViewDU to Uint8Array 2.0077 s/op 1.0498 s/op 1.91
migrate state 1000000 validators, 24 modified, 0 new 910.01 ms/op 846.46 ms/op 1.08
migrate state 1000000 validators, 1700 modified, 1000 new 1.3329 s/op 1.1740 s/op 1.14
migrate state 1000000 validators, 3400 modified, 2000 new 1.5730 s/op 1.3826 s/op 1.14
migrate state 1500000 validators, 24 modified, 0 new 1.0341 s/op 960.77 ms/op 1.08
migrate state 1500000 validators, 1700 modified, 1000 new 1.2819 s/op 1.3199 s/op 0.97
migrate state 1500000 validators, 3400 modified, 2000 new 1.3891 s/op 1.7433 s/op 0.80
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 4.6000 ns/op 5.4900 ns/op 0.84
state getBlockRootAtSlot - 250000 vs - 7PWei 664.14 ns/op 589.74 ns/op 1.13
naive computeProposerIndex 100000 validators 71.828 ms/op 66.854 ms/op 1.07
computeProposerIndex 100000 validators 1.7404 ms/op 1.8039 ms/op 0.96
naiveGetNextSyncCommitteeIndices 1000 validators 8.9388 s/op 10.079 s/op 0.89
getNextSyncCommitteeIndices 1000 validators 131.53 ms/op 172.71 ms/op 0.76
naiveGetNextSyncCommitteeIndices 10000 validators 10.103 s/op 12.085 s/op 0.84
getNextSyncCommitteeIndices 10000 validators 221.21 ms/op 355.14 ms/op 0.62
naiveGetNextSyncCommitteeIndices 100000 validators 9.5869 s/op 11.982 s/op 0.80
getNextSyncCommitteeIndices 100000 validators 157.99 ms/op 206.37 ms/op 0.77
naive computeShuffledIndex 100000 validators 30.366 s/op 36.909 s/op 0.82
cached computeShuffledIndex 100000 validators 580.61 ms/op 700.08 ms/op 0.83
naive computeShuffledIndex 2000000 validators 481.47 s/op 773.51 s/op 0.62
cached computeShuffledIndex 2000000 validators 29.889 s/op 62.927 s/op 0.47
computeProposers - vc 250000 597.71 us/op 653.47 us/op 0.91
computeEpochShuffling - vc 250000 40.570 ms/op 44.837 ms/op 0.90
getNextSyncCommittee - vc 250000 10.134 ms/op 12.381 ms/op 0.82
computeSigningRoot for AttestationData 22.317 us/op 29.541 us/op 0.76
hash AttestationData serialized data then Buffer.toString(base64) 1.5711 us/op 1.7536 us/op 0.90
toHexString serialized data 1.2834 us/op 1.4320 us/op 0.90
Buffer.toString(base64) 134.38 ns/op 150.48 ns/op 0.89
nodejs block root to RootHex using toHex 136.41 ns/op 148.37 ns/op 0.92
nodejs block root to RootHex using toRootHex 85.067 ns/op 87.612 ns/op 0.97
browser block root to RootHex using the deprecated toHexString 213.10 ns/op 242.15 ns/op 0.88
browser block root to RootHex using toHex 169.41 ns/op 184.14 ns/op 0.92
browser block root to RootHex using toRootHex 158.22 ns/op 168.18 ns/op 0.94

by benchmarkbot/action

@nflaig
Copy link
Member

nflaig commented Oct 3, 2025

merge conflicts

@nflaig
Copy link
Member

nflaig commented Oct 3, 2025

do we really need this? I have never encountered this as an issue, so it's seems purely theoretical

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.

2 participants