Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: potential race condition between add_block and sync #4677

Merged
merged 1 commit into from
Sep 14, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions base_layer/core/src/chain_storage/blockchain_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,17 +875,11 @@ where B: BlockchainBackend
}

let new_height = block.header.height;
// Perform orphan block validation.
if let Err(e) = self.validators.orphan.validate(&block) {
warn!(
target: LOG_TARGET,
"Block #{} ({}) failed validation - {}",
&new_height,
block.hash().to_hex(),
e.to_string()
);
return Err(e.into());
}
// This is important, we ask for a write lock to disable all read access to the db. The sync process sets the
// add_block disable flag, but we can have a race condition between the two especially since the orphan
// validation can take some time during big blocks as it does Rangeproof and metadata signature validation.
// Because the sync process first acquires a read_lock then a write_lock, and the RWLock will be prioritised,
// the add_block write lock will be given out before the sync write_lock.
trace!(
target: LOG_TARGET,
"[add_block] waiting for write access to add block block #{}",
Expand All @@ -900,6 +894,21 @@ where B: BlockchainBackend
new_height,
timer.elapsed()
);
let block_hash = block.hash();
if db.contains(&DbKey::BlockHash(block_hash))? {
return Ok(BlockAddResult::BlockExists);
}
// Perform orphan block validation.
if let Err(e) = self.validators.orphan.validate(&block) {
warn!(
target: LOG_TARGET,
"Block #{} ({}) failed validation - {}",
&new_height,
block.hash().to_hex(),
e.to_string()
);
return Err(e.into());
}
let block_add_result = add_block(
&mut *db,
&self.config,
Expand Down Expand Up @@ -1390,10 +1399,6 @@ fn add_block<T: BlockchainBackend>(
difficulty_calculator: &DifficultyCalculator,
block: Arc<Block>,
) -> Result<BlockAddResult, ChainStorageError> {
let block_hash = block.hash();
if db.contains(&DbKey::BlockHash(block_hash))? {
return Ok(BlockAddResult::BlockExists);
}
handle_possible_reorg(
db,
config,
Expand Down