cdk_sqlite/mint/
memory.rs1use std::collections::HashMap;
3
4use cdk_common::database::{self, MintDatabase, MintKeysDatabase};
5use cdk_common::mint::{self, MintKeySetInfo, MintQuote, Operation};
6use cdk_common::nuts::{CurrencyUnit, Id, Proofs, State};
7use cdk_common::MintInfo;
8
9use super::MintSqliteDatabase;
10
11const CDK_MINT_PRIMARY_NAMESPACE: &str = "cdk_mint";
12const CDK_MINT_CONFIG_SECONDARY_NAMESPACE: &str = "config";
13const CDK_MINT_CONFIG_KV_KEY: &str = "mint_info";
14
15pub async fn empty() -> Result<MintSqliteDatabase, database::Error> {
17 #[cfg(not(feature = "sqlcipher"))]
18 let path = ":memory:";
19 #[cfg(feature = "sqlcipher")]
20 let path = (":memory:", "memory");
21
22 MintSqliteDatabase::new(path).await
23}
24
25#[allow(clippy::too_many_arguments)]
27pub async fn new_with_state(
28 active_keysets: HashMap<CurrencyUnit, Id>,
29 keysets: Vec<MintKeySetInfo>,
30 mint_quotes: Vec<MintQuote>,
31 melt_quotes: Vec<mint::MeltQuote>,
32 pending_proofs: Proofs,
33 spent_proofs: Proofs,
34 mint_info: MintInfo,
35) -> Result<MintSqliteDatabase, database::Error> {
36 let db = empty().await?;
37 let mut tx = MintKeysDatabase::begin_transaction(&db).await?;
38
39 for active_keyset in active_keysets {
40 tx.set_active_keyset(active_keyset.0, active_keyset.1)
41 .await?;
42 }
43
44 for keyset in keysets {
45 tx.add_keyset_info(keyset).await?;
46 }
47 tx.commit().await?;
48
49 let mut tx = MintDatabase::begin_transaction(&db).await?;
50
51 for quote in mint_quotes {
52 tx.add_mint_quote(quote).await?;
53 }
54
55 for quote in melt_quotes {
56 tx.add_melt_quote(quote).await?;
57 }
58
59 let operation = Operation::new_swap(Default::default(), Default::default(), Default::default());
60
61 if !pending_proofs.is_empty() {
62 let mut proofs = tx.add_proofs(pending_proofs, None, &operation).await?;
63 tx.update_proofs_state(&mut proofs, State::Pending).await?;
64 }
65
66 if !spent_proofs.is_empty() {
67 let mut proofs = tx.add_proofs(spent_proofs, None, &operation).await?;
68 tx.update_proofs_state(&mut proofs, State::Spent).await?;
69 }
70 let mint_info_bytes = serde_json::to_vec(&mint_info)?;
71 tx.kv_write(
72 CDK_MINT_PRIMARY_NAMESPACE,
73 CDK_MINT_CONFIG_SECONDARY_NAMESPACE,
74 CDK_MINT_CONFIG_KV_KEY,
75 &mint_info_bytes,
76 )
77 .await?;
78 tx.commit().await?;
79
80 Ok(db)
81}
82
83#[cfg(test)]
84mod tests {
85 use std::collections::HashMap;
86 use std::str::FromStr;
87
88 use cdk_common::database::MintProofsDatabase;
89 use cdk_common::nuts::{Id, Proof, State};
90 use cdk_common::secret::Secret;
91 use cdk_common::{Amount, MintInfo, SecretKey};
92
93 use super::new_with_state;
94
95 fn make_proof(keyset_id: Id, amount: u64) -> Proof {
96 Proof {
97 amount: Amount::from(amount),
98 keyset_id,
99 secret: Secret::generate(),
100 c: SecretKey::generate().public_key(),
101 witness: None,
102 dleq: None,
103 p2pk_e: None,
104 }
105 }
106
107 #[tokio::test]
108 async fn new_with_state_restores_spent_proofs_as_spent() {
109 let keyset_id = Id::from_str("00916bbf7ef91a36").expect("valid keyset id");
110 let pending_proofs = vec![make_proof(keyset_id, 1)];
111 let spent_proofs = vec![make_proof(keyset_id, 2), make_proof(keyset_id, 4)];
112 let spent_ys = spent_proofs
113 .iter()
114 .map(|proof| proof.y().expect("valid proof y"))
115 .collect::<Vec<_>>();
116
117 let db = new_with_state(
118 HashMap::new(),
119 vec![],
120 vec![],
121 vec![],
122 pending_proofs,
123 spent_proofs,
124 MintInfo::default(),
125 )
126 .await
127 .expect("valid db");
128
129 let states = db.get_proofs_states(&spent_ys).await.expect("proof states");
130
131 assert_eq!(states, vec![Some(State::Spent), Some(State::Spent)]);
132 }
133
134 #[tokio::test]
135 async fn new_with_state_restores_pending_proofs_without_spent_proofs() {
136 let keyset_id = Id::from_str("00916bbf7ef91a36").expect("valid keyset id");
137 let pending_proofs = vec![make_proof(keyset_id, 1), make_proof(keyset_id, 2)];
138 let pending_ys = pending_proofs
139 .iter()
140 .map(|proof| proof.y().expect("valid proof y"))
141 .collect::<Vec<_>>();
142
143 let db = new_with_state(
144 HashMap::new(),
145 vec![],
146 vec![],
147 vec![],
148 pending_proofs,
149 vec![],
150 MintInfo::default(),
151 )
152 .await
153 .expect("valid db");
154
155 let states = db
156 .get_proofs_states(&pending_ys)
157 .await
158 .expect("proof states");
159
160 assert_eq!(states, vec![Some(State::Pending), Some(State::Pending)]);
161 }
162}