Skip to content

Conversation

@iovoid
Copy link
Contributor

@iovoid iovoid commented Apr 9, 2025

Motivation

Like with #2336 the goal is to avoid blocking the current task.

Description

Makes store getters not related to tries (and thus the EVM) async, and propagates the changes to users of store. They are made async by using spawn_blocking

Many instances of functional code (and_then, map) had to be replaced due to bad async support.

Closes #2424

@iovoid iovoid requested a review from a team as a code owner April 9, 2025 15:53
@github-actions
Copy link

github-actions bot commented Apr 9, 2025

Lines of code report

Total lines added: 394
Total lines removed: 3
Total lines changed: 397

Detailed view
+--------------------------------------------------------+-------+------+
| File                                                   | Lines | Diff |
+--------------------------------------------------------+-------+------+
| ethrex/cmd/ef_tests/blockchain/test_runner.rs          | 147   | +2   |
+--------------------------------------------------------+-------+------+
| ethrex/cmd/ethrex/ethrex.rs                            | 82    | +1   |
+--------------------------------------------------------+-------+------+
| ethrex/cmd/ethrex/initializers.rs                      | 340   | +2   |
+--------------------------------------------------------+-------+------+
| ethrex/cmd/ethrex/l2.rs                                | 250   | +1   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/blockchain.rs                 | 510   | +3   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/fork_choice.rs                | 142   | +1   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/mempool.rs                    | 571   | -3   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/smoke_test.rs                 | 235   | +6   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/l2/sequencer/l1_committer.rs             | 405   | +5   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/l2/sequencer/l1_watcher.rs               | 247   | +1   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/l2/sequencer/prover_server.rs            | 472   | +4   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/p2p/rlpx/connection.rs        | 535   | +2   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/p2p/rlpx/eth/transactions.rs  | 309   | +3   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/p2p/sync.rs                   | 568   | +1   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/p2p/sync/trie_rebuild.rs      | 244   | +2   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/p2p/sync_manager.rs           | 129   | +2   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/engine/fork_choice.rs     | 390   | +14  |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/engine/payload.rs         | 683   | +2   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/eth/account.rs            | 233   | +12  |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/eth/block.rs              | 356   | +4   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/eth/fee_market.rs         | 234   | +2   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/eth/filter.rs             | 605   | +3   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/eth/logs.rs               | 177   | +4   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/eth/transaction.rs        | 602   | +17  |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/l2/transaction.rs         | 216   | +5   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/networking/rpc/types/block_identifier.rs | 140   | +8   |
+--------------------------------------------------------+-------+------+
| ethrex/crates/storage/api.rs                           | 251   | +20  |
+--------------------------------------------------------+-------+------+
| ethrex/crates/storage/store.rs                         | 1248  | +29  |
+--------------------------------------------------------+-------+------+
| ethrex/crates/storage/store_db/in_memory.rs            | 609   | +37  |
+--------------------------------------------------------+-------+------+
| ethrex/crates/storage/store_db/libmdbx.rs              | 1366  | +87  |
+--------------------------------------------------------+-------+------+
| ethrex/crates/storage/store_db/redb.rs                 | 1218  | +114 |
+--------------------------------------------------------+-------+------+

@Arkenan Arkenan added the performance Block execution throughput and performance in general label Apr 11, 2025
Copy link
Collaborator

@mpaulucci mpaulucci left a comment

Choose a reason for hiding this comment

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

LGTM

InvalidForkChoice::NewHeadAlreadyCanonical => {
ForkChoiceResponse::from(PayloadStatus::valid_with_hash(
latest_canonical_block_hash(&context.storage).unwrap(),
latest_canonical_block_hash(&context.storage).await.unwrap(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this function returns a result, let's leverage this PR to remove this unwrap

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

Comment on lines +412 to +415
let mut bodies = Vec::new();
for hash in self.hashes.iter() {
bodies.push(context.storage.get_block_body_by_hash(*hash).await?)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It might make sense to do a single request to the DB for the bulk.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented

Comment on lines 451 to 453
for block_num in self.start..=last {
bodies.push(context.storage.get_block_body(block_num).await?)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented!

});
let latest_block_num = storage.get_latest_block_number().await?;
// Box needed to keep the future Sync
// https://github.com/rust-lang/rust/issues/128095
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not very clear to me why we need to use box. There is no mention to it in that github issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't have to be Box (anything that can keep the variable Sync works). The issue explains why we need to keep the variable  Sync even though it's dropped before the next await

}

fn get_receipts_for_block(&self, block_hash: &BlockHash) -> Result<Vec<Receipt>, StoreError> {
async fn get_receipts_for_block(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this async if it doesn't go through the async api?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

}

fn read_account_snapshot(&self, start: H256) -> Result<Vec<(H256, AccountState)>, StoreError> {
async fn read_account_snapshot(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, how is this async?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

}

fn get_finalized_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
async fn get_finalized_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is await missing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It wasn't missing but the function was sync. Made it async.

}

fn get_safe_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
async fn get_safe_block_number(&self) -> Result<Option<BlockNumber>, StoreError> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is await missing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It wasn't missing but the function was sync. Made it async.

@github-actions
Copy link

Benchmark Block Execution Results Comparison Against Main

Command Mean [s] Min [s] Max [s] Relative
base 182.445 ± 0.932 180.999 184.686 1.00
head 183.186 ± 1.597 180.792 185.537 1.00 ± 0.01

Copy link
Collaborator

@Arkenan Arkenan left a comment

Choose a reason for hiding this comment

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

LGTM

@iovoid iovoid added this pull request to the merge queue Apr 15, 2025
Merged via the queue into main with commit 5b5c66c Apr 15, 2025
31 checks passed
@iovoid iovoid deleted the store/async-getters branch April 15, 2025 15:23
pedrobergamini pushed a commit to pedrobergamini/ethrex that referenced this pull request Aug 24, 2025
**Motivation**

Like with lambdaclass#2336 the goal is to avoid blocking the current task.

**Description**

Makes store getters not related to tries (and thus the EVM) async, and
propagates the changes to users of store. They are made async by using
`spawn_blocking `

Many instances of functional code (`and_then`, `map`) had to be replaced
due to bad async support.

Closes lambdaclass#2424
github-merge-queue bot pushed a commit that referenced this pull request Nov 25, 2025
…5408)

**Motivation**

When we added RPC metrics for success/error rates in #5335, we found
that we were returning "Internal error" in the
`engine_getPayloadBodiesByRange` method. This was related to changes
done in #2430, which turned missing payloads into a DB error. The spec
says we should return `null`s for any missing payloads, so this deviates
from the spec.

**Description**

This PR fixes the spec deviation by changing the batch-GET methods from
the Store API to return `None` on missing values instead of failing.

Closes #5403

---------

Co-authored-by: Rodrigo Oliveri <[email protected]>
LeanSerra pushed a commit that referenced this pull request Nov 26, 2025
…5408)

**Motivation**

When we added RPC metrics for success/error rates in #5335, we found
that we were returning "Internal error" in the
`engine_getPayloadBodiesByRange` method. This was related to changes
done in #2430, which turned missing payloads into a DB error. The spec
says we should return `null`s for any missing payloads, so this deviates
from the spec.

**Description**

This PR fixes the spec deviation by changing the batch-GET methods from
the Store API to return `None` on missing values instead of failing.

Closes #5403

---------

Co-authored-by: Rodrigo Oliveri <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Block execution throughput and performance in general

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make all store getter functions async

6 participants