From 07b60285234aaf29ed08052b37ec00bc4b7c6516 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 22 Mar 2024 14:25:24 +0200 Subject: [PATCH] Fix sector scrubbing --- .../src/plotting.rs | 1 + .../subspace-farmer/src/single_disk_farm.rs | 107 ++++++++++-------- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/crates/subspace-farmer-components/src/plotting.rs b/crates/subspace-farmer-components/src/plotting.rs index 0ae5ef1d06..9aa588b7d6 100644 --- a/crates/subspace-farmer-components/src/plotting.rs +++ b/crates/subspace-farmer-components/src/plotting.rs @@ -460,6 +460,7 @@ where // * sector contents map // * record chunks as s-buckets // * record metadata + // * checksum { let (sector_contents_map_region, remaining_bytes) = sector_output.split_at_mut(SectorContentsMap::encoded_size(pieces_in_sector)); diff --git a/crates/subspace-farmer/src/single_disk_farm.rs b/crates/subspace-farmer/src/single_disk_farm.rs index 0362d11847..c9f3b69db3 100644 --- a/crates/subspace-farmer/src/single_disk_farm.rs +++ b/crates/subspace-farmer/src/single_disk_farm.rs @@ -55,8 +55,7 @@ use std::{fs, io, mem}; use subspace_core_primitives::crypto::kzg::Kzg; use subspace_core_primitives::crypto::{blake3_hash, Scalar}; use subspace_core_primitives::{ - Blake3Hash, HistorySize, Piece, PieceOffset, PublicKey, Record, SectorId, SectorIndex, - SegmentIndex, + Blake3Hash, HistorySize, PieceOffset, PublicKey, Record, SectorId, SectorIndex, SegmentIndex, }; use subspace_erasure_coding::ErasureCoding; use subspace_farmer_components::file_ext::FileExt; @@ -64,9 +63,7 @@ use subspace_farmer_components::file_ext::FileExt; use subspace_farmer_components::file_ext::OpenOptionsExt; use subspace_farmer_components::plotting::PlottedSector; use subspace_farmer_components::reading::ReadSectorRecordChunksMode; -use subspace_farmer_components::sector::{ - sector_size, SectorContentsMap, SectorMetadata, SectorMetadataChecksummed, -}; +use subspace_farmer_components::sector::{sector_size, SectorMetadata, SectorMetadataChecksummed}; use subspace_farmer_components::{FarmerProtocolInfo, PieceGetter, ReadAtSync}; use subspace_networking::KnownPeersManager; use subspace_proof_of_space::Table; @@ -1871,27 +1868,27 @@ impl SingleDiskFarm { plot_file }; + let sector_bytes_range = 0..(sector_size as usize - mem::size_of::()); + info!("Checking sectors and corresponding metadata"); (0..metadata_header.plotted_sector_count) .into_par_iter() .map_init( - || { - let sector_metadata_bytes = vec![0; sector_metadata_size]; - let piece = Piece::default(); - - (sector_metadata_bytes, piece) - }, - |(sector_metadata_bytes, piece), sector_index| { + || vec![0u8; Record::SIZE], + |scratch_buffer, sector_index| { let _span_guard = span.enter(); let offset = RESERVED_PLOT_METADATA + u64::from(sector_index) * sector_metadata_size as u64; - if let Err(error) = metadata_file.read_exact_at(sector_metadata_bytes, offset) { + if let Err(error) = metadata_file + .read_exact_at(&mut scratch_buffer[..sector_metadata_size], offset) + { warn!( path = %metadata_file_path.display(), %error, - %sector_index, %offset, + size = %sector_metadata_size, + %sector_index, "Failed to read sector metadata, replacing with dummy expired sector \ metadata" ); @@ -1908,7 +1905,7 @@ impl SingleDiskFarm { } let sector_metadata = match SectorMetadataChecksummed::decode( - &mut sector_metadata_bytes.as_slice(), + &mut &scratch_buffer[..sector_metadata_size], ) { Ok(sector_metadata) => sector_metadata, Err(error) => { @@ -1973,32 +1970,38 @@ impl SingleDiskFarm { } let mut hasher = blake3::Hasher::new(); - for piece_offset in 0..pieces_in_sector { - let offset = u64::from(sector_index) * sector_size - + u64::from(piece_offset) * Piece::SIZE as u64; + // Read sector bytes and compute checksum + for offset_in_sector in sector_bytes_range.clone().step_by(scratch_buffer.len()) + { + let offset = + u64::from(sector_index) * sector_size + offset_in_sector as u64; + let bytes_to_read = (offset_in_sector + scratch_buffer.len()) + .min(sector_bytes_range.end) + - offset_in_sector; + + let bytes = &mut scratch_buffer[..bytes_to_read]; - if let Err(error) = plot_file.read_exact_at(piece.as_mut(), offset) { + if let Err(error) = plot_file.read_exact_at(bytes, offset) { warn!( path = %plot_file_path.display(), %error, %sector_index, - %piece_offset, - size = %piece.len() as u64, %offset, - "Failed to read piece bytes" + size = %bytes.len() as u64, + "Failed to read sector bytes" ); continue; } - hasher.update(piece.as_ref()); + hasher.update(bytes); } let actual_checksum = *hasher.finalize().as_bytes(); let mut expected_checksum = [0; mem::size_of::()]; { - let offset = u64::from(sector_index) * sector_size - + u64::from(pieces_in_sector) * Piece::SIZE as u64; + let offset = + u64::from(sector_index) * sector_size + sector_bytes_range.end as u64; if let Err(error) = plot_file.read_exact_at(&mut expected_checksum, offset) { warn!( @@ -2006,7 +2009,8 @@ impl SingleDiskFarm { %error, %sector_index, %offset, - "Failed to read checksum bytes" + size = %expected_checksum.len() as u64, + "Failed to read sector checksum bytes" ); } } @@ -2030,42 +2034,47 @@ impl SingleDiskFarm { )?; } - *piece = Piece::default(); + scratch_buffer.fill(0); - // Write dummy pieces - let mut hasher = blake3::Hasher::new(); - for piece_offset in 0..pieces_in_sector { - let offset = u64::from(sector_index) * sector_size - + u64::from(piece_offset) * Piece::SIZE as u64; + hasher.reset(); + // Fill sector with zeroes and compute checksum + for offset_in_sector in + sector_bytes_range.clone().step_by(scratch_buffer.len()) + { + let offset = + u64::from(sector_index) * sector_size + offset_in_sector as u64; + let bytes_to_write = (offset_in_sector + scratch_buffer.len()) + .min(sector_bytes_range.end) + - offset_in_sector; + let bytes = &mut scratch_buffer[..bytes_to_write]; if !dry_run { - if let Err(error) = plot_file.write_all_at(piece.as_ref(), offset) { + if let Err(error) = plot_file.write_all_at(bytes, offset) { return Err(SingleDiskFarmScrubError::FailedToWriteBytes { file: plot_file_path.clone(), - size: piece.len() as u64, + size: scratch_buffer.len() as u64, offset, error, }); } } - hasher.update(piece.as_ref()); + hasher.update(bytes); } - - let offset = u64::from(sector_index) * sector_size - + u64::from(pieces_in_sector) * Piece::SIZE as u64; - // Write checksum - if !dry_run { - if let Err(error) = - plot_file.write_all_at(hasher.finalize().as_bytes(), offset) - { - return Err(SingleDiskFarmScrubError::FailedToWriteBytes { - file: plot_file_path.clone(), - size: hasher.finalize().as_bytes().len() as u64, - offset, - error, - }); + { + let checksum = *hasher.finalize().as_bytes(); + let offset = u64::from(sector_index) * sector_size + + sector_bytes_range.end as u64; + if !dry_run { + if let Err(error) = plot_file.write_all_at(&checksum, offset) { + return Err(SingleDiskFarmScrubError::FailedToWriteBytes { + file: plot_file_path.clone(), + size: checksum.len() as u64, + offset, + error, + }); + } } }