reth_snap_sync/common/record.rs
1//! Versioned progress records kept in the metadata table.
2//!
3//! Account coverage and storage progress each implement [`SnapRecord`], so a record written by
4//! another build version is reported instead of misread when a download resumes.
5
6use crate::SnapSyncError;
7use reth_storage_api::{MetadataProvider, MetadataWriter};
8use reth_storage_errors::provider::ProviderError;
9use serde::{de::DeserializeOwned, Serialize};
10
11/// A progress record stored as JSON under its own metadata key.
12///
13/// The serialized record carries a `version` field, checked before the rest is decoded.
14pub(crate) trait SnapRecord: Serialize + DeserializeOwned {
15 /// Metadata key the record is stored under.
16 const KEY: &'static str;
17
18 /// Encoding version this build writes.
19 const VERSION: u32;
20
21 /// Reads the record, reporting one written at another version instead of misreading it.
22 fn read(provider: &impl MetadataProvider) -> Result<Option<Self>, SnapSyncError> {
23 let Some(bytes) = provider.get_metadata(Self::KEY)? else { return Ok(None) };
24 let value: serde_json::Value =
25 serde_json::from_slice(&bytes).map_err(ProviderError::other)?;
26 let version = value.get("version").and_then(serde_json::Value::as_u64);
27 if version != Some(u64::from(Self::VERSION)) {
28 return Err(SnapSyncError::UnsupportedRecord { key: Self::KEY, version })
29 }
30 Ok(Some(serde_json::from_value(value).map_err(ProviderError::other)?))
31 }
32
33 /// Removes the record, whichever version wrote it.
34 fn clear(provider: &impl MetadataWriter) -> Result<(), SnapSyncError> {
35 provider.delete_metadata(Self::KEY)?;
36 Ok(())
37 }
38
39 /// Writes this record under its key.
40 fn write(&self, provider: &impl MetadataWriter) -> Result<(), SnapSyncError> {
41 provider
42 .write_metadata(Self::KEY, serde_json::to_vec(self).map_err(ProviderError::other)?)?;
43 Ok(())
44 }
45}