Pārlūkot izejas kodu

feat: `MintKeySet::generate_from_xpriv` and `MintKeySet::generate_from_seed` methods

- Added two new unit tests: `mint_mod_generate_keyset_from_seed` and `mint_mod_generate_keyset_from_xpriv`
- Implemented `mint_mod_new_mint` async test to ensure proper Mint instantiation with minimal data
- Refactored `MintKeySet::generate_from_xpriv` and `MintKeySet::generate_from_seed` methods to accept max_order, currency_unit, and derivation_path parameters directly
vnprc 7 mēneši atpakaļ
vecāks
revīzija
73e8792965
2 mainītis faili ar 183 papildinājumiem un 14 dzēšanām
  1. 171 2
      crates/cdk/src/mint/mod.rs
  2. 12 12
      crates/cdk/src/nuts/nut02.rs

+ 171 - 2
crates/cdk/src/mint/mod.rs

@@ -98,7 +98,9 @@ impl Mint {
                         let keyset = MintKeySet::generate_from_xpriv(
                             &secp_ctx,
                             xpriv,
-                            highest_index_keyset.clone(),
+                            highest_index_keyset.max_order,
+                            highest_index_keyset.unit,
+                            highest_index_keyset.derivation_path.clone(),
                         );
                         active_keysets.insert(id, keyset);
                         let mut keyset_info = highest_index_keyset;
@@ -1156,7 +1158,13 @@ impl Mint {
     /// Generate [`MintKeySet`] from [`MintKeySetInfo`]
     #[instrument(skip_all)]
     pub fn generate_keyset(&self, keyset_info: MintKeySetInfo) -> MintKeySet {
-        MintKeySet::generate_from_xpriv(&self.secp_ctx, self.xpriv, keyset_info)
+        MintKeySet::generate_from_xpriv(
+            &self.secp_ctx,
+            self.xpriv,
+            keyset_info.max_order,
+            keyset_info.unit,
+            keyset_info.derivation_path,
+        )
     }
 
     /// Get the total amount issed by keyset
@@ -1296,3 +1304,164 @@ fn derivation_path_from_unit(unit: CurrencyUnit, index: u32) -> DerivationPath {
         ChildNumber::from_hardened_idx(index).expect("0 is a valid index"),
     ])
 }
+
+#[cfg(test)]
+mod tests {
+    use bitcoin::Network;
+    use secp256k1::Secp256k1;
+
+    use super::*;
+
+    #[test]
+    fn mint_mod_generate_keyset_from_seed() {
+        let seed = "test_seed".as_bytes();
+        let keyset = MintKeySet::generate_from_seed(
+            &Secp256k1::new(),
+            seed,
+            2,
+            CurrencyUnit::Sat,
+            derivation_path_from_unit(CurrencyUnit::Sat, 0),
+        );
+
+        assert_eq!(keyset.unit, CurrencyUnit::Sat);
+        assert_eq!(keyset.keys.len(), 2);
+
+        let expected_amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = vec![
+            (
+                Amount::from(1),
+                PublicKey::from_hex(
+                    "0257aed43bf2c1cdbe3e7ae2db2b27a723c6746fc7415e09748f6847916c09176e",
+                )
+                .unwrap(),
+            ),
+            (
+                Amount::from(2),
+                PublicKey::from_hex(
+                    "03ad95811e51adb6231613f9b54ba2ba31e4442c9db9d69f8df42c2b26fbfed26e",
+                )
+                .unwrap(),
+            ),
+        ]
+        .into_iter()
+        .collect();
+
+        let amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = keyset
+            .keys
+            .iter()
+            .map(|(amount, pair)| (*amount, pair.public_key))
+            .collect();
+
+        assert_eq!(amounts_and_pubkeys, expected_amounts_and_pubkeys);
+    }
+
+    #[test]
+    fn mint_mod_generate_keyset_from_xpriv() {
+        let seed = "test_seed".as_bytes();
+        let network = Network::Bitcoin;
+        let xpriv = ExtendedPrivKey::new_master(network, seed).expect("Failed to create xpriv");
+        let keyset = MintKeySet::generate_from_xpriv(
+            &Secp256k1::new(),
+            xpriv,
+            2,
+            CurrencyUnit::Sat,
+            derivation_path_from_unit(CurrencyUnit::Sat, 0),
+        );
+
+        assert_eq!(keyset.unit, CurrencyUnit::Sat);
+        assert_eq!(keyset.keys.len(), 2);
+
+        let expected_amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = vec![
+            (
+                Amount::from(1),
+                PublicKey::from_hex(
+                    "0257aed43bf2c1cdbe3e7ae2db2b27a723c6746fc7415e09748f6847916c09176e",
+                )
+                .unwrap(),
+            ),
+            (
+                Amount::from(2),
+                PublicKey::from_hex(
+                    "03ad95811e51adb6231613f9b54ba2ba31e4442c9db9d69f8df42c2b26fbfed26e",
+                )
+                .unwrap(),
+            ),
+        ]
+        .into_iter()
+        .collect();
+
+        let amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = keyset
+            .keys
+            .iter()
+            .map(|(amount, pair)| (*amount, pair.public_key))
+            .collect();
+
+        assert_eq!(amounts_and_pubkeys, expected_amounts_and_pubkeys);
+    }
+
+    use cdk_database::mint_memory::MintMemoryDatabase;
+
+    #[tokio::test]
+    async fn mint_mod_new_mint() {
+        // mock DB settings
+        let active_keysets: HashMap<CurrencyUnit, Id> = HashMap::new();
+        let keysets: Vec<MintKeySetInfo> = Vec::new();
+        let mint_quotes: Vec<MintQuote> = Vec::new();
+        let melt_quotes: Vec<MeltQuote> = Vec::new();
+        let pending_proofs: Proofs = Proofs::new();
+        let spent_proofs: Proofs = Proofs::new();
+        let blinded_signatures: HashMap<[u8; 33], BlindSignature> = HashMap::new();
+
+        // Mock data
+        let mint_url = "http://example.com";
+        let seed = b"some_random_seed";
+        let mint_info = MintInfo::default();
+        let localstore = Arc::new(
+            MintMemoryDatabase::new(
+                active_keysets,
+                keysets,
+                mint_quotes,
+                melt_quotes,
+                pending_proofs,
+                spent_proofs,
+                blinded_signatures,
+            )
+            .unwrap(),
+        );
+        let supported_units: HashMap<CurrencyUnit, (u64, u8)> = HashMap::new();
+
+        // Instantiate a new Mint
+        let mint = Mint::new(mint_url, seed, mint_info, localstore, supported_units).await;
+
+        // Assert the mint was created successfully
+        assert!(mint.is_ok());
+        let mint = mint.unwrap();
+
+        assert_eq!(mint.get_mint_url().to_string(), "http://example.com");
+        let info = mint.mint_info();
+        assert!(info.name.is_none());
+        assert!(info.pubkey.is_none());
+        assert_eq!(
+            mint.pubkeys().await.unwrap(),
+            KeysResponse {
+                keysets: Vec::new()
+            }
+        );
+
+        assert_eq!(
+            mint.keysets().await.unwrap(),
+            KeysetResponse {
+                keysets: Vec::new()
+            }
+        );
+
+        assert_eq!(
+            mint.total_issued().await.unwrap(),
+            HashMap::<nut02::Id, Amount>::new()
+        );
+
+        assert_eq!(
+            mint.total_redeemed().await.unwrap(),
+            HashMap::<nut02::Id, Amount>::new()
+        );
+    }
+}

