migrations.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. use core::str;
  2. use std::collections::HashMap;
  3. use std::str::FromStr;
  4. use std::sync::Arc;
  5. use cdk::mint::MintQuote;
  6. use cdk::nuts::{CurrencyUnit, MintQuoteState, Proof, State};
  7. use cdk::{Amount, UncheckedUrl};
  8. use lightning_invoice::Bolt11Invoice;
  9. use redb::{Database, ReadableTable, TableDefinition};
  10. use serde::{Deserialize, Serialize};
  11. use super::{Error, PROOFS_STATE_TABLE, PROOFS_TABLE};
  12. const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
  13. const PENDING_PROOFS_TABLE: TableDefinition<[u8; 33], &str> =
  14. TableDefinition::new("pending_proofs");
  15. const SPENT_PROOFS_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("spent_proofs");
  16. pub fn migrate_01_to_02(db: Arc<Database>) -> Result<u32, Error> {
  17. migrate_mint_quotes_01_to_02(db)?;
  18. Ok(2)
  19. }
  20. pub fn migrate_02_to_03(db: Arc<Database>) -> Result<u32, Error> {
  21. migrate_mint_proofs_02_to_03(db)?;
  22. Ok(3)
  23. }
  24. /// Mint Quote Info
  25. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
  26. struct V1MintQuote {
  27. pub id: String,
  28. pub mint_url: UncheckedUrl,
  29. pub amount: Amount,
  30. pub unit: CurrencyUnit,
  31. pub request: String,
  32. pub state: MintQuoteState,
  33. pub expiry: u64,
  34. }
  35. impl From<V1MintQuote> for MintQuote {
  36. fn from(quote: V1MintQuote) -> MintQuote {
  37. MintQuote {
  38. id: quote.id,
  39. mint_url: quote.mint_url,
  40. amount: quote.amount,
  41. unit: quote.unit,
  42. request: quote.request.clone(),
  43. state: quote.state,
  44. expiry: quote.expiry,
  45. request_lookup_id: Bolt11Invoice::from_str(&quote.request).unwrap().to_string(),
  46. }
  47. }
  48. }
  49. fn migrate_mint_quotes_01_to_02(db: Arc<Database>) -> Result<(), Error> {
  50. let read_txn = db.begin_read().map_err(Error::from)?;
  51. let table = read_txn
  52. .open_table(MINT_QUOTES_TABLE)
  53. .map_err(Error::from)?;
  54. let mint_quotes: HashMap<String, Option<V1MintQuote>>;
  55. {
  56. mint_quotes = table
  57. .iter()
  58. .map_err(Error::from)?
  59. .flatten()
  60. .map(|(quote_id, mint_quote)| {
  61. (
  62. quote_id.value().to_string(),
  63. serde_json::from_str(mint_quote.value()).ok(),
  64. )
  65. })
  66. .collect();
  67. }
  68. let migrated_mint_quotes: HashMap<String, Option<MintQuote>> = mint_quotes
  69. .into_iter()
  70. .map(|(quote_id, quote)| (quote_id, quote.map(|q| q.into())))
  71. .collect();
  72. {
  73. let write_txn = db.begin_write()?;
  74. {
  75. let mut table = write_txn
  76. .open_table(MINT_QUOTES_TABLE)
  77. .map_err(Error::from)?;
  78. for (quote_id, quote) in migrated_mint_quotes {
  79. match quote {
  80. Some(quote) => {
  81. let quote_str = serde_json::to_string(&quote)?;
  82. table.insert(quote_id.as_str(), quote_str.as_str())?;
  83. }
  84. None => {
  85. table.remove(quote_id.as_str())?;
  86. }
  87. }
  88. }
  89. }
  90. write_txn.commit()?;
  91. }
  92. Ok(())
  93. }
  94. fn migrate_mint_proofs_02_to_03(db: Arc<Database>) -> Result<(), Error> {
  95. let pending_proofs: Vec<([u8; 33], Option<Proof>)>;
  96. let spent_proofs: Vec<([u8; 33], Option<Proof>)>;
  97. {
  98. let read_txn = db.begin_read().map_err(Error::from)?;
  99. let table = read_txn
  100. .open_table(PENDING_PROOFS_TABLE)
  101. .map_err(Error::from)?;
  102. pending_proofs = table
  103. .iter()
  104. .map_err(Error::from)?
  105. .flatten()
  106. .map(|(quote_id, mint_quote)| {
  107. (
  108. quote_id.value(),
  109. serde_json::from_str(mint_quote.value()).ok(),
  110. )
  111. })
  112. .collect();
  113. }
  114. {
  115. let read_txn = db.begin_read().map_err(Error::from)?;
  116. let table = read_txn
  117. .open_table(SPENT_PROOFS_TABLE)
  118. .map_err(Error::from)?;
  119. spent_proofs = table
  120. .iter()
  121. .map_err(Error::from)?
  122. .flatten()
  123. .map(|(quote_id, mint_quote)| {
  124. (
  125. quote_id.value(),
  126. serde_json::from_str(mint_quote.value()).ok(),
  127. )
  128. })
  129. .collect();
  130. }
  131. let write_txn = db.begin_write().map_err(Error::from)?;
  132. {
  133. let mut proofs_table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
  134. let mut state_table = write_txn
  135. .open_table(PROOFS_STATE_TABLE)
  136. .map_err(Error::from)?;
  137. for (y, proof) in pending_proofs {
  138. if let Some(proof) = proof {
  139. proofs_table.insert(y, serde_json::to_string(&proof)?.as_str())?;
  140. state_table.insert(y, State::Pending.to_string().as_str())?;
  141. }
  142. }
  143. for (y, proof) in spent_proofs {
  144. if let Some(proof) = proof {
  145. proofs_table.insert(y, serde_json::to_string(&proof)?.as_str())?;
  146. state_table.insert(y, State::Spent.to_string().as_str())?;
  147. }
  148. }
  149. }
  150. write_txn.commit()?;
  151. Ok(())
  152. }