Skip to content

Commit 65a718a

Browse files
committed
feat(common): add utxo-hd in-memory ledger state snaspshot support
1 parent 5b0e487 commit 65a718a

File tree

1 file changed

+203
-7
lines changed

1 file changed

+203
-7
lines changed

mithril-common/src/digesters/ledger_state_snapshot.rs

Lines changed: 203 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ fn find_ledger_dir(path_to_walk: &Path) -> Option<PathBuf> {
1919
.map(|e| e.into_path())
2020
}
2121

22+
fn is_ledger_state_snapshot(path: &Path) -> bool {
23+
if path.is_dir() {
24+
path.join(LedgerStateSnapshot::IN_MEMORY_META).exists()
25+
&& path.join(LedgerStateSnapshot::IN_MEMORY_STATE).exists()
26+
&& path.join(LedgerStateSnapshot::IN_MEMORY_TABLES).exists()
27+
&& path
28+
.join(LedgerStateSnapshot::IN_MEMORY_TABLES)
29+
.join(LedgerStateSnapshot::IN_MEMORY_TVAR)
30+
.exists()
31+
} else {
32+
path.is_file()
33+
}
34+
}
35+
2236
/// Represent an ledger file in a Cardano node database directory
2337
#[derive(Debug, PartialEq, Eq, Clone)]
2438
pub enum LedgerStateSnapshot {
@@ -31,6 +45,15 @@ pub enum LedgerStateSnapshot {
3145
/// The filename
3246
filename: OsString,
3347
},
48+
/// Snapshot of an UTxO-HD in-memory ledger state
49+
InMemory {
50+
/// The path to the ledger file
51+
path: PathBuf,
52+
/// The ledger file slot number
53+
slot_number: SlotNumber,
54+
/// Name of the ledger state folder
55+
folder_name: OsString,
56+
},
3457
}
3558

3659
/// [LedgerStateSnapshot::list_all_in_dir] related errors.
@@ -42,6 +65,15 @@ pub enum LedgerStateSnapshotListingError {
4265
}
4366

