Skip to content

Commit ce42d51

Browse files
authored
Merge pull request #2554 from input-output-hk/dlachaume/2492/add-documentation-and-ci-tests-for-utxo-hd-ledger-state-snapshot-conversion
Feat: documentation and CI tests for UTxO-HD ledger state snapshot conversion `mithril-client` CLI command
2 parents fb5e9cb + 35a2299 commit ce42d51

File tree

8 files changed

+116
-22
lines changed

8 files changed

+116
-22
lines changed

.github/workflows/test-client.yml

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ jobs:
167167
shell: bash
168168
run: .github/workflows/scripts/verify-cardano-db-restoration.sh ./bin/cdb-download-output.txt "${{ matrix.extra_args }}"
169169

170+
- name: Ledger state snapshot conversion from InMemory to LMDB
171+
if: matrix.extra_args == '--include-ancillary'
172+
env:
173+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
174+
shell: bash
175+
working-directory: ./bin
176+
run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} --unstable tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor LMDB --cardano-network $NETWORK --commit
177+
170178
- name: Remove downloaded artifacts to free up disk space (Linux, Windows)
171179
if: runner.os != 'macOS'
172180
shell: bash
@@ -310,12 +318,29 @@ jobs:
310318
echo "CDB_SNAPSHOT_DIGEST=$(${{ steps.command.outputs.mithril_client }} --origin-tag CI cardano-db snapshot list --json | jq -r '.[0].digest')" >> $GITHUB_ENV
311319
312320
- name: Cardano Database Snapshot / download & restore latest
321+
if: matrix.extra_args != '--include-ancillary'
313322
shell: bash
314323
run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} --origin-tag CI cardano-db download $CDB_SNAPSHOT_DIGEST --download-dir /app ${{ matrix.extra_args }}
315324

