1use std::cmp::Ordering;
4use std::collections::HashMap;
5use std::path::Path;
6use std::str::FromStr;
7use std::sync::Arc;
8
9use async_trait::async_trait;
10use cdk_common::common::{LnKey, QuoteTTL};
11use cdk_common::database::{self, MintDatabase};
12use cdk_common::dhke::hash_to_curve;
13use cdk_common::mint::{self, MintKeySetInfo, MintQuote};
14use cdk_common::nut00::ProofsMethods;
15use cdk_common::{
16 BlindSignature, CurrencyUnit, Id, MeltBolt11Request, MeltQuoteState, MintInfo, MintQuoteState,
17 Proof, Proofs, PublicKey, State,
18};
19use migrations::{migrate_01_to_02, migrate_04_to_05};
20use redb::{Database, MultimapTableDefinition, ReadableTable, TableDefinition};
21use uuid::Uuid;
22
23use super::error::Error;
24use crate::migrations::migrate_00_to_01;
25use crate::mint::migrations::{migrate_02_to_03, migrate_03_to_04};
26
27mod migrations;
28
29const ACTIVE_KEYSETS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("active_keysets");
30const KEYSETS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("keysets");
31const MINT_QUOTES_TABLE: TableDefinition<[u8; 16], &str> = TableDefinition::new("mint_quotes");
32const MELT_QUOTES_TABLE: TableDefinition<[u8; 16], &str> = TableDefinition::new("melt_quotes");
33const PROOFS_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("proofs");
34const PROOFS_STATE_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("proofs_state");
35const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config");
36const BLINDED_SIGNATURES: TableDefinition<[u8; 33], &str> =
38 TableDefinition::new("blinded_signatures");
39const QUOTE_PROOFS_TABLE: MultimapTableDefinition<[u8; 16], [u8; 33]> =
40 MultimapTableDefinition::new("quote_proofs");
41const QUOTE_SIGNATURES_TABLE: MultimapTableDefinition<[u8; 16], [u8; 33]> =
42 MultimapTableDefinition::new("quote_signatures");
43
44const MELT_REQUESTS: TableDefinition<[u8; 16], (&str, &str)> =
45 TableDefinition::new("melt_requests");
46
47const DATABASE_VERSION: u32 = 5;
48
49#[derive(Debug, Clone)]
51pub struct MintRedbDatabase {
52 db: Arc<Database>,
53}
54
55impl MintRedbDatabase {
56 pub fn new(path: &Path) -> Result<Self, Error> {
58 {
59 let db = Arc::new(Database::create(path)?);
62
63 let read_txn = db.begin_read()?;
65 let table = read_txn.open_table(CONFIG_TABLE);
66
67 let db_version = match table {
68 Ok(table) => table.get("db_version")?.map(|v| v.value().to_owned()),
69 Err(_) => None,
70 };
71 match db_version {
72 Some(db_version) => {
73 let mut current_file_version = u32::from_str(&db_version)?;
74 match current_file_version.cmp(&DATABASE_VERSION) {
75 Ordering::Less => {
76 tracing::info!(
77 "Database needs to be upgraded at {} current is {}",
78 current_file_version,
79 DATABASE_VERSION
80 );
81 if current_file_version == 0 {
82 current_file_version = migrate_00_to_01(Arc::clone(&db))?;
83 }
84
85 if current_file_version == 1 {
86 current_file_version = migrate_01_to_02(Arc::clone(&db))?;
87 }
88
89 if current_file_version == 2 {
90 current_file_version = migrate_02_to_03(Arc::clone(&db))?;
91 }
92
93 if current_file_version == 3 {
94 current_file_version = migrate_03_to_04(Arc::clone(&db))?;
95 }
96
97 if current_file_version == 4 {
98 current_file_version = migrate_04_to_05(Arc::clone(&db))?;
99 }
100
101 if current_file_version != DATABASE_VERSION {
102 tracing::warn!(
103 "Database upgrade did not complete at {} current is {}",
104 current_file_version,
105 DATABASE_VERSION
106 );
107 return Err(Error::UnknownDatabaseVersion);
108 }
109
110 let write_txn = db.begin_write()?;
111 {
112 let mut table = write_txn.open_table(CONFIG_TABLE)?;
113
114 table
115 .insert("db_version", DATABASE_VERSION.to_string().as_str())?;
116 }
117
118 write_txn.commit()?;
119 }
120 Ordering::Equal => {
121 tracing::info!("Database is at current version {}", DATABASE_VERSION);
122 }
123 Ordering::Greater => {
124 tracing::warn!(
125 "Database upgrade did not complete at {} current is {}",
126 current_file_version,
127 DATABASE_VERSION
128 );
129 return Err(Error::UnknownDatabaseVersion);
130 }
131 }
132 }
133 None => {
134 let write_txn = db.begin_write()?;
135 {
136 let mut table = write_txn.open_table(CONFIG_TABLE)?;
137 let _ = write_txn.open_table(ACTIVE_KEYSETS_TABLE)?;
139 let _ = write_txn.open_table(KEYSETS_TABLE)?;
140 let _ = write_txn.open_table(MINT_QUOTES_TABLE)?;
141 let _ = write_txn.open_table(MELT_QUOTES_TABLE)?;
142 let _ = write_txn.open_table(PROOFS_TABLE)?;
143 let _ = write_txn.open_table(PROOFS_STATE_TABLE)?;
144 let _ = write_txn.open_table(BLINDED_SIGNATURES)?;
145 let _ = write_txn.open_multimap_table(QUOTE_PROOFS_TABLE)?;
146 let _ = write_txn.open_multimap_table(QUOTE_SIGNATURES_TABLE)?;
147
148 table.insert("db_version", DATABASE_VERSION.to_string().as_str())?;
149 }
150
151 write_txn.commit()?;
152 }
153 }
154 drop(db);
155 }
156
157 let db = Database::create(path)?;
158 Ok(Self { db: Arc::new(db) })
159 }
160}
161
162#[async_trait]
163impl MintDatabase for MintRedbDatabase {
164 type Err = database::Error;
165
166 async fn set_active_keyset(&self, unit: CurrencyUnit, id: Id) -> Result<(), Self::Err> {
167 let write_txn = self.db.begin_write().map_err(Error::from)?;
168
169 {
170 let mut table = write_txn
171 .open_table(ACTIVE_KEYSETS_TABLE)
172 .map_err(Error::from)?;
173 table
174 .insert(unit.to_string().as_str(), id.to_string().as_str())
175 .map_err(Error::from)?;
176 }
177 write_txn.commit().map_err(Error::from)?;
178
179 Ok(())
180 }
181
182 async fn get_active_keyset_id(&self, unit: &CurrencyUnit) -> Result<Option<Id>, Self::Err> {
183 let read_txn = self.db.begin_read().map_err(Error::from)?;
184 let table = read_txn
185 .open_table(ACTIVE_KEYSETS_TABLE)
186 .map_err(Error::from)?;
187
188 if let Some(id) = table.get(unit.to_string().as_str()).map_err(Error::from)? {
189 return Ok(Some(Id::from_str(id.value()).map_err(Error::from)?));
190 }
191
192 Ok(None)
193 }
194
195 async fn get_active_keysets(&self) -> Result<HashMap<CurrencyUnit, Id>, Self::Err> {
196 let read_txn = self.db.begin_read().map_err(Error::from)?;
197 let table = read_txn
198 .open_table(ACTIVE_KEYSETS_TABLE)
199 .map_err(Error::from)?;
200
201 let mut active_keysets = HashMap::new();
202
203 for (unit, id) in (table.iter().map_err(Error::from)?).flatten() {
204 let unit = CurrencyUnit::from_str(unit.value())?;
205 let id = Id::from_str(id.value()).map_err(Error::from)?;
206
207 active_keysets.insert(unit, id);
208 }
209
210 Ok(active_keysets)
211 }
212
213 async fn add_keyset_info(&self, keyset: MintKeySetInfo) -> Result<(), Self::Err> {
214 let write_txn = self.db.begin_write().map_err(Error::from)?;
215
216 {
217 let mut table = write_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
218 table
219 .insert(
220 keyset.id.to_string().as_str(),
221 serde_json::to_string(&keyset)
222 .map_err(Error::from)?
223 .as_str(),
224 )
225 .map_err(Error::from)?;
226 }
227 write_txn.commit().map_err(Error::from)?;
228
229 Ok(())
230 }
231
232 async fn get_keyset_info(&self, keyset_id: &Id) -> Result<Option<MintKeySetInfo>, Self::Err> {
233 let read_txn = self.db.begin_read().map_err(Error::from)?;
234 let table = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
235
236 match table
237 .get(keyset_id.to_string().as_str())
238 .map_err(Error::from)?
239 {
240 Some(keyset) => Ok(serde_json::from_str(keyset.value()).map_err(Error::from)?),
241 None => Ok(None),
242 }
243 }
244
245 async fn get_keyset_infos(&self) -> Result<Vec<MintKeySetInfo>, Self::Err> {
246 let read_txn = self.db.begin_read().map_err(Error::from)?;
247 let table = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
248
249 let mut keysets = Vec::new();
250
251 for (_id, keyset) in (table.iter().map_err(Error::from)?).flatten() {
252 let keyset = serde_json::from_str(keyset.value()).map_err(Error::from)?;
253
254 keysets.push(keyset)
255 }
256
257 Ok(keysets)
258 }
259
260 async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err> {
261 let write_txn = self.db.begin_write().map_err(Error::from)?;
262
263 {
264 let mut table = write_txn
265 .open_table(MINT_QUOTES_TABLE)
266 .map_err(Error::from)?;
267 table
268 .insert(
269 quote.id.as_bytes(),
270 serde_json::to_string("e).map_err(Error::from)?.as_str(),
271 )
272 .map_err(Error::from)?;
273 }
274 write_txn.commit().map_err(Error::from)?;
275
276 Ok(())
277 }
278
279 async fn get_mint_quote(&self, quote_id: &Uuid) -> Result<Option<MintQuote>, Self::Err> {
280 let read_txn = self.db.begin_read().map_err(Error::from)?;
281 let table = read_txn
282 .open_table(MINT_QUOTES_TABLE)
283 .map_err(Error::from)?;
284
285 match table.get(quote_id.as_bytes()).map_err(Error::from)? {
286 Some(quote) => Ok(serde_json::from_str(quote.value()).map_err(Error::from)?),
287 None => Ok(None),
288 }
289 }
290
291 async fn update_mint_quote_state(
292 &self,
293 quote_id: &Uuid,
294 state: MintQuoteState,
295 ) -> Result<MintQuoteState, Self::Err> {
296 let write_txn = self.db.begin_write().map_err(Error::from)?;
297
298 let current_state;
299 {
300 let mut mint_quote: MintQuote;
301 let mut table = write_txn
302 .open_table(MINT_QUOTES_TABLE)
303 .map_err(Error::from)?;
304 {
305 let quote_guard = table
306 .get(quote_id.as_bytes())
307 .map_err(Error::from)?
308 .ok_or(Error::UnknownQuote)?;
309
310 let quote = quote_guard.value();
311
312 mint_quote = serde_json::from_str(quote).map_err(Error::from)?;
313 }
314
315 current_state = mint_quote.state;
316 mint_quote.state = state;
317
318 {
319 table
320 .insert(
321 quote_id.as_bytes(),
322 serde_json::to_string(&mint_quote)
323 .map_err(Error::from)?
324 .as_str(),
325 )
326 .map_err(Error::from)?;
327 }
328 }
329 write_txn.commit().map_err(Error::from)?;
330
331 Ok(current_state)
332 }
333 async fn get_mint_quote_by_request(
334 &self,
335 request: &str,
336 ) -> Result<Option<MintQuote>, Self::Err> {
337 let quotes = self.get_mint_quotes().await?;
338
339 let quote = quotes
340 .into_iter()
341 .filter(|q| q.request.eq(request))
342 .collect::<Vec<MintQuote>>()
343 .first()
344 .cloned();
345
346 Ok(quote)
347 }
348
349 async fn get_mint_quote_by_request_lookup_id(
350 &self,
351 request_lookup_id: &str,
352 ) -> Result<Option<MintQuote>, Self::Err> {
353 let quotes = self.get_mint_quotes().await?;
354
355 let quote = quotes
356 .into_iter()
357 .filter(|q| q.request_lookup_id.eq(request_lookup_id))
358 .collect::<Vec<MintQuote>>()
359 .first()
360 .cloned();
361
362 Ok(quote)
363 }
364
365 async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err> {
366 let read_txn = self.db.begin_read().map_err(Error::from)?;
367 let table = read_txn
368 .open_table(MINT_QUOTES_TABLE)
369 .map_err(Error::from)?;
370
371 let mut quotes = Vec::new();
372
373 for (_id, quote) in (table.iter().map_err(Error::from)?).flatten() {
374 let quote = serde_json::from_str(quote.value()).map_err(Error::from)?;
375
376 quotes.push(quote)
377 }
378
379 Ok(quotes)
380 }
381
382 async fn get_mint_quotes_with_state(
383 &self,
384 state: MintQuoteState,
385 ) -> Result<Vec<MintQuote>, Self::Err> {
386 let read_txn = self.db.begin_read().map_err(Error::from)?;
387 let table = read_txn
388 .open_table(MINT_QUOTES_TABLE)
389 .map_err(Error::from)?;
390
391 let mut quotes = Vec::new();
392
393 for (_id, quote) in (table.iter().map_err(Error::from)?).flatten() {
394 let quote: MintQuote = serde_json::from_str(quote.value()).map_err(Error::from)?;
395
396 if quote.state == state {
397 quotes.push(quote)
398 }
399 }
400
401 Ok(quotes)
402 }
403
404 async fn remove_mint_quote(&self, quote_id: &Uuid) -> Result<(), Self::Err> {
405 let write_txn = self.db.begin_write().map_err(Error::from)?;
406
407 {
408 let mut table = write_txn
409 .open_table(MINT_QUOTES_TABLE)
410 .map_err(Error::from)?;
411 table.remove(quote_id.as_bytes()).map_err(Error::from)?;
412 }
413 write_txn.commit().map_err(Error::from)?;
414
415 Ok(())
416 }
417
418 async fn add_melt_quote(&self, quote: mint::MeltQuote) -> Result<(), Self::Err> {
419 let write_txn = self.db.begin_write().map_err(Error::from)?;
420
421 {
422 let mut table = write_txn
423 .open_table(MELT_QUOTES_TABLE)
424 .map_err(Error::from)?;
425 table
426 .insert(
427 quote.id.as_bytes(),
428 serde_json::to_string("e).map_err(Error::from)?.as_str(),
429 )
430 .map_err(Error::from)?;
431 }
432 write_txn.commit().map_err(Error::from)?;
433
434 Ok(())
435 }
436
437 async fn get_melt_quote(&self, quote_id: &Uuid) -> Result<Option<mint::MeltQuote>, Self::Err> {
438 let read_txn = self.db.begin_read().map_err(Error::from)?;
439 let table = read_txn
440 .open_table(MELT_QUOTES_TABLE)
441 .map_err(Error::from)?;
442
443 let quote = table.get(quote_id.as_bytes()).map_err(Error::from)?;
444
445 Ok(quote.map(|q| serde_json::from_str(q.value()).unwrap()))
446 }
447
448 async fn update_melt_quote_state(
449 &self,
450 quote_id: &Uuid,
451 state: MeltQuoteState,
452 ) -> Result<MeltQuoteState, Self::Err> {
453 let write_txn = self.db.begin_write().map_err(Error::from)?;
454
455 let current_state;
456 {
457 let mut melt_quote: mint::MeltQuote;
458 let mut table = write_txn
459 .open_table(MELT_QUOTES_TABLE)
460 .map_err(Error::from)?;
461 {
462 let quote_guard = table
463 .get(quote_id.as_bytes())
464 .map_err(Error::from)?
465 .ok_or(Error::UnknownQuote)?;
466
467 let quote = quote_guard.value();
468
469 melt_quote = serde_json::from_str(quote).map_err(Error::from)?;
470 }
471
472 current_state = melt_quote.state;
473 melt_quote.state = state;
474
475 {
476 table
477 .insert(
478 quote_id.as_bytes(),
479 serde_json::to_string(&melt_quote)
480 .map_err(Error::from)?
481 .as_str(),
482 )
483 .map_err(Error::from)?;
484 }
485 }
486 write_txn.commit().map_err(Error::from)?;
487
488 Ok(current_state)
489 }
490
491 async fn get_melt_quotes(&self) -> Result<Vec<mint::MeltQuote>, Self::Err> {
492 let read_txn = self.db.begin_read().map_err(Error::from)?;
493 let table = read_txn
494 .open_table(MELT_QUOTES_TABLE)
495 .map_err(Error::from)?;
496
497 let mut quotes = Vec::new();
498
499 for (_id, quote) in (table.iter().map_err(Error::from)?).flatten() {
500 let quote = serde_json::from_str(quote.value()).map_err(Error::from)?;
501
502 quotes.push(quote)
503 }
504
505 Ok(quotes)
506 }
507
508 async fn remove_melt_quote(&self, quote_id: &Uuid) -> Result<(), Self::Err> {
509 let write_txn = self.db.begin_write().map_err(Error::from)?;
510
511 {
512 let mut table = write_txn
513 .open_table(MELT_QUOTES_TABLE)
514 .map_err(Error::from)?;
515 table.remove(quote_id.as_bytes()).map_err(Error::from)?;
516 }
517 write_txn.commit().map_err(Error::from)?;
518
519 Ok(())
520 }
521
522 async fn add_proofs(&self, proofs: Proofs, quote_id: Option<Uuid>) -> Result<(), Self::Err> {
523 let write_txn = self.db.begin_write().map_err(Error::from)?;
524
525 {
526 let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
527 let mut quote_proofs_table = write_txn
528 .open_multimap_table(QUOTE_PROOFS_TABLE)
529 .map_err(Error::from)?;
530 for proof in proofs {
531 let y: PublicKey = hash_to_curve(&proof.secret.to_bytes()).map_err(Error::from)?;
532 let y = y.to_bytes();
533 if table.get(y).map_err(Error::from)?.is_none() {
534 table
535 .insert(
536 y,
537 serde_json::to_string(&proof).map_err(Error::from)?.as_str(),
538 )
539 .map_err(Error::from)?;
540 }
541
542 if let Some(quote_id) = "e_id {
543 quote_proofs_table
544 .insert(quote_id.as_bytes(), y)
545 .map_err(Error::from)?;
546 }
547 }
548 }
549 write_txn.commit().map_err(Error::from)?;
550
551 Ok(())
552 }
553
554 async fn remove_proofs(
555 &self,
556 ys: &[PublicKey],
557 quote_id: Option<Uuid>,
558 ) -> Result<(), Self::Err> {
559 let write_txn = self.db.begin_write().map_err(Error::from)?;
560
561 {
562 let mut proofs_table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
563
564 for y in ys {
565 proofs_table.remove(&y.to_bytes()).map_err(Error::from)?;
566 }
567 }
568
569 {
570 let mut proof_state_table = write_txn
571 .open_table(PROOFS_STATE_TABLE)
572 .map_err(Error::from)?;
573 for y in ys {
574 proof_state_table
575 .remove(&y.to_bytes())
576 .map_err(Error::from)?;
577 }
578 }
579
580 if let Some(quote_id) = quote_id {
581 let mut quote_proofs_table = write_txn
582 .open_multimap_table(QUOTE_PROOFS_TABLE)
583 .map_err(Error::from)?;
584
585 quote_proofs_table
586 .remove_all(quote_id.as_bytes())
587 .map_err(Error::from)?;
588 }
589
590 write_txn.commit().map_err(Error::from)?;
591
592 Ok(())
593 }
594
595 async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result<Vec<Option<Proof>>, Self::Err> {
596 let read_txn = self.db.begin_read().map_err(Error::from)?;
597 let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
598
599 let mut proofs = Vec::with_capacity(ys.len());
600
601 for y in ys {
602 match table.get(y.to_bytes()).map_err(Error::from)? {
603 Some(proof) => proofs.push(Some(
604 serde_json::from_str(proof.value()).map_err(Error::from)?,
605 )),
606 None => proofs.push(None),
607 }
608 }
609
610 Ok(proofs)
611 }
612
613 async fn get_proof_ys_by_quote_id(&self, quote_id: &Uuid) -> Result<Vec<PublicKey>, Self::Err> {
614 let read_txn = self.db.begin_read().map_err(Error::from)?;
615 let table = read_txn
616 .open_multimap_table(QUOTE_PROOFS_TABLE)
617 .map_err(Error::from)?;
618
619 let ys = table.get(quote_id.as_bytes()).map_err(Error::from)?;
620
621 let proof_ys = ys.fold(Vec::new(), |mut acc, y| {
622 if let Ok(y) = y {
623 if let Ok(pubkey) = PublicKey::from_slice(&y.value()) {
624 acc.push(pubkey);
625 }
626 }
627 acc
628 });
629
630 Ok(proof_ys)
631 }
632
633 async fn get_proofs_states(&self, ys: &[PublicKey]) -> Result<Vec<Option<State>>, Self::Err> {
634 let read_txn = self.db.begin_read().map_err(Error::from)?;
635 let table = read_txn
636 .open_table(PROOFS_STATE_TABLE)
637 .map_err(Error::from)?;
638
639 let mut states = Vec::with_capacity(ys.len());
640
641 for y in ys {
642 match table.get(y.to_bytes()).map_err(Error::from)? {
643 Some(state) => states.push(Some(
644 serde_json::from_str(state.value()).map_err(Error::from)?,
645 )),
646 None => states.push(None),
647 }
648 }
649
650 Ok(states)
651 }
652
653 async fn get_proofs_by_keyset_id(
654 &self,
655 keyset_id: &Id,
656 ) -> Result<(Proofs, Vec<Option<State>>), Self::Err> {
657 let read_txn = self.db.begin_read().map_err(Error::from)?;
658 let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
659
660 let proofs_for_id = table
661 .iter()
662 .map_err(Error::from)?
663 .flatten()
664 .map(|(_, p)| serde_json::from_str::<Proof>(p.value()))
665 .collect::<Result<Proofs, _>>()?
666 .into_iter()
667 .filter(|p| &p.keyset_id == keyset_id)
668 .collect::<Proofs>();
669
670 let proof_ys = proofs_for_id.ys()?;
671
672 assert_eq!(proofs_for_id.len(), proof_ys.len());
673
674 let states = self.get_proofs_states(&proof_ys).await?;
675
676 Ok((proofs_for_id, states))
677 }
678
679 async fn update_proofs_states(
680 &self,
681 ys: &[PublicKey],
682 proofs_state: State,
683 ) -> Result<Vec<Option<State>>, Self::Err> {
684 let write_txn = self.db.begin_write().map_err(Error::from)?;
685
686 let mut states = Vec::with_capacity(ys.len());
687
688 let state_str = serde_json::to_string(&proofs_state).map_err(Error::from)?;
689
690 {
691 let mut table = write_txn
692 .open_table(PROOFS_STATE_TABLE)
693 .map_err(Error::from)?;
694
695 for y in ys {
696 let current_state;
697
698 {
699 match table.get(y.to_bytes()).map_err(Error::from)? {
700 Some(state) => {
701 current_state =
702 Some(serde_json::from_str(state.value()).map_err(Error::from)?)
703 }
704 None => current_state = None,
705 }
706 }
707 states.push(current_state);
708
709 if current_state != Some(State::Spent) {
710 table
711 .insert(y.to_bytes(), state_str.as_str())
712 .map_err(Error::from)?;
713 }
714 }
715 }
716
717 write_txn.commit().map_err(Error::from)?;
718
719 Ok(states)
720 }
721
722 async fn add_blind_signatures(
723 &self,
724 blinded_messages: &[PublicKey],
725 blind_signatures: &[BlindSignature],
726 quote_id: Option<Uuid>,
727 ) -> Result<(), Self::Err> {
728 let write_txn = self.db.begin_write().map_err(Error::from)?;
729
730 {
731 let mut table = write_txn
732 .open_table(BLINDED_SIGNATURES)
733 .map_err(Error::from)?;
734 let mut quote_sigs_table = write_txn
735 .open_multimap_table(QUOTE_SIGNATURES_TABLE)
736 .map_err(Error::from)?;
737
738 for (blinded_message, blind_signature) in blinded_messages.iter().zip(blind_signatures)
739 {
740 let blind_sig = serde_json::to_string(&blind_signature).map_err(Error::from)?;
741 table
742 .insert(blinded_message.to_bytes(), blind_sig.as_str())
743 .map_err(Error::from)?;
744
745 if let Some(quote_id) = "e_id {
746 quote_sigs_table
747 .insert(quote_id.as_bytes(), blinded_message.to_bytes())
748 .map_err(Error::from)?;
749 }
750 }
751 }
752
753 write_txn.commit().map_err(Error::from)?;
754
755 Ok(())
756 }
757
758 async fn get_blind_signatures(
759 &self,
760 blinded_messages: &[PublicKey],
761 ) -> Result<Vec<Option<BlindSignature>>, Self::Err> {
762 let read_txn = self.db.begin_read().map_err(Error::from)?;
763 let table = read_txn
764 .open_table(BLINDED_SIGNATURES)
765 .map_err(Error::from)?;
766
767 let mut signatures = Vec::with_capacity(blinded_messages.len());
768
769 for blinded_message in blinded_messages {
770 match table.get(blinded_message.to_bytes()).map_err(Error::from)? {
771 Some(blind_signature) => signatures.push(Some(
772 serde_json::from_str(blind_signature.value()).map_err(Error::from)?,
773 )),
774 None => signatures.push(None),
775 }
776 }
777
778 Ok(signatures)
779 }
780
781 async fn get_blind_signatures_for_keyset(
782 &self,
783 keyset_id: &Id,
784 ) -> Result<Vec<BlindSignature>, Self::Err> {
785 let read_txn = self.db.begin_read().map_err(Error::from)?;
786 let table = read_txn
787 .open_table(BLINDED_SIGNATURES)
788 .map_err(Error::from)?;
789
790 Ok(table
791 .iter()
792 .map_err(Error::from)?
793 .flatten()
794 .filter_map(|(_m, s)| {
795 match serde_json::from_str::<BlindSignature>(s.value()).ok() {
796 Some(signature) if &signature.keyset_id == keyset_id => Some(signature), _ => None, }
799 })
800 .collect())
801 }
802
803 async fn add_melt_request(
805 &self,
806 melt_request: MeltBolt11Request<Uuid>,
807 ln_key: LnKey,
808 ) -> Result<(), Self::Err> {
809 let write_txn = self.db.begin_write().map_err(Error::from)?;
810 let mut table = write_txn.open_table(MELT_REQUESTS).map_err(Error::from)?;
811
812 table
813 .insert(
814 melt_request.quote.as_bytes(),
815 (
816 serde_json::to_string(&melt_request)?.as_str(),
817 serde_json::to_string(&ln_key)?.as_str(),
818 ),
819 )
820 .map_err(Error::from)?;
821
822 Ok(())
823 }
824 async fn get_melt_request(
826 &self,
827 quote_id: &Uuid,
828 ) -> Result<Option<(MeltBolt11Request<Uuid>, LnKey)>, Self::Err> {
829 let read_txn = self.db.begin_read().map_err(Error::from)?;
830 let table = read_txn.open_table(MELT_REQUESTS).map_err(Error::from)?;
831
832 match table.get(quote_id.as_bytes()).map_err(Error::from)? {
833 Some(melt_request) => {
834 let (melt_request_str, ln_key_str) = melt_request.value();
835 let melt_request = serde_json::from_str(melt_request_str)?;
836 let ln_key = serde_json::from_str(ln_key_str)?;
837
838 Ok(Some((melt_request, ln_key)))
839 }
840 None => Ok(None),
841 }
842 }
843
844 async fn get_blind_signatures_for_quote(
846 &self,
847 quote_id: &Uuid,
848 ) -> Result<Vec<BlindSignature>, Self::Err> {
849 let read_txn = self.db.begin_read().map_err(Error::from)?;
850 let quote_proofs_table = read_txn
851 .open_multimap_table(QUOTE_SIGNATURES_TABLE)
852 .map_err(Error::from)?;
853
854 let ys = quote_proofs_table.get(quote_id.as_bytes()).unwrap();
855
856 let ys: Vec<[u8; 33]> = ys.into_iter().flatten().map(|v| v.value()).collect();
857
858 let mut signatures = Vec::new();
859
860 let signatures_table = read_txn
861 .open_table(BLINDED_SIGNATURES)
862 .map_err(Error::from)?;
863
864 for y in ys {
865 if let Some(sig) = signatures_table.get(y).map_err(Error::from)? {
866 let sig = serde_json::from_str(sig.value())?;
867 signatures.push(sig);
868 }
869 }
870
871 Ok(signatures)
872 }
873
874 async fn set_mint_info(&self, mint_info: MintInfo) -> Result<(), Self::Err> {
875 let write_txn = self.db.begin_write().map_err(Error::from)?;
876
877 {
878 let mut table = write_txn.open_table(CONFIG_TABLE).map_err(Error::from)?;
879 table
880 .insert("mint_info", serde_json::to_string(&mint_info)?.as_str())
881 .map_err(Error::from)?;
882 }
883 write_txn.commit().map_err(Error::from)?;
884
885 Ok(())
886 }
887 async fn get_mint_info(&self) -> Result<MintInfo, Self::Err> {
888 let read_txn = self.db.begin_read().map_err(Error::from)?;
889 let table = read_txn.open_table(CONFIG_TABLE).map_err(Error::from)?;
890
891 if let Some(mint_info) = table.get("mint_info").map_err(Error::from)? {
892 let mint_info = serde_json::from_str(mint_info.value())?;
893
894 return Ok(mint_info);
895 }
896
897 Err(Error::UnknownMintInfo.into())
898 }
899
900 async fn set_quote_ttl(&self, quote_ttl: QuoteTTL) -> Result<(), Self::Err> {
901 let write_txn = self.db.begin_write().map_err(Error::from)?;
902
903 {
904 let mut table = write_txn.open_table(CONFIG_TABLE).map_err(Error::from)?;
905 table
906 .insert("quote_ttl", serde_json::to_string("e_ttl)?.as_str())
907 .map_err(Error::from)?;
908 }
909 write_txn.commit().map_err(Error::from)?;
910
911 Ok(())
912 }
913 async fn get_quote_ttl(&self) -> Result<QuoteTTL, Self::Err> {
914 let read_txn = self.db.begin_read().map_err(Error::from)?;
915 let table = read_txn.open_table(CONFIG_TABLE).map_err(Error::from)?;
916
917 if let Some(quote_ttl) = table.get("quote_ttl").map_err(Error::from)? {
918 let quote_ttl = serde_json::from_str(quote_ttl.value())?;
919
920 return Ok(quote_ttl);
921 }
922
923 Err(Error::UnknownQuoteTTL.into())
924 }
925}