keys.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. //! Keys database tests
  2. use std::str::FromStr;
  3. use bitcoin::bip32::DerivationPath;
  4. use cashu::{CurrencyUnit, Id};
  5. use crate::common::IssuerVersion;
  6. use crate::database::mint::{Database, Error, KeysDatabase};
  7. use crate::mint::MintKeySetInfo;
  8. /// Generate standard keyset amounts as powers of 2
  9. fn standard_keyset_amounts(max_order: u32) -> Vec<u64> {
  10. (0..max_order).map(|n| 2u64.pow(n)).collect()
  11. }
  12. /// Test adding and retrieving keyset info
  13. pub async fn add_and_get_keyset_info<DB>(db: DB)
  14. where
  15. DB: Database<Error> + KeysDatabase<Err = Error>,
  16. {
  17. let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
  18. let keyset_info = MintKeySetInfo {
  19. id: keyset_id,
  20. unit: CurrencyUnit::Sat,
  21. active: true,
  22. valid_from: 0,
  23. final_expiry: None,
  24. derivation_path: DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  25. derivation_path_index: Some(0),
  26. input_fee_ppk: 0,
  27. amounts: standard_keyset_amounts(32),
  28. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  29. };
  30. // Add keyset info
  31. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  32. tx.add_keyset_info(keyset_info.clone()).await.unwrap();
  33. tx.commit().await.unwrap();
  34. // Retrieve keyset info
  35. let retrieved = db.get_keyset_info(&keyset_id).await.unwrap();
  36. assert!(retrieved.is_some());
  37. let retrieved = retrieved.unwrap();
  38. assert_eq!(retrieved.id, keyset_info.id);
  39. assert_eq!(retrieved.unit, keyset_info.unit);
  40. assert_eq!(retrieved.active, keyset_info.active);
  41. assert_eq!(retrieved.amounts, keyset_info.amounts);
  42. assert_eq!(retrieved.issuer_version, keyset_info.issuer_version);
  43. }
  44. /// Test adding duplicate keyset info is idempotent
  45. pub async fn add_duplicate_keyset_info<DB>(db: DB)
  46. where
  47. DB: Database<Error> + KeysDatabase<Err = Error>,
  48. {
  49. let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
  50. let keyset_info = MintKeySetInfo {
  51. id: keyset_id,
  52. unit: CurrencyUnit::Sat,
  53. active: true,
  54. valid_from: 0,
  55. final_expiry: None,
  56. derivation_path: DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  57. derivation_path_index: Some(0),
  58. input_fee_ppk: 0,
  59. amounts: standard_keyset_amounts(32),
  60. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  61. };
  62. // Add keyset info first time
  63. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  64. tx.add_keyset_info(keyset_info.clone()).await.unwrap();
  65. tx.commit().await.unwrap();
  66. // Add the same keyset info again - this may succeed (idempotent) or fail
  67. // Both behaviors are acceptable
  68. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  69. let result = tx.add_keyset_info(keyset_info).await;
  70. assert!(result.is_ok());
  71. tx.commit().await.unwrap();
  72. // Verify keyset still exists
  73. let retrieved = db.get_keyset_info(&keyset_id).await.unwrap();
  74. assert!(retrieved.is_some());
  75. }
  76. /// Test getting all keyset infos
  77. pub async fn get_all_keyset_infos<DB>(db: DB)
  78. where
  79. DB: Database<Error> + KeysDatabase<Err = Error>,
  80. {
  81. let keyset_id1 = Id::from_str("00916bbf7ef91a36").unwrap();
  82. let keyset_info1 = MintKeySetInfo {
  83. id: keyset_id1,
  84. unit: CurrencyUnit::Sat,
  85. active: true,
  86. valid_from: 0,
  87. final_expiry: None,
  88. derivation_path: DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  89. derivation_path_index: Some(0),
  90. input_fee_ppk: 0,
  91. amounts: standard_keyset_amounts(32),
  92. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  93. };
  94. let keyset_id2 = Id::from_str("00916bbf7ef91a37").unwrap();
  95. let keyset_info2 = MintKeySetInfo {
  96. id: keyset_id2,
  97. unit: CurrencyUnit::Sat,
  98. active: false,
  99. valid_from: 0,
  100. final_expiry: None,
  101. derivation_path: DerivationPath::from_str("m/0'/0'/1'").unwrap(),
  102. derivation_path_index: Some(1),
  103. input_fee_ppk: 0,
  104. amounts: standard_keyset_amounts(32),
  105. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  106. };
  107. // Add keyset infos
  108. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  109. tx.add_keyset_info(keyset_info1.clone()).await.unwrap();
  110. tx.add_keyset_info(keyset_info2.clone()).await.unwrap();
  111. tx.commit().await.unwrap();
  112. // Get all keyset infos
  113. let all_keysets = db.get_keyset_infos().await.unwrap();
  114. assert!(all_keysets.len() >= 2);
  115. assert!(all_keysets.iter().any(|k| k.id == keyset_id1));
  116. assert!(all_keysets.iter().any(|k| k.id == keyset_id2));
  117. }
  118. /// Test setting and getting active keyset
  119. pub async fn set_and_get_active_keyset<DB>(db: DB)
  120. where
  121. DB: Database<Error> + KeysDatabase<Err = Error>,
  122. {
  123. let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
  124. let keyset_info = MintKeySetInfo {
  125. id: keyset_id,
  126. unit: CurrencyUnit::Sat,
  127. active: true,
  128. valid_from: 0,
  129. final_expiry: None,
  130. derivation_path: DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  131. derivation_path_index: Some(0),
  132. input_fee_ppk: 0,
  133. amounts: standard_keyset_amounts(32),
  134. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  135. };
  136. // Add keyset info
  137. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  138. tx.add_keyset_info(keyset_info.clone()).await.unwrap();
  139. tx.set_active_keyset(CurrencyUnit::Sat, keyset_id)
  140. .await
  141. .unwrap();
  142. tx.commit().await.unwrap();
  143. // Get active keyset
  144. let active_id = db.get_active_keyset_id(&CurrencyUnit::Sat).await.unwrap();
  145. assert!(active_id.is_some());
  146. assert_eq!(active_id.unwrap(), keyset_id);
  147. }
  148. /// Test getting all active keysets
  149. pub async fn get_all_active_keysets<DB>(db: DB)
  150. where
  151. DB: Database<Error> + KeysDatabase<Err = Error>,
  152. {
  153. let keyset_id_sat = Id::from_str("00916bbf7ef91a36").unwrap();
  154. let keyset_info_sat = MintKeySetInfo {
  155. id: keyset_id_sat,
  156. unit: CurrencyUnit::Sat,
  157. active: true,
  158. valid_from: 0,
  159. final_expiry: None,
  160. derivation_path: DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  161. derivation_path_index: Some(0),
  162. input_fee_ppk: 0,
  163. amounts: standard_keyset_amounts(32),
  164. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  165. };
  166. let keyset_id_usd = Id::from_str("00916bbf7ef91a37").unwrap();
  167. let keyset_info_usd = MintKeySetInfo {
  168. id: keyset_id_usd,
  169. unit: CurrencyUnit::Usd,
  170. active: true,
  171. valid_from: 0,
  172. final_expiry: None,
  173. derivation_path: DerivationPath::from_str("m/0'/0'/1'").unwrap(),
  174. derivation_path_index: Some(1),
  175. input_fee_ppk: 0,
  176. amounts: standard_keyset_amounts(32),
  177. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  178. };
  179. // Add keyset infos and set as active
  180. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  181. tx.add_keyset_info(keyset_info_sat.clone()).await.unwrap();
  182. tx.add_keyset_info(keyset_info_usd.clone()).await.unwrap();
  183. tx.set_active_keyset(CurrencyUnit::Sat, keyset_id_sat)
  184. .await
  185. .unwrap();
  186. tx.set_active_keyset(CurrencyUnit::Usd, keyset_id_usd)
  187. .await
  188. .unwrap();
  189. tx.commit().await.unwrap();
  190. // Get all active keysets
  191. let active_keysets = db.get_active_keysets().await.unwrap();
  192. assert!(active_keysets.len() >= 2);
  193. assert_eq!(active_keysets.get(&CurrencyUnit::Sat), Some(&keyset_id_sat));
  194. assert_eq!(active_keysets.get(&CurrencyUnit::Usd), Some(&keyset_id_usd));
  195. }
  196. /// Test updating active keyset
  197. pub async fn update_active_keyset<DB>(db: DB)
  198. where
  199. DB: Database<Error> + KeysDatabase<Err = Error>,
  200. {
  201. let keyset_id1 = Id::from_str("00916bbf7ef91a36").unwrap();
  202. let keyset_info1 = MintKeySetInfo {
  203. id: keyset_id1,
  204. unit: CurrencyUnit::Sat,
  205. active: true,
  206. valid_from: 0,
  207. final_expiry: None,
  208. derivation_path: DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  209. derivation_path_index: Some(0),
  210. input_fee_ppk: 0,
  211. amounts: standard_keyset_amounts(32),
  212. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  213. };
  214. let keyset_id2 = Id::from_str("00916bbf7ef91a37").unwrap();
  215. let keyset_info2 = MintKeySetInfo {
  216. id: keyset_id2,
  217. unit: CurrencyUnit::Sat,
  218. active: false,
  219. valid_from: 0,
  220. final_expiry: None,
  221. derivation_path: DerivationPath::from_str("m/0'/0'/1'").unwrap(),
  222. derivation_path_index: Some(1),
  223. input_fee_ppk: 0,
  224. amounts: standard_keyset_amounts(32),
  225. issuer_version: IssuerVersion::from_str("cdk/0.1.0").ok(),
  226. };
  227. // Add both keysets and set first as active
  228. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  229. tx.add_keyset_info(keyset_info1.clone()).await.unwrap();
  230. tx.add_keyset_info(keyset_info2.clone()).await.unwrap();
  231. tx.set_active_keyset(CurrencyUnit::Sat, keyset_id1)
  232. .await
  233. .unwrap();
  234. tx.commit().await.unwrap();
  235. // Verify first keyset is active
  236. let active_id = db.get_active_keyset_id(&CurrencyUnit::Sat).await.unwrap();
  237. assert_eq!(active_id, Some(keyset_id1));
  238. // Update to second keyset
  239. let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
  240. tx.set_active_keyset(CurrencyUnit::Sat, keyset_id2)
  241. .await
  242. .unwrap();
  243. tx.commit().await.unwrap();
  244. // Verify second keyset is now active
  245. let active_id = db.get_active_keyset_id(&CurrencyUnit::Sat).await.unwrap();
  246. assert_eq!(active_id, Some(keyset_id2));
  247. }
  248. /// Test getting non-existent keyset info
  249. pub async fn get_nonexistent_keyset_info<DB>(db: DB)
  250. where
  251. DB: Database<Error> + KeysDatabase<Err = Error>,
  252. {
  253. let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
  254. // Try to get non-existent keyset
  255. let retrieved = db.get_keyset_info(&keyset_id).await.unwrap();
  256. assert!(retrieved.is_none());
  257. }
  258. /// Test getting active keyset when none is set
  259. pub async fn get_active_keyset_when_none_set<DB>(db: DB)
  260. where
  261. DB: Database<Error> + KeysDatabase<Err = Error>,
  262. {
  263. // Try to get active keyset when none is set
  264. let active_id = db.get_active_keyset_id(&CurrencyUnit::Sat).await.unwrap();
  265. assert!(active_id.is_none());
  266. }