common.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. use std::collections::HashMap;
  2. use std::sync::Arc;
  3. use bitcoin::bip32::{ChildNumber, DerivationPath, Xpriv};
  4. use bitcoin::secp256k1::{self, All, Secp256k1};
  5. use cdk_common::database;
  6. use cdk_common::error::Error;
  7. use cdk_common::mint::MintKeySetInfo;
  8. use cdk_common::nuts::{CurrencyUnit, Id, MintKeySet};
  9. use cdk_common::util::unix_time;
  10. /// Initialize keysets and returns a [`Result`] with a tuple of the following:
  11. /// * a [`HashMap`] mapping each active keyset `Id` to `MintKeySet`
  12. /// * a [`Vec`] of `CurrencyUnit` containing active keysets units
  13. pub async fn init_keysets(
  14. xpriv: Xpriv,
  15. secp_ctx: &Secp256k1<All>,
  16. localstore: &Arc<dyn database::MintKeysDatabase<Err = database::Error> + Send + Sync>,
  17. supported_units: &HashMap<CurrencyUnit, (u64, u8)>,
  18. custom_paths: &HashMap<CurrencyUnit, DerivationPath>,
  19. ) -> Result<(HashMap<Id, MintKeySet>, Vec<CurrencyUnit>), Error> {
  20. let mut active_keysets: HashMap<Id, MintKeySet> = HashMap::new();
  21. let mut active_keyset_units: Vec<CurrencyUnit> = vec![];
  22. // Get keysets info from DB
  23. let keysets_infos = localstore.get_keyset_infos().await?;
  24. if !keysets_infos.is_empty() {
  25. tracing::debug!("Setting all saved keysets to inactive");
  26. for keyset in keysets_infos.clone() {
  27. // Set all to in active
  28. let mut keyset = keyset;
  29. keyset.active = false;
  30. localstore.add_keyset_info(keyset).await?;
  31. }
  32. let keysets_by_unit: HashMap<CurrencyUnit, Vec<MintKeySetInfo>> =
  33. keysets_infos.iter().fold(HashMap::new(), |mut acc, ks| {
  34. acc.entry(ks.unit.clone()).or_default().push(ks.clone());
  35. acc
  36. });
  37. for (unit, keysets) in keysets_by_unit {
  38. let mut keysets = keysets;
  39. keysets.sort_by(|a, b| b.derivation_path_index.cmp(&a.derivation_path_index));
  40. // Get the keyset with the highest counter
  41. let highest_index_keyset = keysets
  42. .first()
  43. .cloned()
  44. .expect("unit will not be added to hashmap if empty");
  45. let keysets: Vec<MintKeySetInfo> = keysets
  46. .into_iter()
  47. .filter(|ks| ks.derivation_path_index.is_some())
  48. .collect();
  49. if let Some((input_fee_ppk, max_order)) = supported_units.get(&unit) {
  50. if !keysets.is_empty()
  51. && &highest_index_keyset.input_fee_ppk == input_fee_ppk
  52. && &highest_index_keyset.max_order == max_order
  53. {
  54. tracing::debug!("Current highest index keyset matches expect fee and max order. Setting active");
  55. let id = highest_index_keyset.id;
  56. let keyset = MintKeySet::generate_from_xpriv(
  57. secp_ctx,
  58. xpriv,
  59. highest_index_keyset.max_order,
  60. highest_index_keyset.unit.clone(),
  61. highest_index_keyset.derivation_path.clone(),
  62. );
  63. active_keysets.insert(id, keyset);
  64. let mut keyset_info = highest_index_keyset;
  65. keyset_info.active = true;
  66. localstore.add_keyset_info(keyset_info).await?;
  67. active_keyset_units.push(unit.clone());
  68. localstore.set_active_keyset(unit, id).await?;
  69. } else {
  70. // Check to see if there are not keysets by this unit
  71. let derivation_path_index = if keysets.is_empty() {
  72. 1
  73. } else {
  74. highest_index_keyset.derivation_path_index.unwrap_or(0) + 1
  75. };
  76. let derivation_path = match custom_paths.get(&unit) {
  77. Some(path) => path.clone(),
  78. None => derivation_path_from_unit(unit.clone(), derivation_path_index)
  79. .ok_or(Error::UnsupportedUnit)?,
  80. };
  81. let (keyset, keyset_info) = create_new_keyset(
  82. secp_ctx,
  83. xpriv,
  84. derivation_path,
  85. Some(derivation_path_index),
  86. unit.clone(),
  87. *max_order,
  88. *input_fee_ppk,
  89. );
  90. let id = keyset_info.id;
  91. localstore.add_keyset_info(keyset_info).await?;
  92. localstore.set_active_keyset(unit.clone(), id).await?;
  93. active_keysets.insert(id, keyset);
  94. active_keyset_units.push(unit.clone());
  95. };
  96. }
  97. }
  98. }
  99. Ok((active_keysets, active_keyset_units))
  100. }
  101. /// Generate new [`MintKeySetInfo`] from path
  102. #[tracing::instrument(skip_all)]
  103. pub fn create_new_keyset<C: secp256k1::Signing>(
  104. secp: &secp256k1::Secp256k1<C>,
  105. xpriv: Xpriv,
  106. derivation_path: DerivationPath,
  107. derivation_path_index: Option<u32>,
  108. unit: CurrencyUnit,
  109. max_order: u8,
  110. input_fee_ppk: u64,
  111. ) -> (MintKeySet, MintKeySetInfo) {
  112. let keyset = MintKeySet::generate(
  113. secp,
  114. xpriv
  115. .derive_priv(secp, &derivation_path)
  116. .expect("RNG busted"),
  117. unit,
  118. max_order,
  119. );
  120. let keyset_info = MintKeySetInfo {
  121. id: keyset.id,
  122. unit: keyset.unit.clone(),
  123. active: true,
  124. valid_from: unix_time(),
  125. valid_to: None,
  126. derivation_path,
  127. derivation_path_index,
  128. max_order,
  129. input_fee_ppk,
  130. };
  131. (keyset, keyset_info)
  132. }
  133. pub fn derivation_path_from_unit(unit: CurrencyUnit, index: u32) -> Option<DerivationPath> {
  134. let unit_index = unit.derivation_index()?;
  135. Some(DerivationPath::from(vec![
  136. ChildNumber::from_hardened_idx(0).expect("0 is a valid index"),
  137. ChildNumber::from_hardened_idx(unit_index).expect("0 is a valid index"),
  138. ChildNumber::from_hardened_idx(index).expect("0 is a valid index"),
  139. ]))
  140. }