Skip to content

Commit eeef9ef

Browse files
Merge branch 'alin/manifest-consistency-checks' into 'master'
improvement: Check manifest consistency during validation Ensure that manifest is internally consistent (chunks are adjacent, file size is equal to the sum of chunk sizes, no orphan chunks are present). See merge request dfinity-lab/public/ic!12608
2 parents 41c037a + 26ad585 commit eeef9ef

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

rs/state_manager/src/manifest.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ pub enum ManifestValidationError {
7878
manifest_version: StateSyncVersion,
7979
max_supported_version: StateSyncVersion,
8080
},
81+
InconsistentManifest {
82+
reason: String,
83+
},
8184
}
8285

8386
impl fmt::Display for ManifestValidationError {
@@ -111,6 +114,7 @@ impl fmt::Display for ManifestValidationError {
111114
"manifest version {} not supported, maximum supported version {}",
112115
manifest_version, max_supported_version,
113116
),
117+
Self::InconsistentManifest { reason } => write!(f, "inconsistent manifest: {}", reason),
114118
}
115119
}
116120
}
@@ -912,6 +916,16 @@ pub fn compute_manifest(
912916
);
913917
metrics.chunk_id_usage_nearing_limits_critical.inc();
914918
}
919+
920+
// Sanity check: ensure that we have produced a valid manifest.
921+
debug_assert_eq!(
922+
Ok(()),
923+
validate_manifest(
924+
&manifest,
925+
&CryptoHash(manifest_hash(&manifest).to_vec()).into()
926+
)
927+
);
928+
915929
Ok(manifest)
916930
}
917931

@@ -931,6 +945,12 @@ pub fn validate_manifest(
931945
let mut chunk_start: usize = 0;
932946

933947
for (file_index, f) in manifest.file_table.iter().enumerate() {
948+
if f.relative_path.is_absolute() {
949+
return Err(ManifestValidationError::InconsistentManifest {
950+
reason: format!("absolute file path: {},", f.relative_path.display(),),
951+
});
952+
}
953+
934954
let mut hasher = file_hasher();
935955

936956
let chunk_count: usize = manifest.chunk_table[chunk_start..]
@@ -940,10 +960,34 @@ pub fn validate_manifest(
940960

941961
(chunk_count as u32).update_hash(&mut hasher);
942962

943-
for chunk_info in manifest.chunk_table[chunk_start..chunk_start + chunk_count].iter() {
963+
let mut file_offset = 0;
964+
for i in chunk_start..chunk_start + chunk_count {
965+
let chunk_info = manifest.chunk_table.get(i).unwrap();
944966
assert_eq!(chunk_info.file_index, file_index as u32);
967+
if chunk_info.offset != file_offset {
968+
return Err(ManifestValidationError::InconsistentManifest {
969+
reason: format!(
970+
"unexpected offset for chunk {} of file {}: was {}, expected {}",
971+
i,
972+
f.relative_path.display(),
973+
chunk_info.offset,
974+
file_offset
975+
),
976+
});
977+
}
978+
file_offset += chunk_info.size_bytes as u64;
945979
write_chunk_hash(&mut hasher, chunk_info, manifest.version);
946980
}
981+
if f.size_bytes != file_offset {
982+
return Err(ManifestValidationError::InconsistentManifest {
983+
reason: format!(
984+
"mismatching file size and total chunk size for {}: {} vs {}",
985+
f.relative_path.display(),
986+
f.size_bytes,
987+
file_offset
988+
),
989+
});
990+
}
947991

948992
chunk_start += chunk_count;
949993

@@ -957,6 +1001,15 @@ pub fn validate_manifest(
9571001
});
9581002
}
9591003
}
1004+
if manifest.chunk_table.len() != chunk_start {
1005+
return Err(ManifestValidationError::InconsistentManifest {
1006+
reason: format!(
1007+
"extra chunks in manifest: actual {}, expected {}",
1008+
manifest.chunk_table.len(),
1009+
chunk_start
1010+
),
1011+
});
1012+
}
9601013

9611014
let hash = manifest_hash(manifest);
9621015

rs/state_manager/src/manifest/tests/computation.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -546,11 +546,8 @@ fn orphan_chunk_detected() {
546546
);
547547
let root_hash = CryptoHashOfState::from(CryptoHash(manifest_hash.to_vec()));
548548
match validate_manifest(&manifest, &root_hash) {
549-
Err(ManifestValidationError::InvalidRootHash { .. }) => (),
550-
other => panic!(
551-
"Expected an orphan chunk to change the root hash, got: {:?}",
552-
other
553-
),
549+
Err(ManifestValidationError::InconsistentManifest { .. }) => (),
550+
other => panic!("Expected an orphan chunk to be detected, got: {:?}", other),
554551
}
555552
}
556553
}

0 commit comments

Comments
 (0)