diff --git a/.github/workflows/scripts/verify-cardano-db-restoration.sh b/.github/workflows/scripts/verify-cardano-db-restoration.sh index e0f507bcd6f..ad0174a7fef 100755 --- a/.github/workflows/scripts/verify-cardano-db-restoration.sh +++ b/.github/workflows/scripts/verify-cardano-db-restoration.sh @@ -3,12 +3,12 @@ set -e if [[ $# -lt 1 ]]; then - echo "Usage: $0 --docker-cmd [docker run command string] [--include-ancillary] [--ledger-backend ]" + echo "Usage: $0 --docker-cmd [docker run command string] [--include-ancillary] [--ledger-backend ]" echo "" echo "Parameters:" - echo " --docker-cmd (Required) The 'docker run' command output in the result of a mithril-client CLI download or snapshot converter command." - echo " --include-ancillary (Optional) Does the ancillary files were included in the restoration." - echo " --ledger-backend (Optional) Specify the ledger backend. Default is 'in-memory'. Note: lmdb backend requires --include-ancillary to be set." + echo " --docker-cmd (Required) The 'docker run' command output in the result of a mithril-client CLI download or snapshot converter command." + echo " --include-ancillary (Optional) Whether the ancillary files were included in the restoration." + echo " --ledger-backend (Optional) Specify the ledger backend. Default is 'in-memory'. Note: lmdb and lsm backends require --include-ancillary to be set." exit 1 fi @@ -33,9 +33,17 @@ fi echo "Docker command:" echo "$DOCKER_CMD" -# Note: ledger conversion to lmdb can only be executed if ancillary files are included -if [[ ${LEDGER_BACKEND,,} == "lmdb" && "$INCLUDE_ANCILLARY" == "true" ]]; then - DOCKER_CMD="${DOCKER_CMD/ ghcr/" -e CARDANO_CONFIG_JSON_MERGE='{\"LedgerDB\":{\"Backend\":\"V1LMDB\"}}' ghcr"}" +# Note: ledger conversion to an on disk backend can only be executed if ancillary files are included +if [[ "$INCLUDE_ANCILLARY" == "true" ]]; then + case ${LEDGER_BACKEND,,} in + lmdb) + DOCKER_CMD="${DOCKER_CMD/ ghcr/" -e CARDANO_CONFIG_JSON_MERGE='{\"LedgerDB\":{\"Backend\":\"V1LMDB\"}}' ghcr"}" + ;; + lsm) + # The LSM backend relies on io_uring syscalls which are blocked by the default Docker seccomp profile + DOCKER_CMD="${DOCKER_CMD/ ghcr/" -e CARDANO_CONFIG_JSON_MERGE='{\"LedgerDB\":{\"Backend\":\"V2LSM\"}}' --security-opt seccomp=unconfined ghcr"}" + ;; + esac fi DOCKER_CMD_DETACHED="${DOCKER_CMD/docker run/docker run -d}" diff --git a/.github/workflows/test-client.yml b/.github/workflows/test-client.yml index 4e970b681fc..05bb03382f1 100644 --- a/.github/workflows/test-client.yml +++ b/.github/workflows/test-client.yml @@ -81,6 +81,7 @@ on: env: NETWORK: ${{ inputs.network }} AGGREGATOR_ENDPOINT: ${{ inputs.aggregator_endpoint }} + LSM_MINIMUM_CARDANO_NODE_VERSION: "11.1.0" jobs: prepare: @@ -126,7 +127,7 @@ jobs: if [[ $CARDANO_DATABASE_V2_CAPABILITY == "true" ]]; then echo 'available_cardano_database_backends=["v2"]' >> $GITHUB_OUTPUT - echo 'bin-cdb-download-matrix-include=[{"backend":"v2","os":"ubuntu-24.04","ledger_backend":"lmdb","extra_args":"--include-ancillary"}]' >> $GITHUB_OUTPUT + echo 'bin-cdb-download-matrix-include=[{"backend":"v2","os":"ubuntu-24.04","ledger_backend":"on-disk","extra_args":"--include-ancillary"}]' >> $GITHUB_OUTPUT else echo 'available_cardano_database_backends=[]' >> $GITHUB_OUTPUT echo 'bin-cdb-download-matrix-include=[]' >> $GITHUB_OUTPUT @@ -329,6 +330,23 @@ jobs: echo "hash=$(./mithril-client --origin-tag CI cardano-db snapshot list --backend ${{ matrix.backend }} --json | jq -r '.[0].hash')" >> $GITHUB_OUTPUT echo "cardano_node_version=$(./mithril-client --origin-tag CI cardano-db snapshot list --backend ${{ matrix.backend }} --json | jq -r '.[0].cardano_node_version')" >> $GITHUB_OUTPUT + - name: Resolve ledger backend + id: ledger_backend + shell: bash + run: | + LEDGER_BACKEND="${{ matrix.ledger_backend }}" + CARDANO_VERSION="${{ steps.last_snapshot.outputs.cardano_node_version }}" + if [[ "$LEDGER_BACKEND" == "on-disk" ]]; then + OLDEST_VERSION=$(printf '%s\n%s\n' "$CARDANO_VERSION" "$LSM_MINIMUM_CARDANO_NODE_VERSION" | sort -V | head -n1) + if [[ "$OLDEST_VERSION" == "$LSM_MINIMUM_CARDANO_NODE_VERSION" ]]; then + LEDGER_BACKEND="lsm" + else + LEDGER_BACKEND="lmdb" + fi + fi + + echo "name=$LEDGER_BACKEND" >> $GITHUB_OUTPUT + - name: Cardano Database Snapshot / download & restore latest shell: bash working-directory: ./bin @@ -337,19 +355,22 @@ jobs: --backend ${{ matrix.backend }} --download-dir "${{ matrix.backend }}" ${{ matrix.extra_args }} --json \ | tee cdb-${{ matrix.backend }}-download-output.json - - name: Ledger state snapshot conversion from InMemory to ${{ matrix.ledger_backend }} + - name: Ledger state snapshot conversion from InMemory to ${{ steps.ledger_backend.outputs.name }} # The 'snapshot-converter' binary is not currently supported on Linux ARM64 platforms. - if: matrix.os != 'ubuntu-24.04-arm' && matrix.extra_args == '--include-ancillary' && contains(fromJSON('["lmdb", "legacy"]'), matrix.ledger_backend) + if: matrix.os != 'ubuntu-24.04-arm' && matrix.extra_args == '--include-ancillary' && contains(fromJSON('["on-disk", "legacy"]'), matrix.ledger_backend) env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} shell: bash working-directory: ./bin run: | - LEDGER_BACKEND="${{ matrix.ledger_backend }}" + LEDGER_BACKEND="${{ steps.ledger_backend.outputs.name }}" CARDANO_VERSION="${{ steps.last_snapshot.outputs.cardano_node_version }}" - if [[ ${LEDGER_BACKEND,,} == "lmdb" ]]; then - UTXO_HD_FLAVOR="LMDB" - fi + case ${LEDGER_BACKEND,,} in + lmdb) UTXO_HD_FLAVOR="LMDB" ;; + lsm) UTXO_HD_FLAVOR="LSM" ;; + legacy) UTXO_HD_FLAVOR="Legacy" ;; + *) echo "Unsupported ledger backend: $LEDGER_BACKEND" >&2; exit 1 ;; + esac ./mithril-client ${{ needs.prepare.outputs.debug_level }} tools utxo-hd snapshot-converter --db-directory ${{ matrix.backend }}/db \ --cardano-node-version $CARDANO_VERSION --utxo-hd-flavor $UTXO_HD_FLAVOR --commit --json \ @@ -371,7 +392,7 @@ jobs: DOCKER_CMD=$(jq -r ".run_docker_cmd" ./bin/cdb-${{ matrix.backend }}-download-output.json) fi - .github/workflows/scripts/verify-cardano-db-restoration.sh --docker-cmd "$DOCKER_CMD" --ledger-backend ${{ matrix.ledger_backend }} ${{ matrix.extra_args }} + .github/workflows/scripts/verify-cardano-db-restoration.sh --docker-cmd "$DOCKER_CMD" --ledger-backend ${{ steps.ledger_backend.outputs.name }} ${{ matrix.extra_args }} - name: Cardano Database V2 Snapshot / verify tampered and missing immutables from a specific range if: matrix.backend == 'v2' @@ -552,7 +573,8 @@ jobs: run: | mkdir -p $PWD/data chmod -R a+w $PWD/data - echo "mithril_client=docker run --rm -e NETWORK=$NETWORK -e GENESIS_VERIFICATION_KEY=$GENESIS_VERIFICATION_KEY -e ANCILLARY_VERIFICATION_KEY=$ANCILLARY_VERIFICATION_KEY -e AGGREGATOR_ENDPOINT=$AGGREGATOR_ENDPOINT -e GITHUB_TOKEN=$GITHUB_TOKEN --name='mithril-client' -v $PWD/data:/app/data ghcr.io/intersectmbo/mithril-client:$MITHRIL_IMAGE_ID" >> $GITHUB_OUTPUT + # The LSM ledger conversion uses io_uring syscalls, which are blocked by the default Docker seccomp profile + echo "mithril_client=docker run --rm -e NETWORK=$NETWORK -e GENESIS_VERIFICATION_KEY=$GENESIS_VERIFICATION_KEY -e ANCILLARY_VERIFICATION_KEY=$ANCILLARY_VERIFICATION_KEY -e AGGREGATOR_ENDPOINT=$AGGREGATOR_ENDPOINT -e GITHUB_TOKEN=$GITHUB_TOKEN --name='mithril-client' --security-opt seccomp=unconfined -v $PWD/data:/app/data ghcr.io/intersectmbo/mithril-client:$MITHRIL_IMAGE_ID" >> $GITHUB_OUTPUT - name: fetch latest snapshot hash id: last_snapshot @@ -561,15 +583,27 @@ jobs: echo "hash=$(${{ steps.command.outputs.mithril_client }} --origin-tag CI cardano-db snapshot list --backend ${{ matrix.backend }} --json | jq -r '.[0].hash')" >> $GITHUB_OUTPUT echo "cardano_node_version=$(${{ steps.command.outputs.mithril_client }} --origin-tag CI cardano-db snapshot list --backend ${{ matrix.backend }} --json | jq -r '.[0].cardano_node_version')" >> $GITHUB_OUTPUT + - name: Resolve UTxO-HD flavor + id: utxo_hd_flavor + shell: bash + run: | + CARDANO_VERSION="${{ steps.last_snapshot.outputs.cardano_node_version }}" + OLDEST_VERSION=$(printf '%s\n%s\n' "$CARDANO_VERSION" "$LSM_MINIMUM_CARDANO_NODE_VERSION" | sort -V | head -n1) + if [[ "$OLDEST_VERSION" == "$LSM_MINIMUM_CARDANO_NODE_VERSION" ]]; then + echo "name=LSM" >> $GITHUB_OUTPUT + else + echo "name=LMDB" >> $GITHUB_OUTPUT + fi + - name: Cardano Database Snapshot / download & restore latest shell: bash run: | ${{ steps.command.outputs.mithril_client }} ${{ needs.prepare.outputs.debug_level }} --origin-tag CI cardano-db download ${{ steps.last_snapshot.outputs.hash }} --backend ${{ matrix.backend }} --download-dir "/app/data/${{ matrix.backend }}" ${{ matrix.extra_args }} - - name: Ledger state snapshot conversion from InMemory to LMDB + - name: Ledger state snapshot conversion from InMemory to ${{ steps.utxo_hd_flavor.outputs.name }} if: matrix.extra_args == '--include-ancillary' && matrix.backend == 'v2' shell: bash - run: ${{ steps.command.outputs.mithril_client }} ${{ needs.prepare.outputs.debug_level }} tools utxo-hd snapshot-converter --db-directory /app/data/v2/db --cardano-node-version ${{ steps.last_snapshot.outputs.cardano_node_version }} --utxo-hd-flavor LMDB --commit + run: ${{ steps.command.outputs.mithril_client }} ${{ needs.prepare.outputs.debug_level }} tools utxo-hd snapshot-converter --db-directory /app/data/v2/db --cardano-node-version ${{ steps.last_snapshot.outputs.cardano_node_version }} --utxo-hd-flavor ${{ steps.utxo_hd_flavor.outputs.name }} --commit - name: Cardano Database V2 Snapshot / verify immutables if: matrix.backend == 'v2' diff --git a/Cargo.lock b/Cargo.lock index e6026e12a93..236a9226a0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4456,7 +4456,7 @@ dependencies = [ [[package]] name = "mithril-client-cli" -version = "0.13.22" +version = "0.13.23" dependencies = [ "anyhow", "async-trait", diff --git a/docs/website/root/manual/getting-started/bootstrap-cardano-node.md b/docs/website/root/manual/getting-started/bootstrap-cardano-node.md index 5e24f601d8d..7fd45176c59 100644 --- a/docs/website/root/manual/getting-started/bootstrap-cardano-node.md +++ b/docs/website/root/manual/getting-started/bootstrap-cardano-node.md @@ -207,10 +207,12 @@ Then, create a shell function for the Mithril client: ```bash mithril_client () { - docker run --rm -e GENESIS_VERIFICATION_KEY=$GENESIS_VERIFICATION_KEY -e AGGREGATOR_ENDPOINT=$AGGREGATOR_ENDPOINT --name='mithril-client' -v $(pwd):/app/data -w /app/data -u $(id -u) ghcr.io/intersectmbo/mithril-client:$MITHRIL_IMAGE_ID $@ + docker run --rm -e GENESIS_VERIFICATION_KEY=$GENESIS_VERIFICATION_KEY -e AGGREGATOR_ENDPOINT=$AGGREGATOR_ENDPOINT --name='mithril-client' --security-opt seccomp=unconfined -v $(pwd):/app/data -w /app/data -u $(id -u) ghcr.io/intersectmbo/mithril-client:$MITHRIL_IMAGE_ID "$@" } ``` +The `--security-opt seccomp=unconfined` option is required by the `LSM` ledger state conversion, which uses io_uring syscalls blocked by the default Docker seccomp profile. + You can now use the `mithril_client` function: ```bash @@ -520,20 +522,30 @@ Upgrade and replace the restored ledger state snapshot to 'LMDB' flavor by runni ### Step 5 (optional): Convert the ledger state snapshot to another flavor -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. +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 using the Mithril client `tools utxo-hd snapshot-converter` command. + +Each flavor can only be read by a range of Cardano node versions: -To do so, run the following command: +| Flavor | Cardano node versions running the converted ledger state | +| -------- | -------------------------------------------------------- | +| `LSM` | `10.7.0` and above | +| `LMDB` | `11.0.1` and below | +| `Legacy` | `10.3.1` and below | + +To convert the ledger state to the `LSM` flavor, run the following command: ``` -mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor LMDB +mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor LSM ``` -Or, to convert it to the `Legacy` flavor: +Or, to convert it to the `LMDB` flavor, which is useful to run a Cardano node older than the one used by the aggregator: ``` -mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor Legacy +mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version 11.0.1 --utxo-hd-flavor LMDB ``` +The `LMDB` backend was dropped in Cardano node `11.1.0`. Requesting that flavor with `11.1.0` or upper fails, so pass a version able to run it. + Use the `--commit` option to replace the current ledger state with the converted snapshot. 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. diff --git a/docs/website/versioned_docs/version-maintained/manual/getting-started/bootstrap-cardano-node.md b/docs/website/versioned_docs/version-maintained/manual/getting-started/bootstrap-cardano-node.md index 5e24f601d8d..7fd45176c59 100644 --- a/docs/website/versioned_docs/version-maintained/manual/getting-started/bootstrap-cardano-node.md +++ b/docs/website/versioned_docs/version-maintained/manual/getting-started/bootstrap-cardano-node.md @@ -207,10 +207,12 @@ Then, create a shell function for the Mithril client: ```bash mithril_client () { - docker run --rm -e GENESIS_VERIFICATION_KEY=$GENESIS_VERIFICATION_KEY -e AGGREGATOR_ENDPOINT=$AGGREGATOR_ENDPOINT --name='mithril-client' -v $(pwd):/app/data -w /app/data -u $(id -u) ghcr.io/intersectmbo/mithril-client:$MITHRIL_IMAGE_ID $@ + docker run --rm -e GENESIS_VERIFICATION_KEY=$GENESIS_VERIFICATION_KEY -e AGGREGATOR_ENDPOINT=$AGGREGATOR_ENDPOINT --name='mithril-client' --security-opt seccomp=unconfined -v $(pwd):/app/data -w /app/data -u $(id -u) ghcr.io/intersectmbo/mithril-client:$MITHRIL_IMAGE_ID "$@" } ``` +The `--security-opt seccomp=unconfined` option is required by the `LSM` ledger state conversion, which uses io_uring syscalls blocked by the default Docker seccomp profile. + You can now use the `mithril_client` function: ```bash @@ -520,20 +522,30 @@ Upgrade and replace the restored ledger state snapshot to 'LMDB' flavor by runni ### Step 5 (optional): Convert the ledger state snapshot to another flavor -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. +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 using the Mithril client `tools utxo-hd snapshot-converter` command. + +Each flavor can only be read by a range of Cardano node versions: -To do so, run the following command: +| Flavor | Cardano node versions running the converted ledger state | +| -------- | -------------------------------------------------------- | +| `LSM` | `10.7.0` and above | +| `LMDB` | `11.0.1` and below | +| `Legacy` | `10.3.1` and below | + +To convert the ledger state to the `LSM` flavor, run the following command: ``` -mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor LMDB +mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor LSM ``` -Or, to convert it to the `Legacy` flavor: +Or, to convert it to the `LMDB` flavor, which is useful to run a Cardano node older than the one used by the aggregator: ``` -mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version latest --utxo-hd-flavor Legacy +mithril-client tools utxo-hd snapshot-converter --db-directory db --cardano-node-version 11.0.1 --utxo-hd-flavor LMDB ``` +The `LMDB` backend was dropped in Cardano node `11.1.0`. Requesting that flavor with `11.1.0` or upper fails, so pass a version able to run it. + Use the `--commit` option to replace the current ledger state with the converted snapshot. 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. diff --git a/mithril-client-cli/Cargo.toml b/mithril-client-cli/Cargo.toml index 96799e17658..4e01ce80f5a 100644 --- a/mithril-client-cli/Cargo.toml +++ b/mithril-client-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-client-cli" -version = "0.13.22" +version = "0.13.23" description = "A Mithril Client" authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-client-cli/src/commands/cardano_db/shared_steps.rs b/mithril-client-cli/src/commands/cardano_db/shared_steps.rs index d2c9ce202c3..4104ab6bc05 100644 --- a/mithril-client-cli/src/commands/cardano_db/shared_steps.rs +++ b/mithril-client-cli/src/commands/cardano_db/shared_steps.rs @@ -10,8 +10,8 @@ use mithril_client::{ }; use crate::utils::{ - CARDANO_NODE_V10_6_2, CARDANO_NODE_V10_7_0, CardanoDbUtils, LedgerFormat, ProgressPrinter, - is_version_equal_or_upper, + CardanoDbUtils, LedgerFormat, ProgressPrinter, is_version_at_least_10_6_2_or_latest, + is_version_at_least_10_7_0_or_latest, is_version_at_least_11_1_0_or_latest, }; pub struct ComputeCardanoDatabaseMessageOptions { @@ -197,10 +197,14 @@ pub fn log_download_information( json["snapshot_converter_cmd_to_lsm"] = serde_json::Value::String(snapshot_converter_cmd("LSM")); } - json["snapshot_converter_cmd_to_lmdb"] = - serde_json::Value::String(snapshot_converter_cmd("LMDB")); - json["snapshot_converter_cmd_to_legacy"] = - serde_json::Value::String(snapshot_converter_cmd("Legacy")); + if !is_version_at_least_11_1_0_or_latest(cardano_node_version) { + json["snapshot_converter_cmd_to_lmdb"] = + serde_json::Value::String(snapshot_converter_cmd("LMDB")); + } + if !is_version_at_least_10_6_2_or_latest(cardano_node_version) { + json["snapshot_converter_cmd_to_legacy"] = + serde_json::Value::String(snapshot_converter_cmd("Legacy")); + } } } @@ -235,13 +239,15 @@ pub fn log_download_information( ); } - println!( - r###"Upgrade and replace the restored ledger state snapshot to 'LMDB' flavor by running the command: + if !is_version_at_least_11_1_0_or_latest(cardano_node_version) { + println!( + r###"Upgrade and replace the restored ledger state snapshot to 'LMDB' flavor by running the command: {} "###, - snapshot_converter_cmd("LMDB"), - ); + snapshot_converter_cmd("LMDB"), + ); + } if !is_version_at_least_10_6_2_or_latest(cardano_node_version) { println!( @@ -259,14 +265,6 @@ pub fn log_download_information( Ok(()) } -pub fn is_version_at_least_10_7_0_or_latest(version: &str) -> bool { - is_version_equal_or_upper(version, CARDANO_NODE_V10_7_0) -} - -pub fn is_version_at_least_10_6_2_or_latest(version: &str) -> bool { - is_version_equal_or_upper(version, CARDANO_NODE_V10_6_2) -} - #[cfg(test)] mod tests { use mithril_client::{ diff --git a/mithril-client-cli/src/commands/tools/utxo_hd/snapshot_converter.rs b/mithril-client-cli/src/commands/tools/utxo_hd/snapshot_converter.rs index a23d9ef43a4..5d5a1cd7b50 100644 --- a/mithril-client-cli/src/commands/tools/utxo_hd/snapshot_converter.rs +++ b/mithril-client-cli/src/commands/tools/utxo_hd/snapshot_converter.rs @@ -14,14 +14,12 @@ use mithril_client::{ common::{CardanoNetwork, MagicId}, }; +use crate::CommandContext; use crate::utils::{ ArchiveUnpacker, CardanoDbUtils, GitHubReleaseRetriever, HttpDownloader, LedgerFormat, ProgressOutputType, ProgressPrinter, ReqwestGitHubApiClient, ReqwestHttpDownloader, copy_dir, - is_version_equal_or_upper, print_simple_warning, remove_dir_contents, -}; -use crate::{ - CommandContext, - utils::{CARDANO_NODE_V10_6_2, CARDANO_NODE_V10_7_0, CARDANO_NODE_V11_1_0}, + is_version_at_least_10_6_2_or_latest, is_version_at_least_10_7_0_or_latest, + is_version_at_least_11_1_0_or_latest, print_simple_warning, remove_dir_contents, }; const GITHUB_ORGANIZATION: &str = "IntersectMBO"; @@ -47,6 +45,9 @@ const PROTOCOL_MAGIC_ID_FILE: &str = "protocolMagicId"; const CONVERSION_FALLBACK_LIMIT: usize = 2; +/// Last Cardano node version able to run a ledger state converted to the LMDB flavor. +const CARDANO_NODE_LAST_LMDB_VERSION: &str = "11.0.1"; + #[derive(Debug, Clone, ValueEnum, Eq, PartialEq)] enum UTxOHDFlavor { #[clap(name = "Legacy")] @@ -396,6 +397,14 @@ impl SnapshotConverterCommand { )); } + if is_version_at_least_11_1_0_or_latest(&self.cardano_node_version) + && self.utxo_hd_flavor == UTxOHDFlavor::Lmdb + { + return Err(anyhow!( + "UTxO HD Flavor LMDB is not supported on Cardano node 11.1.0 or upper" + )); + } + let is_local_bin_mode = self.binary_path.is_some() && self.config_path.is_some(); let number_of_steps = Self::calculate_number_of_steps(is_local_bin_mode, self.commit); @@ -665,6 +674,15 @@ impl SnapshotConverterCommand { ); } + if matches!(&utxo_hd_flavor, UTxOHDFlavor::Lmdb) { + print_simple_warning( + &format!( + "LMDB ledger format is only compatible with cardano-node up to `{CARDANO_NODE_LAST_LMDB_VERSION}`." + ), + is_json_output_enabled, + ); + } + if is_json_output_enabled { println!( "{}", @@ -987,18 +1005,6 @@ fn get_snapshot_converter_bin_by_version( } } -fn is_version_at_least_11_1_0_or_latest(version: &str) -> bool { - is_version_equal_or_upper(version, CARDANO_NODE_V11_1_0) -} - -fn is_version_at_least_10_7_0_or_latest(version: &str) -> bool { - is_version_equal_or_upper(version, CARDANO_NODE_V10_7_0) -} - -fn is_version_at_least_10_6_2_or_latest(version: &str) -> bool { - is_version_equal_or_upper(version, CARDANO_NODE_V10_6_2) -} - #[cfg(test)] mod tests { use std::fs::File; @@ -1093,6 +1099,58 @@ mod tests { "UTxO HD Flavor Legacy is not supported on Cardano node 10.6.2 or upper" ); } + + #[tokio::test] + async fn should_return_error_if_utxo_hd_flavor_is_lmdb_and_cardano_node_version_11_1_0() { + let command = SnapshotConverterCommand { + cardano_node_version: "11.1.0".to_string(), + utxo_hd_flavor: UTxOHDFlavor::Lmdb, + ..dummy_snapshot_converter_command() + }; + + let result = SnapshotConverterCommand::execute(&command, fake_command_context()).await; + + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().to_string(), + "UTxO HD Flavor LMDB is not supported on Cardano node 11.1.0 or upper" + ); + } + + #[tokio::test] + async fn should_return_error_if_utxo_hd_flavor_is_lmdb_and_cardano_node_version_11_1_0_or_upper() + { + let command = SnapshotConverterCommand { + cardano_node_version: "11.2.1".to_string(), + utxo_hd_flavor: UTxOHDFlavor::Lmdb, + ..dummy_snapshot_converter_command() + }; + + let result = SnapshotConverterCommand::execute(&command, fake_command_context()).await; + + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().to_string(), + "UTxO HD Flavor LMDB is not supported on Cardano node 11.1.0 or upper" + ); + } + + #[tokio::test] + async fn should_return_error_if_utxo_hd_flavor_is_lmdb_and_cardano_node_version_latest() { + let command = SnapshotConverterCommand { + cardano_node_version: "latest".to_string(), + utxo_hd_flavor: UTxOHDFlavor::Lmdb, + ..dummy_snapshot_converter_command() + }; + + let result = SnapshotConverterCommand::execute(&command, fake_command_context()).await; + + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().to_string(), + "UTxO HD Flavor LMDB is not supported on Cardano node 11.1.0 or upper" + ); + } } mod download_cardano_node_distribution { diff --git a/mithril-client-cli/src/utils/version.rs b/mithril-client-cli/src/utils/version.rs index 24a9c184b0c..e0c7af1fa01 100644 --- a/mithril-client-cli/src/utils/version.rs +++ b/mithril-client-cli/src/utils/version.rs @@ -26,6 +26,21 @@ pub fn is_version_equal_or_upper(version_to_check: &str, version_reference: Vers }) } +/// Returns `true` when the Cardano node version is `10.6.2` or newer. +pub fn is_version_at_least_10_6_2_or_latest(version: &str) -> bool { + is_version_equal_or_upper(version, CARDANO_NODE_V10_6_2) +} + +/// Returns `true` when the Cardano node version is `10.7.0` or newer. +pub fn is_version_at_least_10_7_0_or_latest(version: &str) -> bool { + is_version_equal_or_upper(version, CARDANO_NODE_V10_7_0) +} + +/// Returns `true` when the Cardano node version is `11.1.0` or newer. +pub fn is_version_at_least_11_1_0_or_latest(version: &str) -> bool { + is_version_equal_or_upper(version, CARDANO_NODE_V11_1_0) +} + #[cfg(test)] mod tests { use super::*; @@ -65,4 +80,19 @@ mod tests { VERSION_11_1_0 )); } + + #[test] + fn cardano_node_version_predicates_match_their_reference_version() { + assert!(!is_version_at_least_10_6_2_or_latest("10.6.1")); + assert!(is_version_at_least_10_6_2_or_latest("10.6.2")); + assert!(is_version_at_least_10_6_2_or_latest("latest")); + + assert!(!is_version_at_least_10_7_0_or_latest("10.6.9")); + assert!(is_version_at_least_10_7_0_or_latest("10.7.0")); + assert!(is_version_at_least_10_7_0_or_latest("latest")); + + assert!(!is_version_at_least_11_1_0_or_latest("11.0.9")); + assert!(is_version_at_least_11_1_0_or_latest("11.1.0")); + assert!(is_version_at_least_11_1_0_or_latest("latest")); + } }