Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Create immutable builder for incremental Cardano DB #2223

Merged
merged 23 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fba790a
test: verify snapshot overwrite an already existing archive
dlachaume Jan 7, 2025
a020d61
feat: create immutable files archives
dlachaume Jan 6, 2025
8d7771c
Allow to define in test the temp_dir for Snapshotter verification
sfauvel Jan 8, 2025
3d88125
Stabilizing tests using Snapshotter
sfauvel Jan 9, 2025
3ba9198
Implement upload of archives in `ImmutableArtifactBuilder`
sfauvel Jan 9, 2025
e49823c
Finalize `upload` to call archive creation and archive upload
sfauvel Jan 9, 2025
178db9d
`ImmutableArtifactBuilder` calls uploaders for all immutable archives
sfauvel Jan 10, 2025
f60f6bc
feat: implement `ImmutableFilesUploader` and `extract_immutable_file_…
sfauvel Jan 10, 2025
346af56
refactor: fix clippy warning in snapshotter
dlachaume Jan 13, 2025
791fd1b
refactor: move `MultiFilesUri` to `cardano_database` in common
dlachaume Jan 14, 2025
4a895a9
feature: plugs `immutable_builder` to the `CardanoDatabaseArtifactBui…
sfauvel Jan 14, 2025
891bcd7
Create a `DigestArtifactBuilder`
sfauvel Jan 14, 2025
a6d9a43
feature: Plugs `DigestFileUploader` to the `CardanoDatabaseArtifactBu…
sfauvel Jan 14, 2025
a5104b8
fix: remove clippy warning
sfauvel Jan 15, 2025
5f26b62
refactor: Rework `DigestArtifactBuilder` design
sfauvel Jan 15, 2025
b06a0fe
feature: Create digest file to upload
sfauvel Jan 16, 2025
68b4760
refacto: Create temporary digests file in the folder given to the `Di…
sfauvel Jan 16, 2025
caa92fd
refacto: Take PR comments into account
sfauvel Jan 16, 2025
9cac703
refacto: Create a `file_uri` module containing `FileUri`, `TemplateUr…
sfauvel Jan 16, 2025
d245e2a
refacto: Rename some functions
sfauvel Jan 17, 2025
24732a5
fix: resolve inconsistency in `openapi.yaml` examples
dlachaume Jan 17, 2025
e1303a0
chore: reference the features in the CHANGELOG
dlachaume Jan 17, 2025
1b1913b
chore: upgrade crate versions and `openapi.yaml` version
dlachaume Jan 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ As a minor extension, we have adopted a slightly different versioning convention
- Implement the artifact routes of the aggregator for the signed entity type `CardanoDatabase`.
- Implement the immutable file digests route in the aggregator.
- Implement the artifact ancillary builder in the aggregator.
- Implement the artifact immutable builder in the aggregator.
- Implement the artifact digest builder in the aggregator.

- Crates versions:

Expand Down
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion mithril-aggregator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-aggregator"
version = "0.6.12"
version = "0.6.13"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand Down Expand Up @@ -35,6 +35,7 @@ openssl-probe = { version = "0.1.5", optional = true }
paste = "1.0.15"
prometheus = "0.13.4"
rayon = "1.10.0"
regex = "1.11.1"
reqwest = { version = "0.12.12", features = ["json"] }
semver = "1.0.24"
serde = { version = "1.0.217", features = ["derive"] }
Expand Down
122 changes: 98 additions & 24 deletions mithril-aggregator/src/artifact_builder/cardano_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ use mithril_common::{

use crate::artifact_builder::{AncillaryArtifactBuilder, ArtifactBuilder};

use super::{DigestArtifactBuilder, ImmutableArtifactBuilder};

pub struct CardanoDatabaseArtifactBuilder {
db_directory: PathBuf,
cardano_node_version: Version,
compression_algorithm: CompressionAlgorithm,
ancillary_builder: Arc<AncillaryArtifactBuilder>,
immutable_builder: Arc<ImmutableArtifactBuilder>,
digest_builder: Arc<DigestArtifactBuilder>,
}

impl CardanoDatabaseArtifactBuilder {
Expand All @@ -30,12 +34,16 @@ impl CardanoDatabaseArtifactBuilder {
cardano_node_version: &Version,
compression_algorithm: CompressionAlgorithm,
ancillary_builder: Arc<AncillaryArtifactBuilder>,
immutable_builder: Arc<ImmutableArtifactBuilder>,
digest_builder: Arc<DigestArtifactBuilder>,
) -> Self {
Self {
db_directory,
cardano_node_version: cardano_node_version.clone(),
compression_algorithm,
ancillary_builder,
immutable_builder,
digest_builder,
}
}
}
Expand All @@ -62,11 +70,16 @@ impl ArtifactBuilder<CardanoDbBeacon, CardanoDatabaseSnapshot> for CardanoDataba
let total_db_size_uncompressed = compute_uncompressed_database_size(&self.db_directory)?;

let ancillary_locations = self.ancillary_builder.upload(&beacon).await?;
let immutables_locations = self
.immutable_builder
.upload(beacon.immutable_file_number)
.await?;
let digest_locations = self.digest_builder.upload().await?;

let locations = ArtifactsLocations {
ancillary: ancillary_locations,
digests: vec![],
immutables: vec![],
digests: digest_locations,
immutables: immutables_locations,
};

let cardano_database = CardanoDatabaseSnapshot::new(
Expand Down Expand Up @@ -109,17 +122,24 @@ fn compute_uncompressed_database_size(path: &Path) -> StdResult<u64> {

#[cfg(test)]
mod tests {
use std::path::PathBuf;
use std::{collections::BTreeMap, path::PathBuf};

use mithril_common::{
digesters::DummyCardanoDbBuilder,
entities::{AncillaryLocation, ProtocolMessage, ProtocolMessagePartKey},
entities::{
AncillaryLocation, DigestLocation, ImmutablesLocation, MultiFilesUri, ProtocolMessage,
ProtocolMessagePartKey, TemplateUri,
},
test_utils::{fake_data, TempDir},
CardanoNetwork,
};
use reqwest::Url;

use crate::{
artifact_builder::MockAncillaryFileUploader, test_tools::TestLogger, DumbSnapshotter,
artifact_builder::{MockAncillaryFileUploader, MockImmutableFilesUploader},
immutable_file_digest_mapper::MockImmutableFileDigestMapper,
test_tools::TestLogger,
DumbSnapshotter,
};

use super::*;
Expand Down Expand Up @@ -155,6 +175,7 @@ mod tests {
async fn should_compute_valid_artifact() {
let test_dir = get_test_directory("should_compute_valid_artifact");

let beacon = fake_data::beacon();
let immutable_trio_file_size = 777;
let ledger_file_size = 6666;
let volatile_file_size = 99;
Expand All @@ -168,29 +189,73 @@ mod tests {
.build();
let expected_total_size = immutable_trio_file_size + ledger_file_size + volatile_file_size;

let mut ancillary_uploader = MockAncillaryFileUploader::new();
ancillary_uploader.expect_upload().return_once(|_| {
Ok(AncillaryLocation::CloudStorage {
uri: "ancillary_uri".to_string(),
})
});
let ancillary_artifact_builder = {
let mut ancillary_uploader = MockAncillaryFileUploader::new();
ancillary_uploader.expect_upload().return_once(|_| {
Ok(AncillaryLocation::CloudStorage {
uri: "ancillary_uri".to_string(),
})
});

AncillaryArtifactBuilder::new(
vec![Arc::new(ancillary_uploader)],
Arc::new(DumbSnapshotter::new()),
CardanoNetwork::DevNet(123),
CompressionAlgorithm::Gzip,
TestLogger::stdout(),
)
.unwrap()
};

let immutable_artifact_builder = {
let number_of_immutable_file_loaded = fake_data::beacon().immutable_file_number;
let mut immutable_uploader = MockImmutableFilesUploader::new();
immutable_uploader
.expect_batch_upload()
.withf(move |paths| paths.len() == number_of_immutable_file_loaded as usize)
.return_once(|_| {
Ok(ImmutablesLocation::CloudStorage {
uri: MultiFilesUri::Template(TemplateUri(
"immutable_template_uri".to_string(),
)),
})
});

ImmutableArtifactBuilder::new(
vec![Arc::new(immutable_uploader)],
Arc::new(DumbSnapshotter::new()),
CompressionAlgorithm::Gzip,
TestLogger::stdout(),
)
.unwrap()
};

let digest_artifact_builder = {
let mut immutable_file_digest_mapper = MockImmutableFileDigestMapper::new();

immutable_file_digest_mapper
.expect_get_immutable_file_digest_map()
.returning(|| Ok(BTreeMap::new()));

DigestArtifactBuilder::new(
Url::parse("http://aggregator_uri").unwrap(),
vec![],
test_dir.join("digests"),
Arc::new(immutable_file_digest_mapper),
TestLogger::stdout(),
)
.unwrap()
};

let cardano_database_artifact_builder = CardanoDatabaseArtifactBuilder::new(
test_dir,
&Version::parse("1.0.0").unwrap(),
CompressionAlgorithm::Zstandard,
Arc::new(
AncillaryArtifactBuilder::new(
vec![Arc::new(ancillary_uploader)],
Arc::new(DumbSnapshotter::new()),
CardanoNetwork::DevNet(123),
CompressionAlgorithm::Gzip,
TestLogger::stdout(),
)
.unwrap(),
),
Arc::new(ancillary_artifact_builder),
Arc::new(immutable_artifact_builder),
Arc::new(digest_artifact_builder),
);

let beacon = fake_data::beacon();
let certificate_with_merkle_root = {
let mut protocol_message = ProtocolMessage::new();
protocol_message.set_message_part(
Expand All @@ -211,14 +276,23 @@ mod tests {
let expected_ancillary_locations = vec![AncillaryLocation::CloudStorage {
uri: "ancillary_uri".to_string(),
}];

let expected_immutables_locations = vec![ImmutablesLocation::CloudStorage {
uri: MultiFilesUri::Template(TemplateUri("immutable_template_uri".to_string())),
}];

let expected_digest_locations = vec![DigestLocation::Aggregator {
uri: "http://aggregator_uri/artifact/cardano-database/digests".to_string(),
}];

let artifact_expected = CardanoDatabaseSnapshot::new(
"merkleroot".to_string(),
beacon,
expected_total_size,
ArtifactsLocations {
ancillary: expected_ancillary_locations,
digests: vec![],
immutables: vec![],
digests: expected_digest_locations,
immutables: expected_immutables_locations,
},
CompressionAlgorithm::Zstandard,
&Version::parse("1.0.0").unwrap(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,9 @@ mod tests {

use mithril_common::{
digesters::{DummyCardanoDbBuilder, IMMUTABLE_DIR, LEDGER_DIR, VOLATILE_DIR},
test_utils::TempDir,
test_utils::{assert_equivalent, TempDir},
};
use uuid::Uuid;

use crate::{
test_tools::TestLogger, CompressedArchiveSnapshotter, DumbSnapshotter,
Expand Down Expand Up @@ -309,11 +310,11 @@ mod tests {
.await
.unwrap();

assert_eq!(
assert_equivalent(
locations,
vec![AncillaryLocation::CloudStorage {
uri: "an_uri".to_string()
}]
uri: "an_uri".to_string(),
}],
);
}

Expand All @@ -339,22 +340,22 @@ mod tests {
.await
.unwrap();

assert_eq!(
assert_equivalent(
locations,
vec![
AncillaryLocation::CloudStorage {
uri: "an_uri".to_string()
uri: "an_uri".to_string(),
},
AncillaryLocation::CloudStorage {
uri: "another_uri".to_string()
}
]
uri: "another_uri".to_string(),
},
],
);
}

#[tokio::test]
async fn create_archive_should_embed_ledger_volatile_directories_and_last_immutables() {
let test_dir = "cardano_database/create_archive";
let test_dir = "create_archive/cardano_database";
let cardano_db = DummyCardanoDbBuilder::new(test_dir)
.with_immutables(&[1, 2, 3])
.with_ledger_files(&["blocks-0.dat", "blocks-1.dat", "blocks-2.dat"])
Expand All @@ -363,15 +364,14 @@ mod tests {
std::fs::create_dir(cardano_db.get_dir().join("whatever")).unwrap();

let db_directory = cardano_db.get_dir().to_path_buf();
let snapshotter = {
CompressedArchiveSnapshotter::new(
db_directory.clone(),
db_directory.parent().unwrap().join("snapshot_dest"),
SnapshotterCompressionAlgorithm::Gzip,
TestLogger::stdout(),
)
.unwrap()
};
let mut snapshotter = CompressedArchiveSnapshotter::new(
db_directory.clone(),
db_directory.parent().unwrap().join("snapshot_dest"),
SnapshotterCompressionAlgorithm::Gzip,
TestLogger::stdout(),
)
.unwrap();
snapshotter.set_sub_temp_dir(Uuid::new_v4().to_string());

let builder = AncillaryArtifactBuilder::new(
vec![Arc::new(MockAncillaryFileUploader::new())],
Expand Down Expand Up @@ -422,15 +422,14 @@ mod tests {

#[tokio::test]
async fn upload_should_return_error_and_not_upload_when_archive_creation_fails() {
let snapshotter = {
CompressedArchiveSnapshotter::new(
PathBuf::from("directory_not_existing"),
PathBuf::from("whatever"),
SnapshotterCompressionAlgorithm::Gzip,
TestLogger::stdout(),
)
.unwrap()
};
let mut snapshotter = CompressedArchiveSnapshotter::new(
PathBuf::from("directory_not_existing"),
PathBuf::from("whatever"),
SnapshotterCompressionAlgorithm::Gzip,
TestLogger::stdout(),
)
.unwrap();
snapshotter.set_sub_temp_dir(Uuid::new_v4().to_string());

let mut uploader = MockAncillaryFileUploader::new();
uploader.expect_upload().never();
Expand Down
Loading