316-
- name: Remove downloaded artifacts to free up disk space
325+
- name: Cardano Database Snapshot / download & restore latest and run conversion from InMemory to LMDB
326+
if: matrix.extra_args == '--include-ancillary'
327+
env:
328+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
317329
shell: bash
318-
run: rm --force /app/db/immutable/*.{chunk,primary,secondary}
330+
run: |
331+
docker run --rm \
332+
--entrypoint bash \
333+
-e NETWORK=$NETWORK \
334+
-e GENESIS_VERIFICATION_KEY=$GENESIS_VERIFICATION_KEY \
335+
-e ANCILLARY_VERIFICATION_KEY=$ANCILLARY_VERIFICATION_KEY \
336+
-e AGGREGATOR_ENDPOINT=$AGGREGATOR_ENDPOINT \
337+
-e GITHUB_TOKEN=$GITHUB_TOKEN \
338+
--name='mithril-client' \
339+
ghcr.io/input-output-hk/mithril-client:$MITHRIL_IMAGE_ID \
340+
-c "
341+
/app/bin/mithril-client --origin-tag CI cardano-db download $CDB_SNAPSHOT_DIGEST --download-dir /app --include-ancillary &&
342+
/app/bin/mithril-client --unstable tools utxo-hd snapshot-converter --db-directory /app/db --cardano-node-version latest --utxo-hd-flavor LMDB --cardano-network \$NETWORK --commit
343+
"
319344
320345
- name: Mithril Stake Distribution / list and get last hash
321346
shell: bash
@@ -454,3 +479,13 @@ jobs:
454479
run: |
455480
python3 ./.github/workflows/scripts/run-wasm-tests-browser-headless.py firefox
456481
./.github/workflows/scripts/parse-wasm-headless-tests-results.sh firefox-results.html
482+
483+
- name: Upload Results Artifacts
484+
if: failure()
485+
uses: actions/upload-artifact@v4
486+
with:
487+
name: mithril-e2e-tests-artifacts-run_${{ github.run_number }}-attempt_${{ github.run_attempt }}-run_id_${{ matrix.run_id }}
488+
path: |
489+
chrome-results.html
490+
firefox-results.html
491+
if-no-files-found: error

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/website/root/manual/develop/nodes/mithril-client.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ Commands:
223223
cardano-transaction Cardano transactions management (alias: ctx)
224224
cardano-stake-distribution Cardano stake distribution management (alias: csd)
225225
cardano-db-v2 Deprecated, use `cardano-db` instead
226+
tools [unstable] Tools commands
226227
help Print this message or the help of the given subcommand(s)
227228

228229
Options:
@@ -523,6 +524,13 @@ Here are the subcommands available:
523524
| **snapshot list** | Lists available cardano-db v2 snapshots |
524525
| **snapshot show** | Shows information about a cardano-db v2 snapshot |
525526

527+
### Tools (`unstable`)
528+
529+
| Subcommand | Performed action |
530+
| ----------- | ------------------------------------------------------------------------------------- |
531+
| **utxo-hd** | UTxO-HD related commands (e.g., converting a ledger state snapshot to another flavor) |
532+
| **help** | Prints this message or the help for the given subcommand(s) |
533+
526534
## Configuration parameters
527535

528536
The configuration parameters can be set in either of the following ways:
@@ -670,3 +678,14 @@ Deprecated, use `cardano-db download` with option `--backend v2` instead
670678
| `include_ancillary` | `--include-ancillary` | - | - | Include ancillary files in the download, if set the `ancillary_verification_key` is required in order to verify the ancillary files | `false` | - | - |
671679
| `ancillary_verification_key` | `--ancillary-verification-key` | - | `ANCILLARY_VERIFICATION_KEY` | Ancillary verification key to verify the ancillary files | - | - | - |
672680
| `allow_override` | `--allow-override` | - | - | Allow existing files in the download directory to be overridden | `false` | - | - |
681+
682+
`tools utxo-hd snapshot-converter` command:
683+
684+
| Parameter | Command line (long) | Command line (short) | Environment variable | Description | Default value | Example | Mandatory |
685+
| ---------------------- | ------------------------ | :------------------: | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -------- | :----------------: |
686+
| `db_directory` | `--db-directory` | - | - | Path to the Cardano node database directory | - | - | :heavy_check_mark: |
687+
| `cardano_node_version` | `--cardano-node-version` | - | - | Cardano node version of the Mithril signed snapshot (`latest` and `pre-release` are also supported to download the latest or pre-release distribution.) | - | `10.4.1` | :heavy_check_mark: |
688+
| `cardano_network` | `--cardano-network` | - | - | Cardano network | - | - | :heavy_check_mark: |
689+
| `utxo_hd_flavor` | `--utxo-hd-flavor` | - | - | UTxO-HD flavor to convert the ledger snapshot to (`Legacy` or `LMDB`) | - | `LMDB` | :heavy_check_mark: |
690+
| `commit` | `--commit` | - | - | Replaces the current ledger state in the `db_directory` | `false` | - | - |
691+
| `github_token` | `--github-token` | - | `GITHUB_TOKEN` | GitHub token for authenticated API calls | - | - | - |

docs/website/root/manual/getting-started/bootstrap-cardano-node.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,9 +482,38 @@ Cardano db 'a1b5e6f43521fd9c5f55e3d6bf27dc4a62f43980681cb67e28cc40582a0d1974' ha
482482
If you are using Cardano Docker image, you can restore a Cardano Node with:
483483
484484
docker run -v cardano-node-ipc:/ipc -v cardano-node-data:/data --mount type=bind,source="/home/mithril/data/testnet/a1b5e6f43521fd9c5f55e3d6bf27dc4a62f43980681cb67e28cc40582a0d1974/db",target=/data/db/ -e NETWORK=preview ghcr.io/intersectmbo/cardano-node:10.4.1
485+
486+
487+
Upgrade and replace the restored ledger state snapshot to 'LMDB' flavor by running the command:
488+
489+
mithril-client --unstable tools utxo-hd snapshot-converter --db-directory db --cardano-node-version 10.4.1 --utxo-hd-flavor LMDB --cardano-network preview --commit
490+
491+
Or to 'Legacy' flavor by running the command:
492+
493+
mithril-client --unstable tools utxo-hd snapshot-converter --db-directory db --cardano-node-version 10.4.1 --utxo-hd-flavor Legacy --cardano-network preview --commit
485494
```
486495
487-
### Step 5: Launch a Cardano node from the restored Cardano DB snapshot
496+
### Step 5 (optional): Convert the ledger state snapshot to another flavor
497+
498+
After restoring a snapshot with the `--include-ancillary` option, the ledger state is in the `InMemory` format. You can convert it to another UTxO-HD flavor (e.g., `LMDB` or `Legacy`) using the Mithril client `tools utxo-hd snapshot-converter` command.
499+
500+
To do so, run the following command with the `--unstable` flag:
501+
502+
```
503+
mithril-client --unstable tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor LMDB --cardano-network $CARDANO_NETWORK
504+
```
505+
506+
Or, to convert it to the `Legacy` flavor:
507+
508+
```
509+
mithril-client --unstable tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor Legacy --cardano-network $CARDANO_NETWORK
510+
```
511+
512+
Use the `--commit` option to replace the current ledger state with the converted snapshot.
513+
514+
You can also replace `latest` with a specific Cardano node version tag which will be used to download the corresponding Cardano node distribution and extract the `snapshot-converter` binary tool.
515+
516+
### Step 6: Launch a Cardano node from the restored Cardano DB snapshot
488517
489518
Launch an empty Cardano node and make it live in minutes!
490519

mithril-client-cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-client-cli"
3-
version = "0.12.9"
3+
version = "0.12.10"
44
description = "A Mithril Client"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-client-cli/src/commands/tools/snapshot_converter.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const GITHUB_ORGANIZATION: &str = "IntersectMBO";
1919
const GITHUB_REPOSITORY: &str = "cardano-node";
2020

2121
const LATEST_DISTRIBUTION_TAG: &str = "latest";
22-
const PRERELEASE_DISTRIBUTION_TAG: &str = "prerelease";
22+
const PRERELEASE_DISTRIBUTION_TAG: &str = "pre-release";
2323

2424
const WORK_DIR: &str = "tmp";
2525
const CARDANO_DISTRIBUTION_DIR: &str = "cardano-node-distribution";
@@ -76,7 +76,7 @@ pub struct SnapshotConverterCommand {
7676

7777
/// Cardano node version of the Mithril signed snapshot.
7878
///
79-
/// `latest` and `prerelease` are also supported to download the latest or prerelease distribution.
79+
/// `latest` and `pre-release` are also supported to download the latest or pre-release distribution.
8080
#[clap(long)]
8181
cardano_node_version: String,
8282

@@ -91,6 +91,10 @@ pub struct SnapshotConverterCommand {
9191
/// If set, the converted snapshot replaces the current ledger state in the `db_directory`.
9292
#[clap(long)]
9393
commit: bool,
94+
95+
/// GitHub token for authenticated API calls.
96+
#[clap(long, env = "GITHUB_TOKEN")]
97+
github_token: Option<String>,
9498
}
9599

96100
impl SnapshotConverterCommand {
@@ -113,7 +117,7 @@ impl SnapshotConverterCommand {
113117
)
114118
})?;
115119
let archive_path = Self::download_cardano_node_distribution(
116-
ReqwestGitHubApiClient::new()?,
120+
ReqwestGitHubApiClient::new(self.github_token.clone())?,
117121
ReqwestHttpDownloader::new()?,
118122
&self.cardano_node_version,
119123
&distribution_dir,
@@ -185,7 +189,7 @@ impl SnapshotConverterCommand {
185189
PRERELEASE_DISTRIBUTION_TAG => github_api_client
186190
.get_prerelease(GITHUB_ORGANIZATION, GITHUB_REPOSITORY)
187191
.await
188-
.with_context(|| "Failed to get prerelease")?,
192+
.with_context(|| "Failed to get pre-release")?,
189193
_ => github_api_client
190194
.get_release_by_tag(GITHUB_ORGANIZATION, GITHUB_REPOSITORY, tag)
191195
.await

mithril-client-cli/src/utils/github_release_retriever/interface.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub trait GitHubReleaseRetriever {
1919
/// Retrieves the latest release.
2020
async fn get_latest_release(&self, owner: &str, repo: &str) -> MithrilResult<GitHubRelease>;
2121

22-
/// Retrieves the prerelease.
22+
/// Retrieves the pre-release.
2323
async fn get_prerelease(&self, owner: &str, repo: &str) -> MithrilResult<GitHubRelease>;
2424

2525
/// Retrieves all available releases.

mithril-client-cli/src/utils/github_release_retriever/reqwest.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,41 @@ use super::{GitHubRelease, GitHubReleaseRetriever};
99

1010
pub struct ReqwestGitHubApiClient {
1111
client: Client,
12+
github_token: Option<String>,
1213
}
1314

1415
impl ReqwestGitHubApiClient {
15-
pub fn new() -> MithrilResult<Self> {
16+
pub fn new(github_token: Option<String>) -> MithrilResult<Self> {
1617
let client = Client::builder()
1718
.user_agent("mithril-client")
1819
.build()
1920
.context("Failed to build Reqwest GitHub API client")?;
2021

21-
Ok(Self { client })
22+
Ok(Self {
23+
client,
24+
github_token,
25+
})
2226
}
2327

2428
async fn download<U: IntoUrl, T: DeserializeOwned>(&self, source_url: U) -> MithrilResult<T> {
2529
let url = source_url
2630
.into_url()
2731
.with_context(|| "Given `source_url` is not a valid Url")?;
28-
let response = self
29-
.client
30-
.get(url.clone())
32+
let mut request = self.client.get(url.clone());
33+
if let Some(token) = &self.github_token {
34+
request = request.bearer_auth(token);
35+
}
36+
let response = request
3137
.send()
3238
.await
3339
.with_context(|| format!("Failed to send request to GitHub API: {}", url))?;
3440
match response.status() {
3541
reqwest::StatusCode::OK => {}
3642
status => {
3743
return Err(anyhow!(
38-
"GitHub API request failed with status code: {}",
39-
status
44+
"GitHub API request failed with status code '{}': {}",
45+
status,
46+
response.text().await.unwrap()
4047
));
4148
}
4249
}
@@ -84,7 +91,7 @@ impl GitHubReleaseRetriever for ReqwestGitHubApiClient {
8491
let prerelease = releases
8592
.into_iter()
8693
.find(|release| release.prerelease)
87-
.ok_or_else(|| anyhow!("No prerelease found"))?;
94+
.ok_or_else(|| anyhow!("No pre-release found"))?;
8895

8996
Ok(prerelease)
9097
}
@@ -121,7 +128,7 @@ mod tests {
121128
when.method(GET).path("/endpoint");
122129
then.status(200).body(r#"{ "key": "value" }"#);
123130
});
124-
let client = ReqwestGitHubApiClient::new().unwrap();
131+
let client = ReqwestGitHubApiClient::new(None).unwrap();
125132

126133
let result: FakeApiResponse = client
127134
.download(format!("{}/endpoint", server.base_url()))
@@ -143,7 +150,7 @@ mod tests {
143150
when.method(GET).path("/endpoint");
144151
then.status(200).body("this is not json");
145152
});
146-
let client = ReqwestGitHubApiClient::new().unwrap();
153+
let client = ReqwestGitHubApiClient::new(None).unwrap();
147154

148155
let result: MithrilResult<FakeApiResponse> = client
149156
.download(format!("{}/endpoint", server.base_url()))
@@ -157,7 +164,7 @@ mod tests {
157164

158165
#[tokio::test]
159166
async fn download_fails_on_invalid_url() {
160-
let client = ReqwestGitHubApiClient::new().unwrap();
167+
let client = ReqwestGitHubApiClient::new(None).unwrap();
161168

162169
let result: MithrilResult<FakeApiResponse> = client.download("not a valid url").await;
163170

@@ -171,7 +178,7 @@ mod tests {
171178
when.method(GET).path("/endpoint");
172179
then.status(StatusCode::INTERNAL_SERVER_ERROR.into());
173180
});
174-
let client = ReqwestGitHubApiClient::new().unwrap();
181+
let client = ReqwestGitHubApiClient::new(None).unwrap();
175182

176183
let result: MithrilResult<FakeApiResponse> = client
177184
.download(format!("{}/endpoint", server.base_url()))

0 commit comments

Comments
 (0)