Skip to content

Commit 65d21a3

Browse files
committed
Promote cardano_block_scanner module to a directory
So all types defined in it can be split to several files. + rework tests so they are specialized on the part they address: either the scanner or the streamer.
1 parent bd41141 commit 65d21a3

File tree

11 files changed

+616
-574
lines changed

11 files changed

+616
-574
lines changed

mithril-common/src/cardano_block_scanner.rs

Lines changed: 0 additions & 550 deletions
This file was deleted.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use std::path::Path;
2+
3+
use async_trait::async_trait;
4+
use slog::{warn, Logger};
5+
6+
use crate::cardano_block_scanner::{BlockScanner, BlockStreamer, ImmutableBlockStreamer};
7+
use crate::digesters::ImmutableFile;
8+
use crate::entities::ImmutableFileNumber;
9+
use crate::StdResult;
10+
11+
/// Cardano block scanner
12+
pub struct CardanoBlockScanner {
13+
logger: Logger,
14+
/// When set to true, no error is returned in case of unparsable block, and an error log is written instead.
15+
/// This can occur when the crate 'pallas-hardano' doesn't support some non final encoding for a Cardano era.
16+
/// This situation should only happen on the test networks and not on the mainnet.
17+
allow_unparsable_block: bool,
18+
}
19+
20+
impl CardanoBlockScanner {
21+
/// Factory
22+
pub fn new(logger: Logger, allow_unparsable_block: bool) -> Self {
23+
if allow_unparsable_block {
24+
warn!(
25+
logger,
26+
"The 'allow_unparsable_block' option is activated. This option should only be used on test networks.")
27+
}
28+
29+
Self {
30+
logger,
31+
allow_unparsable_block,
32+
}
33+
}
34+
}
35+
36+
#[async_trait]
37+
impl BlockScanner for CardanoBlockScanner {
38+
async fn scan(
39+
&self,
40+
dirpath: &Path,
41+
from_immutable: Option<ImmutableFileNumber>,
42+
until_immutable: ImmutableFileNumber,
43+
) -> StdResult<Box<dyn BlockStreamer>> {
44+
let is_in_bounds = |number: ImmutableFileNumber| match from_immutable {
45+
Some(from) => (from..=until_immutable).contains(&number),
46+
None => number <= until_immutable,
47+
};
48+
let immutable_chunks = ImmutableFile::list_completed_in_dir(dirpath)?
49+
.into_iter()
50+
.filter(|f| is_in_bounds(f.number) && f.filename.contains("chunk"))
51+
.collect::<Vec<_>>();
52+
53+
Ok(Box::new(ImmutableBlockStreamer::new(
54+
immutable_chunks,
55+
self.allow_unparsable_block,
56+
self.logger.clone(),
57+
)))
58+
}
59+
}
60+
61+
#[cfg(test)]
62+
mod tests {
63+
use crate::test_utils::{TempDir, TestLogger};
64+
65+
use super::*;
66+
67+
fn get_number_of_immutable_chunk_in_dir(dir: &Path) -> usize {
68+
ImmutableFile::list_completed_in_dir(dir)
69+
.unwrap()
70+
.into_iter()
71+
.map(|i| i.filename.contains("chunk"))
72+
.len()
73+
}
74+
75+
#[tokio::test]
76+
async fn test_parse_from_lower_bound_until_upper_bound() {
77+
let db_path = Path::new("../mithril-test-lab/test_data/immutable/");
78+
assert!(get_number_of_immutable_chunk_in_dir(db_path) >= 3);
79+
80+
let from_immutable_file = 2;
81+
let until_immutable_file = 2;
82+
let cardano_transaction_parser = CardanoBlockScanner::new(TestLogger::stdout(), false);
83+
84+
let mut streamer = cardano_transaction_parser
85+
.scan(db_path, Some(from_immutable_file), until_immutable_file)
86+
.await
87+
.unwrap();
88+
let immutable_blocks = streamer.poll_all().await.unwrap();
89+
90+
let min_immutable = immutable_blocks
91+
.iter()
92+
.map(|b| b.immutable_file_number)
93+
.min();
94+
assert_eq!(min_immutable, Some(from_immutable_file));
95+
96+
let max_immutable = immutable_blocks
97+
.iter()
98+
.map(|b| b.immutable_file_number)
99+
.max();
100+
assert_eq!(max_immutable, Some(until_immutable_file));
101+
}
102+
103+
#[tokio::test]
104+
async fn test_parse_up_to_given_beacon() {
105+
let db_path = Path::new("../mithril-test-lab/test_data/immutable/");
106+
assert!(get_number_of_immutable_chunk_in_dir(db_path) >= 2);
107+
108+
let until_immutable_file = 1;
109+
let cardano_transaction_parser = CardanoBlockScanner::new(TestLogger::stdout(), false);
110+
111+
let mut streamer = cardano_transaction_parser
112+
.scan(db_path, None, until_immutable_file)
113+
.await
114+
.unwrap();
115+
let immutable_blocks = streamer.poll_all().await.unwrap();
116+
117+
let max_immutable = immutable_blocks
118+
.iter()
119+
.map(|b| b.immutable_file_number)
120+
.max();
121+
assert_eq!(max_immutable, Some(until_immutable_file));
122+
}
123+
124+
#[tokio::test]
125+
async fn test_instantiate_parser_with_allow_unparsable_block_should_log_warning() {
126+
let temp_dir = TempDir::create(
127+
"cardano_transaction_parser",
128+
"test_instantiate_parser_with_allow_unparsable_block_should_log_warning",
129+
);
130+
let log_path = temp_dir.join("test.log");
131+
132+
// We create a block to drop the logger and force a flush before we read the log file.
133+
{
134+
let _ = CardanoBlockScanner::new(TestLogger::file(&log_path), true);
135+
}
136+
137+
let log_file = std::fs::read_to_string(&log_path).unwrap();
138+
assert!(log_file.contains("The 'allow_unparsable_block' option is activated. This option should only be used on test networks."));
139+
}
140+
141+
#[tokio::test]
142+
async fn test_instantiate_parser_without_allow_unparsable_block_should_not_log_warning() {
143+
let temp_dir = TempDir::create(
144+
"cardano_transaction_parser",
145+
"test_instantiate_parser_without_allow_unparsable_block_should_not_log_warning",
146+
);
147+
let log_path = temp_dir.join("test.log");
148+
149+
// We create a block to drop the logger and force a flush before we read the log file.
150+
{
151+
let _ = CardanoBlockScanner::new(TestLogger::file(&log_path), false);
152+
}
153+
154+
let log_file = std::fs::read_to_string(&log_path).unwrap();
155+
assert!(!log_file.contains("The 'allow_unparsable_block' option is activated. This option should only be used on test networks."));
156+
}
157+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use std::path::Path;
2+
3+
use async_trait::async_trait;
4+
use tokio::sync::RwLock;
5+
6+
use crate::cardano_block_scanner::{BlockScanner, BlockStreamer, ScannedBlock};
7+
use crate::entities::ImmutableFileNumber;
8+
use crate::StdResult;
9+
10+
/// Dumb block scanner
11+
pub struct DumbBlockScanner {
12+
blocks: RwLock<Vec<ScannedBlock>>,
13+
}
14+
15+
impl DumbBlockScanner {
16+
/// Factory
17+
pub fn new(blocks: Vec<ScannedBlock>) -> Self {
18+
Self {
19+
blocks: RwLock::new(blocks),
20+
}
21+
}
22+
23+
/// Update blocks returned by `parse`
24+
pub async fn update_blocks(&self, new_blocks: Vec<ScannedBlock>) {
25+
let mut blocks = self.blocks.write().await;
26+
*blocks = new_blocks;
27+
}
28+
}
29+
30+
#[async_trait]
31+
impl BlockScanner for DumbBlockScanner {
32+
async fn scan(
33+
&self,
34+
_dirpath: &Path,
35+
_from_immutable: Option<ImmutableFileNumber>,
36+
_until_immutable: ImmutableFileNumber,
37+
) -> StdResult<Box<dyn BlockStreamer>> {
38+
// let iter = self.blocks.read().await.clone().into_iter();
39+
// Ok(Box::new(iter))
40+
todo!()
41+
}
42+
}

0 commit comments

Comments
 (0)