common.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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, MintKeySet};
  9. use cdk_common::util::unix_time;
  10. /// Initialize keysets
  11. pub async fn init_keysets(
  12. xpriv: Xpriv,
  13. secp_ctx: &Secp256k1<All>,
  14. localstore: &Arc<dyn database::MintKeysDatabase<Err = database::Error> + Send + Sync>,
  15. supported_units: &HashMap<CurrencyUnit, (u64, u8)>,
  16. ) -> Result<(), Error> {
  17. let keysets_infos = localstore.get_keyset_infos().await?;
  18. let mut tx = localstore.begin_transaction().await?;
  19. let keysets_by_unit: HashMap<CurrencyUnit, Vec<MintKeySetInfo>> =
  20. keysets_infos.iter().fold(HashMap::new(), |mut acc, ks| {
  21. acc.entry(ks.unit.clone()).or_default().push(ks.clone());
  22. acc
  23. });
  24. for (unit, keysets) in keysets_by_unit {
  25. // We only care about units that are supported
  26. if let Some((input_fee_ppk, max_order)) = supported_units.get(&unit) {
  27. let mut keysets = keysets;
  28. keysets.sort_by_key(|b| std::cmp::Reverse(b.derivation_path_index));
  29. if let Some(highest_index_keyset) = keysets.first() {
  30. // Check if it matches our criteria
  31. if highest_index_keyset.input_fee_ppk == *input_fee_ppk
  32. && highest_index_keyset.amounts.len() == (*max_order as usize)
  33. {
  34. tracing::debug!("Current highest index keyset matches expect fee and max order. Setting active");
  35. let id = highest_index_keyset.id;
  36. // Validate we can generate it (sanity check)
  37. let _ = MintKeySet::generate_from_xpriv(
  38. secp_ctx,
  39. xpriv,
  40. &highest_index_keyset.amounts,
  41. highest_index_keyset.unit.clone(),
  42. highest_index_keyset.derivation_path.clone(),
  43. highest_index_keyset.input_fee_ppk,
  44. highest_index_keyset.final_expiry,
  45. highest_index_keyset.id.get_version(),
  46. );
  47. let mut keyset_info = highest_index_keyset.clone();
  48. keyset_info.active = true;
  49. tx.add_keyset_info(keyset_info).await?;
  50. tx.set_active_keyset(unit.clone(), id).await?;
  51. }
  52. }
  53. }
  54. }
  55. tx.commit().await?;
  56. Ok(())
  57. }
  58. /// Generate new [`MintKeySetInfo`] from path
  59. #[tracing::instrument(skip_all)]
  60. #[allow(clippy::too_many_arguments)]
  61. pub fn create_new_keyset<C: secp256k1::Signing>(
  62. secp: &secp256k1::Secp256k1<C>,
  63. xpriv: Xpriv,
  64. derivation_path: DerivationPath,
  65. derivation_path_index: Option<u32>,
  66. unit: CurrencyUnit,
  67. amounts: &[u64],
  68. input_fee_ppk: u64,
  69. final_expiry: Option<u64>,
  70. use_keyset_v2: bool,
  71. ) -> (MintKeySet, MintKeySetInfo) {
  72. let version = if use_keyset_v2 {
  73. cdk_common::nut02::KeySetVersion::Version01
  74. } else {
  75. cdk_common::nut02::KeySetVersion::Version00
  76. };
  77. let keyset = MintKeySet::generate(
  78. secp,
  79. xpriv
  80. .derive_priv(secp, &derivation_path)
  81. .expect("RNG busted"),
  82. unit,
  83. amounts,
  84. input_fee_ppk,
  85. final_expiry,
  86. version,
  87. );
  88. let keyset_info = MintKeySetInfo {
  89. id: keyset.id,
  90. unit: keyset.unit.clone(),
  91. active: true,
  92. valid_from: unix_time(),
  93. final_expiry: keyset.final_expiry,
  94. derivation_path,
  95. derivation_path_index,
  96. amounts: amounts.to_owned(),
  97. input_fee_ppk,
  98. };
  99. (keyset, keyset_info)
  100. }
  101. pub fn derivation_path_from_unit(unit: CurrencyUnit, index: u32) -> Option<DerivationPath> {
  102. let unit_index = unit.derivation_index()?;
  103. Some(DerivationPath::from(vec![
  104. ChildNumber::from_hardened_idx(0).expect("0 is a valid index"),
  105. ChildNumber::from_hardened_idx(unit_index).expect("0 is a valid index"),
  106. ChildNumber::from_hardened_idx(index).expect("0 is a valid index"),
  107. ]))
  108. }