4467
impl LedgerStateSnapshot {
68+
/// Filename of the in-memory ledger snapshot 'meta' file
69+
pub const IN_MEMORY_META: &'static str = "meta";
70+
/// Filename of the in-memory ledger snapshot 'state' file
71+
pub const IN_MEMORY_STATE: &'static str = "state";
72+
/// Directory name of the in-memory ledger snapshot 'tables' folder
73+
pub const IN_MEMORY_TABLES: &'static str = "tables";
74+
/// Filename of the in-memory ledger snapshot 'tables/tvar' file
75+
pub const IN_MEMORY_TVAR: &'static str = "tvar";
76+
4577
/// `LedgerStateSnapshot::Legacy` factory
4678
pub fn legacy(path: PathBuf, slot_number: SlotNumber, filename: OsString) -> Self {
4779
Self::Legacy {
@@ -51,6 +83,15 @@ impl LedgerStateSnapshot {
5183
}
5284
}
5385

86+
/// `LedgerStateSnapshot::InMemory` factory
87+
pub fn in_memory(path: PathBuf, slot_number: SlotNumber, folder_name: OsString) -> Self {
88+
Self::InMemory {
89+
path,
90+
slot_number,
91+
folder_name,
92+
}
93+
}
94+
5495
/// Convert a path to a [LedgerStateSnapshot] if it satisfies the constraints.
5596
///
5697
/// The constraints are:
@@ -62,11 +103,19 @@ impl LedgerStateSnapshot {
62103
.to_string_lossy()
63104
.parse::<u64>()
64105
.map(|number| {
65-
Self::legacy(
66-
path.to_path_buf(),
67-
SlotNumber(number),
68-
filename.to_os_string(),
69-
)
106+
if path.is_dir() {
107+
Self::in_memory(
108+
path.to_path_buf(),
109+
SlotNumber(number),
110+
filename.to_os_string(),
111+
)
112+
} else {
113+
Self::legacy(
114+
path.to_path_buf(),
115+
SlotNumber(number),
116+
filename.to_os_string(),
117+
)
118+
}
70119
})
71120
.ok()
72121
})
@@ -85,7 +134,7 @@ impl LedgerStateSnapshot {
85134
.min_depth(1)
86135
.max_depth(1)
87136
.into_iter()
88-
.filter_entry(|e| e.file_type().is_file())
137+
.filter_entry(|e| is_ledger_state_snapshot(e.path()))
89138
.filter_map(|file| file.ok())
90139
{
91140
if let Some(ledger_file) = LedgerStateSnapshot::from_path(path.path()) {
@@ -103,13 +152,23 @@ impl LedgerStateSnapshot {
103152
pub fn get_files_relative_path(&self) -> Vec<PathBuf> {
104153
match self {
105154
LedgerStateSnapshot::Legacy { filename, .. } => vec![PathBuf::from(filename)],
155+
LedgerStateSnapshot::InMemory { folder_name, .. } => {
156+
vec![
157+
PathBuf::from(folder_name).join(Self::IN_MEMORY_META),
158+
PathBuf::from(folder_name).join(Self::IN_MEMORY_STATE),
159+
PathBuf::from(folder_name)
160+
.join(Self::IN_MEMORY_TABLES)
161+
.join(Self::IN_MEMORY_TVAR),
162+
]
163+
}
106164
}
107165
}
108166

109167
/// Return the slot number when this snapshot was taken
110168
pub fn slot_number(&self) -> SlotNumber {
111169
match self {
112-
LedgerStateSnapshot::Legacy { slot_number, .. } => *slot_number,
170+
LedgerStateSnapshot::Legacy { slot_number, .. }
171+
| LedgerStateSnapshot::InMemory { slot_number, .. } => *slot_number,
113172
}
114173
}
115174
}
@@ -205,4 +264,141 @@ mod tests {
205264
assert_eq!(vec!["123", "124"], extract_filenames(&ledger_files));
206265
}
207266
}
267+
268+
// UTxO-HD in-memory rules:
269+
// - a folder named after the slot number at which the snapshots are taken (same naming convention as
270+
// legacy state snapshot)
271+
// - contains three files, with one in a subfolder:
272+
// - "/meta"
273+
// - "/state"
274+
// - "/tables/tvar"
275+
mod utxo_hd_in_memory_ledger_state {
276+
use std::fs::create_dir_all;
277+
278+
use super::*;
279+
280+
#[test]
281+
fn list_all_ledger_state_should_not_include_utxo_hd_folder_that_does_not_contains_meta_state_or_tvar_files(
282+
) {
283+
let target_dir = temp_dir_create!();
284+
let ledger_dir = create_ledger_dir(&target_dir);
285+
286+
let ledger_empty_dir = ledger_dir.join("000");
287+
create_dir(&ledger_empty_dir).unwrap();
288+
289+
let ledger_with_missing_meta_files = ledger_dir.join("100");
290+
create_dir_all(
291+
ledger_with_missing_meta_files.join(LedgerStateSnapshot::IN_MEMORY_TABLES),
292+
)
293+
.unwrap();
294+
create_fake_files(
295+
&ledger_with_missing_meta_files,
296+
&[LedgerStateSnapshot::IN_MEMORY_STATE],
297+
);
298+
create_fake_files(
299+
&ledger_with_missing_meta_files.join(LedgerStateSnapshot::IN_MEMORY_TABLES),
300+
&[LedgerStateSnapshot::IN_MEMORY_TVAR],
301+
);
302+
303+
let ledger_with_missing_state_files = ledger_dir.join("200");
304+
create_dir_all(
305+
ledger_with_missing_state_files.join(LedgerStateSnapshot::IN_MEMORY_TABLES),
306+
)
307+
.unwrap();
308+
create_fake_files(
309+
&ledger_with_missing_state_files,
310+
&[LedgerStateSnapshot::IN_MEMORY_META],
311+
);
312+
create_fake_files(
313+
&ledger_with_missing_meta_files.join(LedgerStateSnapshot::IN_MEMORY_TABLES),
314+
&[LedgerStateSnapshot::IN_MEMORY_TVAR],
315+
);
316+
317+
let ledger_with_missing_tvar_files = ledger_dir.join("300");
318+
create_dir_all(
319+
ledger_with_missing_tvar_files.join(LedgerStateSnapshot::IN_MEMORY_TABLES),
320+
)
321+
.unwrap();
322+
create_fake_files(
323+
&ledger_with_missing_tvar_files,
324+
&[
325+
LedgerStateSnapshot::IN_MEMORY_STATE,
326+
LedgerStateSnapshot::IN_MEMORY_META,
327+
],
328+
);
329+
330+
let ledger_with_missing_table_folder = ledger_dir.join("400");
331+
create_dir(&ledger_with_missing_table_folder).unwrap();
332+
create_fake_files(
333+
&ledger_with_missing_table_folder,
334+
&[
335+
LedgerStateSnapshot::IN_MEMORY_STATE,
336+
LedgerStateSnapshot::IN_MEMORY_META,
337+
],
338+
);
339+
340+
let result = LedgerStateSnapshot::list_all_in_dir(&target_dir).unwrap();
341+
342+
assert_eq!(Vec::<LedgerStateSnapshot>::new(), result);
343+
}
344+
345+
#[test]
346+
fn list_all_ledger_state_with_valid_utxo_hd_folder_structure() {
347+
let target_dir = temp_dir_create!();
348+
let ledger_dir = create_ledger_dir(&target_dir);
349+
350+
let ledger_state = ledger_dir.join("200");
351+
create_dir_all(ledger_state.join(LedgerStateSnapshot::IN_MEMORY_TABLES)).unwrap();
352+
create_fake_files(
353+
&ledger_state,
354+
&[
355+
LedgerStateSnapshot::IN_MEMORY_META,
356+
LedgerStateSnapshot::IN_MEMORY_STATE,
357+
],
358+
);
359+
create_fake_files(
360+
&ledger_state.join(LedgerStateSnapshot::IN_MEMORY_TABLES),
361+
&[LedgerStateSnapshot::IN_MEMORY_TVAR],
362+
);
363+
364+
let result = LedgerStateSnapshot::list_all_in_dir(&target_dir).unwrap();
365+
366+
assert_eq!(
367+
vec![LedgerStateSnapshot::in_memory(
368+
ledger_state,
369+
SlotNumber(200),
370+
"200".into()
371+
)],
372+
result
373+
);
374+
}
375+
376+
#[test]
377+
fn get_relative_path_only_list_meta_state_and_tvar_files_even_if_there_are_other_files_in_the_folder(
378+
) {
379+
let target_dir = temp_dir_create!();
380+
create_dir_all(
381+
target_dir
382+
.join("050")
383+
.join(LedgerStateSnapshot::IN_MEMORY_TABLES),
384+
)
385+
.unwrap();
386+
let ledger_state = LedgerStateSnapshot::in_memory(
387+
target_dir.join("050"),
388+
SlotNumber(50),
389+
"050".into(),
390+
);
391+
392+
assert_eq!(
393+
vec![
394+
PathBuf::from("050").join(LedgerStateSnapshot::IN_MEMORY_META),
395+
PathBuf::from("050").join(LedgerStateSnapshot::IN_MEMORY_STATE),
396+
PathBuf::from("050")
397+
.join(LedgerStateSnapshot::IN_MEMORY_TABLES)
398+
.join(LedgerStateSnapshot::IN_MEMORY_TVAR)
399+
],
400+
ledger_state.get_files_relative_path(),
401+
)
402+
}
403+
}
208404
}

0 commit comments

Comments
 (0)