+ 12 - 12
crates/cdk/src/nuts/nut02.rs

@@ -9,6 +9,8 @@ use std::array::TryFromSliceError;
 use std::collections::BTreeMap;
 
 #[cfg(feature = "mint")]
+use bitcoin::bip32::DerivationPath;
+#[cfg(feature = "mint")]
 use bitcoin::bip32::{ChildNumber, ExtendedPrivKey};
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::hashes::Hash;
@@ -23,8 +25,6 @@ use thiserror::Error;
 use super::nut01::Keys;
 #[cfg(feature = "mint")]
 use super::nut01::{MintKeyPair, MintKeys};
-#[cfg(feature = "mint")]
-use crate::mint::MintKeySetInfo;
 use crate::nuts::nut00::CurrencyUnit;
 use crate::util::hex;
 #[cfg(feature = "mint")]
@@ -324,18 +324,18 @@ impl MintKeySet {
     pub fn generate_from_seed<C: secp256k1::Signing>(
         secp: &Secp256k1<C>,
         seed: &[u8],
-        info: MintKeySetInfo,
+        max_order: u8,
+        currency_unit: CurrencyUnit,
+        derivation_path: DerivationPath,
     ) -> Self {
         let xpriv =
             ExtendedPrivKey::new_master(bitcoin::Network::Bitcoin, seed).expect("RNG busted");
-        let max_order = info.max_order;
-        let unit = info.unit;
         Self::generate(
             secp,
             xpriv
-                .derive_priv(secp, &info.derivation_path)
+                .derive_priv(secp, &derivation_path)
                 .expect("RNG busted"),
-            unit,
+            currency_unit,
             max_order,
         )
     }
@@ -344,16 +344,16 @@ impl MintKeySet {
     pub fn generate_from_xpriv<C: secp256k1::Signing>(
         secp: &Secp256k1<C>,
         xpriv: ExtendedPrivKey,
-        info: MintKeySetInfo,
+        max_order: u8,
+        currency_unit: CurrencyUnit,
+        derivation_path: DerivationPath,
     ) -> Self {
-        let max_order = info.max_order;
-        let unit = info.unit;
         Self::generate(
             secp,
             xpriv
-                .derive_priv(secp, &info.derivation_path)
+                .derive_priv(secp, &derivation_path)
                 .expect("RNG busted"),
-            unit,
+            currency_unit,
             max_order,
         )
     }