mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 16:51:03 +00:00
Validate chunks from disk in availability-recovery (#6078)
* Don't use corrupted chunks from disk. Otherwise we would be going to dispute the candidate and get slashed. * Add tests
This commit is contained in:
@@ -376,49 +376,20 @@ impl RequestChunksFromValidators {
|
||||
self.total_received_responses += 1;
|
||||
|
||||
match request_result {
|
||||
Ok(Some(chunk)) => {
|
||||
// Check merkle proofs of any received chunks.
|
||||
|
||||
let validator_index = chunk.index;
|
||||
|
||||
if let Ok(anticipated_hash) =
|
||||
branch_hash(¶ms.erasure_root, chunk.proof(), chunk.index.0 as usize)
|
||||
{
|
||||
let erasure_chunk_hash = BlakeTwo256::hash(&chunk.chunk);
|
||||
|
||||
if erasure_chunk_hash != anticipated_hash {
|
||||
metrics.on_chunk_request_invalid();
|
||||
self.error_count += 1;
|
||||
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
candidate_hash = ?params.candidate_hash,
|
||||
?validator_index,
|
||||
"Merkle proof mismatch",
|
||||
);
|
||||
} else {
|
||||
metrics.on_chunk_request_succeeded();
|
||||
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
candidate_hash = ?params.candidate_hash,
|
||||
?validator_index,
|
||||
"Received valid chunk.",
|
||||
);
|
||||
self.received_chunks.insert(validator_index, chunk);
|
||||
}
|
||||
Ok(Some(chunk)) =>
|
||||
if is_chunk_valid(params, &chunk) {
|
||||
metrics.on_chunk_request_succeeded();
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
candidate_hash = ?params.candidate_hash,
|
||||
validator_index = ?chunk.index,
|
||||
"Received valid chunk",
|
||||
);
|
||||
self.received_chunks.insert(chunk.index, chunk);
|
||||
} else {
|
||||
metrics.on_chunk_request_invalid();
|
||||
self.error_count += 1;
|
||||
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
candidate_hash = ?params.candidate_hash,
|
||||
?validator_index,
|
||||
"Invalid Merkle proof",
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
Ok(None) => {
|
||||
metrics.on_chunk_request_no_such_chunk();
|
||||
self.error_count += 1;
|
||||
@@ -507,7 +478,20 @@ impl RequestChunksFromValidators {
|
||||
self.shuffling.retain(|i| !chunk_indices.contains(i));
|
||||
|
||||
for chunk in chunks {
|
||||
self.received_chunks.insert(chunk.index, chunk);
|
||||
if is_chunk_valid(params, &chunk) {
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
candidate_hash = ?params.candidate_hash,
|
||||
validator_index = ?chunk.index,
|
||||
"Found valid chunk on disk"
|
||||
);
|
||||
self.received_chunks.insert(chunk.index, chunk);
|
||||
} else {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
"Loaded invalid chunk from disk! Disk/Db corruption _very_ likely - please fix ASAP!"
|
||||
);
|
||||
};
|
||||
}
|
||||
},
|
||||
Err(oneshot::Canceled) => {
|
||||
@@ -609,6 +593,35 @@ const fn is_unavailable(
|
||||
received_chunks + requesting_chunks + unrequested_validators < threshold
|
||||
}
|
||||
|
||||
/// Check validity of a chunk.
|
||||
fn is_chunk_valid(params: &RecoveryParams, chunk: &ErasureChunk) -> bool {
|
||||
let anticipated_hash =
|
||||
match branch_hash(¶ms.erasure_root, chunk.proof(), chunk.index.0 as usize) {
|
||||
Ok(hash) => hash,
|
||||
Err(e) => {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
candidate_hash = ?params.candidate_hash,
|
||||
validator_index = ?chunk.index,
|
||||
error = ?e,
|
||||
"Invalid Merkle proof",
|
||||
);
|
||||
return false
|
||||
},
|
||||
};
|
||||
let erasure_chunk_hash = BlakeTwo256::hash(&chunk.chunk);
|
||||
if anticipated_hash != erasure_chunk_hash {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
candidate_hash = ?params.candidate_hash,
|
||||
validator_index = ?chunk.index,
|
||||
"Merkle proof mismatch"
|
||||
);
|
||||
return false
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Re-encode the data into erasure chunks in order to verify
|
||||
/// the root hash of the provided Merkle tree, which is built
|
||||
/// on-top of the encoded chunks.
|
||||
|
||||
Reference in New Issue
Block a user