iota_genesis_builder/stardust/migration/
migration_target_network.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{fmt::Display, str::FromStr};
5
6use fastcrypto::hash::HashFunction;
7use iota_types::{crypto::DefaultHash, digests::TransactionDigest, stardust::coin_type::CoinType};
8
9const MAINNET: &str = "mainnet";
10const TESTNET: &str = "testnet";
11const ALPHANET: &str = "alphanet";
12
13/// The target network of the migration.
14///
15/// Different variants of this enum will result in different digests of the
16/// objects generated in the migration.
17#[derive(Debug, Clone, PartialEq)]
18pub enum MigrationTargetNetwork {
19    Mainnet,
20    Testnet(String),
21    Alphanet(String),
22}
23
24impl MigrationTargetNetwork {
25    /// Returns the [`TransactionDigest`] for the migration to the target
26    /// network in `self`.
27    pub fn migration_transaction_digest(&self, coin_type: &CoinType) -> TransactionDigest {
28        let hash_input = format!("{coin_type}-stardust-migration-{self}");
29        let mut hasher = DefaultHash::default();
30        hasher.update(hash_input);
31        let hash = hasher.finalize();
32
33        TransactionDigest::new(hash.into())
34    }
35}
36
37impl FromStr for MigrationTargetNetwork {
38    type Err = anyhow::Error;
39
40    fn from_str(string: &str) -> Result<Self, Self::Err> {
41        if string == MAINNET {
42            return Ok(MigrationTargetNetwork::Mainnet);
43        }
44
45        if string.starts_with(TESTNET) {
46            return Ok(MigrationTargetNetwork::Testnet(
47                string.chars().skip(TESTNET.len()).collect(),
48            ));
49        }
50
51        if string.starts_with(ALPHANET) {
52            return Ok(MigrationTargetNetwork::Alphanet(
53                string.chars().skip(ALPHANET.len()).collect(),
54            ));
55        }
56
57        anyhow::bail!(
58            "unknown target network name '{string}': please provide the target network for which the snapshot is being generated ('{}', '{}' or '{}')",
59            MigrationTargetNetwork::Mainnet,
60            MigrationTargetNetwork::Testnet("(optional-string)".to_owned()),
61            MigrationTargetNetwork::Alphanet("(optional-string)".to_owned()),
62        )
63    }
64}
65
66impl Display for MigrationTargetNetwork {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        match self {
69            MigrationTargetNetwork::Mainnet => f.write_str(MAINNET),
70            MigrationTargetNetwork::Testnet(string) => {
71                f.write_str(TESTNET)?;
72                f.write_str(string)
73            }
74            MigrationTargetNetwork::Alphanet(string) => {
75                f.write_str(ALPHANET)?;
76                f.write_str(string)
77            }
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use std::str::FromStr;
85
86    use crate::stardust::migration::MigrationTargetNetwork;
87
88    #[test]
89    fn to_and_from_string() {
90        let ok_test_inputs = [
91            "mainnet",
92            "testnet",
93            "alphanet",
94            "testnet1",
95            "alphanetOther",
96        ];
97
98        for test_input in ok_test_inputs {
99            assert_eq!(
100                MigrationTargetNetwork::from_str(test_input)
101                    .unwrap()
102                    .to_string(),
103                test_input
104            )
105        }
106    }
107
108    #[test]
109    fn erroneous_input() {
110        assert!(MigrationTargetNetwork::from_str("shimmer").is_err());
111    }
112}