mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
Another check to prevent duplicate block imports (#8050)
Attempt to address performance issues caused by importing the same block multiple times. - Check fork choice "after" obtaining the fork choice write lock in `BeaconChain::import_block`. We actually use an upgradable read lock, but this is semantically equivalent (the upgradable read has the advantage of not excluding regular reads). The hope is that this change has several benefits: 1. By preventing duplicate block imports we save time repeating work inside `import_block` that is unnecessary, e.g. writing the state to disk. Although the store itself now takes some measures to avoid re-writing diffs, it is even better if we avoid a disk write entirely. 2. By returning `DuplicateFullyImported`, we reduce some duplicated work downstream. E.g. if multiple threads importing columns trigger `import_block`, now only _one_ of them will get a notification of the block import completing successfully, and only this one will run `recompute_head`. This should help avoid a situation where multiple beacon processor workers are consumed by threads blocking on the `recompute_head_lock`. However, a similar block-fest is still possible with the upgradable fork choice lock (a large number of threads can be blocked waiting for the first thread to complete block import). Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
@@ -1730,6 +1730,8 @@ async fn add_altair_block_to_base_chain() {
|
||||
));
|
||||
}
|
||||
|
||||
// This is a regression test for this bug:
|
||||
// https://github.com/sigp/lighthouse/issues/4332#issuecomment-1565092279
|
||||
#[tokio::test]
|
||||
async fn import_duplicate_block_unrealized_justification() {
|
||||
let spec = MainnetEthSpec::default_spec();
|
||||
@@ -1791,7 +1793,7 @@ async fn import_duplicate_block_unrealized_justification() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Unrealized justification should NOT have updated.
|
||||
// The store's global unrealized justification should update immediately and match the block.
|
||||
let unrealized_justification = {
|
||||
let fc = chain.canonical_head.fork_choice_read_lock();
|
||||
assert_eq!(fc.justified_checkpoint().epoch, 0);
|
||||
@@ -1808,9 +1810,12 @@ async fn import_duplicate_block_unrealized_justification() {
|
||||
};
|
||||
|
||||
// Import the second verified block, simulating a block processed via RPC.
|
||||
import_execution_pending_block(chain.clone(), verified_block2)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
import_execution_pending_block(chain.clone(), verified_block2)
|
||||
.await
|
||||
.unwrap_err(),
|
||||
format!("DuplicateFullyImported({block_root})")
|
||||
);
|
||||
|
||||
// Unrealized justification should still be updated.
|
||||
let fc3 = chain.canonical_head.fork_choice_read_lock();
|
||||
|
||||
Reference in New Issue
Block a user