mod.rs 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. //! Redb Wallet
  2. use std::cmp::Ordering;
  3. use std::collections::HashMap;
  4. use std::path::Path;
  5. use std::str::FromStr;
  6. use std::sync::Arc;
  7. use async_trait::async_trait;
  8. use cdk_common::common::ProofInfo;
  9. use cdk_common::database::WalletDatabase;
  10. use cdk_common::mint_url::MintUrl;
  11. use cdk_common::util::unix_time;
  12. use cdk_common::wallet::{self, MintQuote, Transaction, TransactionDirection, TransactionId};
  13. use cdk_common::{
  14. database, CurrencyUnit, Id, KeySet, KeySetInfo, Keys, MintInfo, PublicKey, SpendingConditions,
  15. State,
  16. };
  17. use redb::{Database, MultimapTableDefinition, ReadableTable, TableDefinition};
  18. use tracing::instrument;
  19. use super::error::Error;
  20. use crate::migrations::migrate_00_to_01;
  21. use crate::wallet::migrations::{migrate_01_to_02, migrate_02_to_03, migrate_03_to_04};
  22. mod migrations;
  23. // <Mint_url, Info>
  24. const MINTS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mints_table");
  25. // <Mint_Url, Keyset_id>
  26. const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &[u8]> =
  27. MultimapTableDefinition::new("mint_keysets");
  28. // <Keyset_id, KeysetInfo>
  29. const KEYSETS_TABLE: TableDefinition<&[u8], &str> = TableDefinition::new("keysets");
  30. // <Quote_id, quote>
  31. const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
  32. // <Quote_id, quote>
  33. const MELT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("melt_quotes");
  34. const MINT_KEYS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_keys");
  35. // <Y, Proof Info>
  36. const PROOFS_TABLE: TableDefinition<&[u8], &str> = TableDefinition::new("proofs");
  37. const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config");
  38. const KEYSET_COUNTER: TableDefinition<&str, u32> = TableDefinition::new("keyset_counter");
  39. // <Transaction_id, Transaction>
  40. const TRANSACTIONS_TABLE: TableDefinition<&[u8], &str> = TableDefinition::new("transactions");
  41. const KEYSET_U32_MAPPING: TableDefinition<u32, &str> = TableDefinition::new("keyset_u32_mapping");
  42. const DATABASE_VERSION: u32 = 4;
  43. /// Wallet Redb Database
  44. #[derive(Debug, Clone)]
  45. pub struct WalletRedbDatabase {
  46. db: Arc<Database>,
  47. }
  48. /// Redb Wallet Transaction
  49. pub struct RedbWalletTransaction {
  50. write_txn: Option<redb::WriteTransaction>,
  51. }
  52. impl RedbWalletTransaction {
  53. /// Create a new transaction
  54. fn new(write_txn: redb::WriteTransaction) -> Self {
  55. Self {
  56. write_txn: Some(write_txn),
  57. }
  58. }
  59. /// Get a mutable reference to the write transaction
  60. fn txn(&mut self) -> Result<&mut redb::WriteTransaction, Error> {
  61. self.write_txn.as_mut().ok_or_else(|| {
  62. Error::CDKDatabase(database::Error::Internal(
  63. "Transaction already consumed".to_owned(),
  64. ))
  65. })
  66. }
  67. }
  68. impl WalletRedbDatabase {
  69. /// Create new [`WalletRedbDatabase`]
  70. pub fn new(path: &Path) -> Result<Self, Error> {
  71. {
  72. // Check if parent directory exists before attempting to create database
  73. if let Some(parent) = path.parent() {
  74. if !parent.exists() {
  75. return Err(Error::Io(std::io::Error::new(
  76. std::io::ErrorKind::NotFound,
  77. format!("Parent directory does not exist: {parent:?}"),
  78. )));
  79. }
  80. }
  81. let db = Arc::new(Database::create(path)?);
  82. let db_version: Option<String>;
  83. {
  84. // Check database version
  85. let read_txn = db.begin_read()?;
  86. let table = read_txn.open_table(CONFIG_TABLE);
  87. db_version = match table {
  88. Ok(table) => table.get("db_version")?.map(|v| v.value().to_string()),
  89. Err(_) => None,
  90. };
  91. }
  92. match db_version {
  93. Some(db_version) => {
  94. let mut current_file_version = u32::from_str(&db_version)?;
  95. tracing::info!("Current file version {}", current_file_version);
  96. match current_file_version.cmp(&DATABASE_VERSION) {
  97. Ordering::Less => {
  98. tracing::info!(
  99. "Database needs to be upgraded at {} current is {}",
  100. current_file_version,
  101. DATABASE_VERSION
  102. );
  103. if current_file_version == 0 {
  104. current_file_version = migrate_00_to_01(Arc::clone(&db))?;
  105. }
  106. if current_file_version == 1 {
  107. current_file_version = migrate_01_to_02(Arc::clone(&db))?;
  108. }
  109. if current_file_version == 2 {
  110. current_file_version = migrate_02_to_03(Arc::clone(&db))?;
  111. }
  112. if current_file_version == 3 {
  113. current_file_version = migrate_03_to_04(Arc::clone(&db))?;
  114. }
  115. if current_file_version != DATABASE_VERSION {
  116. tracing::warn!(
  117. "Database upgrade did not complete at {} current is {}",
  118. current_file_version,
  119. DATABASE_VERSION
  120. );
  121. return Err(Error::UnknownDatabaseVersion);
  122. }
  123. let write_txn = db.begin_write()?;
  124. {
  125. let mut table = write_txn.open_table(CONFIG_TABLE)?;
  126. table
  127. .insert("db_version", DATABASE_VERSION.to_string().as_str())?;
  128. }
  129. write_txn.commit()?;
  130. }
  131. Ordering::Equal => {
  132. tracing::info!("Database is at current version {}", DATABASE_VERSION);
  133. }
  134. Ordering::Greater => {
  135. tracing::warn!(
  136. "Database upgrade did not complete at {} current is {}",
  137. current_file_version,
  138. DATABASE_VERSION
  139. );
  140. return Err(Error::UnknownDatabaseVersion);
  141. }
  142. }
  143. }
  144. None => {
  145. let write_txn = db.begin_write()?;
  146. {
  147. let mut table = write_txn.open_table(CONFIG_TABLE)?;
  148. // Open all tables to init a new db
  149. let _ = write_txn.open_table(MINTS_TABLE)?;
  150. let _ = write_txn.open_multimap_table(MINT_KEYSETS_TABLE)?;
  151. let _ = write_txn.open_table(KEYSETS_TABLE)?;
  152. let _ = write_txn.open_table(MINT_QUOTES_TABLE)?;
  153. let _ = write_txn.open_table(MELT_QUOTES_TABLE)?;
  154. let _ = write_txn.open_table(MINT_KEYS_TABLE)?;
  155. let _ = write_txn.open_table(PROOFS_TABLE)?;
  156. let _ = write_txn.open_table(KEYSET_COUNTER)?;
  157. let _ = write_txn.open_table(TRANSACTIONS_TABLE)?;
  158. let _ = write_txn.open_table(KEYSET_U32_MAPPING)?;
  159. table.insert("db_version", DATABASE_VERSION.to_string().as_str())?;
  160. }
  161. write_txn.commit()?;
  162. }
  163. }
  164. drop(db);
  165. }
  166. // Check parent directory again for final database creation
  167. if let Some(parent) = path.parent() {
  168. if !parent.exists() {
  169. return Err(Error::Io(std::io::Error::new(
  170. std::io::ErrorKind::NotFound,
  171. format!("Parent directory does not exist: {parent:?}"),
  172. )));
  173. }
  174. }
  175. let mut db = Database::create(path)?;
  176. db.upgrade()?;
  177. Ok(Self { db: Arc::new(db) })
  178. }
  179. }
  180. #[async_trait]
  181. impl WalletDatabase for WalletRedbDatabase {
  182. type Err = database::Error;
  183. #[instrument(skip(self))]
  184. async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, Self::Err> {
  185. let read_txn = self.db.begin_read().map_err(Into::<Error>::into)?;
  186. let table = read_txn.open_table(MINTS_TABLE).map_err(Error::from)?;
  187. if let Some(mint_info) = table
  188. .get(mint_url.to_string().as_str())
  189. .map_err(Error::from)?
  190. {
  191. return Ok(serde_json::from_str(mint_info.value()).map_err(Error::from)?);
  192. }
  193. Ok(None)
  194. }
  195. #[instrument(skip(self))]
  196. async fn get_mints(&self) -> Result<HashMap<MintUrl, Option<MintInfo>>, Self::Err> {
  197. let read_txn = self.db.begin_read().map_err(Error::from)?;
  198. let table = read_txn.open_table(MINTS_TABLE).map_err(Error::from)?;
  199. let mints = table
  200. .iter()
  201. .map_err(Error::from)?
  202. .flatten()
  203. .filter_map(|(mint, mint_info)| {
  204. MintUrl::from_str(mint.value())
  205. .ok()
  206. .map(|url| (url, serde_json::from_str(mint_info.value()).ok()))
  207. })
  208. .collect();
  209. Ok(mints)
  210. }
  211. #[instrument(skip(self))]
  212. async fn get_mint_keysets(
  213. &self,
  214. mint_url: MintUrl,
  215. ) -> Result<Option<Vec<KeySetInfo>>, Self::Err> {
  216. let read_txn = self.db.begin_read().map_err(Into::<Error>::into)?;
  217. let table = read_txn
  218. .open_multimap_table(MINT_KEYSETS_TABLE)
  219. .map_err(Error::from)?;
  220. let keyset_ids = table
  221. .get(mint_url.to_string().as_str())
  222. .map_err(Error::from)?
  223. .flatten()
  224. .map(|k| Id::from_bytes(k.value()))
  225. .collect::<Result<Vec<_>, _>>()?;
  226. let mut keysets = vec![];
  227. let keysets_t = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
  228. for keyset_id in keyset_ids {
  229. if let Some(keyset) = keysets_t
  230. .get(keyset_id.to_bytes().as_slice())
  231. .map_err(Error::from)?
  232. {
  233. let keyset = serde_json::from_str(keyset.value()).map_err(Error::from)?;
  234. keysets.push(keyset);
  235. }
  236. }
  237. match keysets.is_empty() {
  238. true => Ok(None),
  239. false => Ok(Some(keysets)),
  240. }
  241. }
  242. #[instrument(skip(self), fields(keyset_id = %keyset_id))]
  243. async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Self::Err> {
  244. let read_txn = self.db.begin_read().map_err(Into::<Error>::into)?;
  245. let table = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
  246. match table
  247. .get(keyset_id.to_bytes().as_slice())
  248. .map_err(Error::from)?
  249. {
  250. Some(keyset) => {
  251. let keyset: KeySetInfo =
  252. serde_json::from_str(keyset.value()).map_err(Error::from)?;
  253. Ok(Some(keyset))
  254. }
  255. None => Ok(None),
  256. }
  257. }
  258. #[instrument(skip_all)]
  259. async fn get_mint_quote(&self, quote_id: &str) -> Result<Option<MintQuote>, Self::Err> {
  260. let read_txn = self.db.begin_read().map_err(Into::<Error>::into)?;
  261. let table = read_txn
  262. .open_table(MINT_QUOTES_TABLE)
  263. .map_err(Error::from)?;
  264. if let Some(mint_info) = table.get(quote_id).map_err(Error::from)? {
  265. return Ok(serde_json::from_str(mint_info.value()).map_err(Error::from)?);
  266. }
  267. Ok(None)
  268. }
  269. #[instrument(skip_all)]
  270. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err> {
  271. let read_txn = self.db.begin_read().map_err(Into::<Error>::into)?;
  272. let table = read_txn
  273. .open_table(MINT_QUOTES_TABLE)
  274. .map_err(Error::from)?;
  275. Ok(table
  276. .iter()
  277. .map_err(Error::from)?
  278. .flatten()
  279. .flat_map(|(_id, quote)| serde_json::from_str(quote.value()))
  280. .collect())
  281. }
  282. #[instrument(skip_all)]
  283. async fn get_melt_quote(&self, quote_id: &str) -> Result<Option<wallet::MeltQuote>, Self::Err> {
  284. let read_txn = self.db.begin_read().map_err(Error::from)?;
  285. let table = read_txn
  286. .open_table(MELT_QUOTES_TABLE)
  287. .map_err(Error::from)?;
  288. if let Some(mint_info) = table.get(quote_id).map_err(Error::from)? {
  289. return Ok(serde_json::from_str(mint_info.value()).map_err(Error::from)?);
  290. }
  291. Ok(None)
  292. }
  293. #[instrument(skip_all)]
  294. async fn get_melt_quotes(&self) -> Result<Vec<wallet::MeltQuote>, Self::Err> {
  295. let read_txn = self.db.begin_read().map_err(Error::from)?;
  296. let table = read_txn
  297. .open_table(MELT_QUOTES_TABLE)
  298. .map_err(Error::from)?;
  299. Ok(table
  300. .iter()
  301. .map_err(Error::from)?
  302. .flatten()
  303. .flat_map(|(_id, quote)| serde_json::from_str(quote.value()))
  304. .collect())
  305. }
  306. #[instrument(skip(self), fields(keyset_id = %keyset_id))]
  307. async fn get_keys(&self, keyset_id: &Id) -> Result<Option<Keys>, Self::Err> {
  308. let read_txn = self.db.begin_read().map_err(Error::from)?;
  309. let table = read_txn.open_table(MINT_KEYS_TABLE).map_err(Error::from)?;
  310. if let Some(mint_info) = table
  311. .get(keyset_id.to_string().as_str())
  312. .map_err(Error::from)?
  313. {
  314. return Ok(serde_json::from_str(mint_info.value()).map_err(Error::from)?);
  315. }
  316. Ok(None)
  317. }
  318. #[instrument(skip_all)]
  319. async fn get_proofs(
  320. &self,
  321. mint_url: Option<MintUrl>,
  322. unit: Option<CurrencyUnit>,
  323. state: Option<Vec<State>>,
  324. spending_conditions: Option<Vec<SpendingConditions>>,
  325. ) -> Result<Vec<ProofInfo>, Self::Err> {
  326. let read_txn = self.db.begin_read().map_err(Error::from)?;
  327. let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
  328. let proofs: Vec<ProofInfo> = table
  329. .iter()
  330. .map_err(Error::from)?
  331. .flatten()
  332. .filter_map(|(_k, v)| {
  333. let mut proof = None;
  334. if let Ok(proof_info) = serde_json::from_str::<ProofInfo>(v.value()) {
  335. if proof_info.matches_conditions(&mint_url, &unit, &state, &spending_conditions)
  336. {
  337. proof = Some(proof_info)
  338. }
  339. }
  340. proof
  341. })
  342. .collect();
  343. Ok(proofs)
  344. }
  345. #[instrument(skip(self, ys))]
  346. async fn get_proofs_by_ys(&self, ys: Vec<PublicKey>) -> Result<Vec<ProofInfo>, Self::Err> {
  347. if ys.is_empty() {
  348. return Ok(Vec::new());
  349. }
  350. let read_txn = self.db.begin_read().map_err(Error::from)?;
  351. let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
  352. let mut proofs = Vec::new();
  353. for y in ys {
  354. if let Some(proof) = table.get(y.to_bytes().as_slice()).map_err(Error::from)? {
  355. let proof_info =
  356. serde_json::from_str::<ProofInfo>(proof.value()).map_err(Error::from)?;
  357. proofs.push(proof_info);
  358. }
  359. }
  360. Ok(proofs)
  361. }
  362. async fn get_balance(
  363. &self,
  364. mint_url: Option<MintUrl>,
  365. unit: Option<CurrencyUnit>,
  366. state: Option<Vec<State>>,
  367. ) -> Result<u64, database::Error> {
  368. // For redb, we still need to fetch all proofs and sum them
  369. // since redb doesn't have SQL aggregation
  370. let proofs = self.get_proofs(mint_url, unit, state, None).await?;
  371. Ok(proofs.iter().map(|p| u64::from(p.proof.amount)).sum())
  372. }
  373. #[instrument(skip(self))]
  374. async fn get_transaction(
  375. &self,
  376. transaction_id: TransactionId,
  377. ) -> Result<Option<Transaction>, Self::Err> {
  378. let read_txn = self.db.begin_read().map_err(Error::from)?;
  379. let table = read_txn
  380. .open_table(TRANSACTIONS_TABLE)
  381. .map_err(Error::from)?;
  382. if let Some(transaction) = table.get(transaction_id.as_slice()).map_err(Error::from)? {
  383. return Ok(serde_json::from_str(transaction.value()).map_err(Error::from)?);
  384. }
  385. Ok(None)
  386. }
  387. #[instrument(skip(self))]
  388. async fn list_transactions(
  389. &self,
  390. mint_url: Option<MintUrl>,
  391. direction: Option<TransactionDirection>,
  392. unit: Option<CurrencyUnit>,
  393. ) -> Result<Vec<Transaction>, Self::Err> {
  394. let read_txn = self.db.begin_read().map_err(Error::from)?;
  395. let table = read_txn
  396. .open_table(TRANSACTIONS_TABLE)
  397. .map_err(Error::from)?;
  398. let transactions: Vec<Transaction> = table
  399. .iter()
  400. .map_err(Error::from)?
  401. .flatten()
  402. .filter_map(|(_k, v)| {
  403. let mut transaction = None;
  404. if let Ok(tx) = serde_json::from_str::<Transaction>(v.value()) {
  405. if tx.matches_conditions(&mint_url, &direction, &unit) {
  406. transaction = Some(tx)
  407. }
  408. }
  409. transaction
  410. })
  411. .collect();
  412. Ok(transactions)
  413. }
  414. async fn begin_db_transaction(
  415. &self,
  416. ) -> Result<
  417. Box<dyn cdk_common::database::WalletDatabaseTransaction<Self::Err> + Send + Sync>,
  418. Self::Err,
  419. > {
  420. let write_txn = self.db.begin_write().map_err(Error::from)?;
  421. Ok(Box::new(RedbWalletTransaction::new(write_txn)))
  422. }
  423. }
  424. #[async_trait]
  425. impl cdk_common::database::WalletDatabaseTransaction<database::Error> for RedbWalletTransaction {
  426. #[instrument(skip(self), fields(keyset_id = %keyset_id))]
  427. async fn get_keyset_by_id(
  428. &mut self,
  429. keyset_id: &Id,
  430. ) -> Result<Option<KeySetInfo>, database::Error> {
  431. let txn = self.txn().map_err(Into::<database::Error>::into)?;
  432. let table = txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
  433. let result = match table
  434. .get(keyset_id.to_bytes().as_slice())
  435. .map_err(Error::from)?
  436. {
  437. Some(keyset) => {
  438. let keyset: KeySetInfo =
  439. serde_json::from_str(keyset.value()).map_err(Error::from)?;
  440. Ok(Some(keyset))
  441. }
  442. None => Ok(None),
  443. };
  444. result
  445. }
  446. #[instrument(skip(self), fields(keyset_id = %keyset_id))]
  447. async fn get_keys(&mut self, keyset_id: &Id) -> Result<Option<Keys>, database::Error> {
  448. let txn = self.txn().map_err(Into::<database::Error>::into)?;
  449. let table = txn.open_table(MINT_KEYS_TABLE).map_err(Error::from)?;
  450. if let Some(mint_info) = table
  451. .get(keyset_id.to_string().as_str())
  452. .map_err(Error::from)?
  453. {
  454. return Ok(serde_json::from_str(mint_info.value()).map_err(Error::from)?);
  455. }
  456. Ok(None)
  457. }
  458. #[instrument(skip(self))]
  459. async fn add_mint(
  460. &mut self,
  461. mint_url: MintUrl,
  462. mint_info: Option<MintInfo>,
  463. ) -> Result<(), database::Error> {
  464. let txn = self.txn()?;
  465. let mut table = txn.open_table(MINTS_TABLE).map_err(Error::from)?;
  466. table
  467. .insert(
  468. mint_url.to_string().as_str(),
  469. serde_json::to_string(&mint_info)
  470. .map_err(Error::from)?
  471. .as_str(),
  472. )
  473. .map_err(Error::from)?;
  474. Ok(())
  475. }
  476. #[instrument(skip(self))]
  477. async fn remove_mint(&mut self, mint_url: MintUrl) -> Result<(), database::Error> {
  478. let txn = self.txn()?;
  479. let mut table = txn.open_table(MINTS_TABLE).map_err(Error::from)?;
  480. table
  481. .remove(mint_url.to_string().as_str())
  482. .map_err(Error::from)?;
  483. Ok(())
  484. }
  485. #[instrument(skip(self))]
  486. async fn update_mint_url(
  487. &mut self,
  488. old_mint_url: MintUrl,
  489. new_mint_url: MintUrl,
  490. ) -> Result<(), database::Error> {
  491. // Update proofs table
  492. {
  493. let proofs = self
  494. .get_proofs(Some(old_mint_url.clone()), None, None, None)
  495. .await
  496. .map_err(Error::from)?;
  497. // Proofs with new url
  498. let updated_proofs: Vec<ProofInfo> = proofs
  499. .clone()
  500. .into_iter()
  501. .map(|mut p| {
  502. p.mint_url = new_mint_url.clone();
  503. p
  504. })
  505. .collect();
  506. if !updated_proofs.is_empty() {
  507. self.update_proofs(updated_proofs, vec![]).await?;
  508. }
  509. }
  510. // Update mint quotes
  511. {
  512. let read_txn = self.txn()?;
  513. let mut table = read_txn
  514. .open_table(MINT_QUOTES_TABLE)
  515. .map_err(Error::from)?;
  516. let unix_time = unix_time();
  517. let quotes = table
  518. .iter()
  519. .map_err(Error::from)?
  520. .flatten()
  521. .filter_map(|(_, quote)| {
  522. let mut q: MintQuote = serde_json::from_str(quote.value())
  523. .inspect_err(|err| {
  524. tracing::warn!(
  525. "Failed to deserialize {} with error {}",
  526. quote.value(),
  527. err
  528. )
  529. })
  530. .ok()?;
  531. if q.expiry < unix_time {
  532. q.mint_url = new_mint_url.clone();
  533. Some(q)
  534. } else {
  535. None
  536. }
  537. })
  538. .collect::<Vec<_>>();
  539. for quote in quotes {
  540. table
  541. .insert(
  542. quote.id.as_str(),
  543. serde_json::to_string(&quote).map_err(Error::from)?.as_str(),
  544. )
  545. .map_err(Error::from)?;
  546. }
  547. }
  548. Ok(())
  549. }
  550. #[instrument(skip(self))]
  551. async fn add_mint_keysets(
  552. &mut self,
  553. mint_url: MintUrl,
  554. keysets: Vec<KeySetInfo>,
  555. ) -> Result<(), database::Error> {
  556. let txn = self.txn()?;
  557. let mut table = txn
  558. .open_multimap_table(MINT_KEYSETS_TABLE)
  559. .map_err(Error::from)?;
  560. let mut keysets_table = txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
  561. let mut u32_table = txn.open_table(KEYSET_U32_MAPPING).map_err(Error::from)?;
  562. let mut existing_u32 = false;
  563. for keyset in keysets {
  564. // Check if keyset already exists
  565. let existing_keyset = {
  566. let existing_keyset = keysets_table
  567. .get(keyset.id.to_bytes().as_slice())
  568. .map_err(Error::from)?;
  569. existing_keyset.map(|r| r.value().to_string())
  570. };
  571. let existing = u32_table
  572. .insert(u32::from(keyset.id), keyset.id.to_string().as_str())
  573. .map_err(Error::from)?;
  574. match existing {
  575. None => existing_u32 = false,
  576. Some(id) => {
  577. let id = Id::from_str(id.value())?;
  578. if id == keyset.id {
  579. existing_u32 = false;
  580. } else {
  581. existing_u32 = true;
  582. break;
  583. }
  584. }
  585. }
  586. let keyset = if let Some(existing_keyset) = existing_keyset {
  587. let mut existing_keyset: KeySetInfo = serde_json::from_str(&existing_keyset)?;
  588. existing_keyset.active = keyset.active;
  589. existing_keyset.input_fee_ppk = keyset.input_fee_ppk;
  590. existing_keyset
  591. } else {
  592. table
  593. .insert(
  594. mint_url.to_string().as_str(),
  595. keyset.id.to_bytes().as_slice(),
  596. )
  597. .map_err(Error::from)?;
  598. keyset
  599. };
  600. keysets_table
  601. .insert(
  602. keyset.id.to_bytes().as_slice(),
  603. serde_json::to_string(&keyset)
  604. .map_err(Error::from)?
  605. .as_str(),
  606. )
  607. .map_err(Error::from)?;
  608. }
  609. if existing_u32 {
  610. tracing::warn!("Keyset already exists for keyset id");
  611. return Err(database::Error::Duplicate);
  612. }
  613. Ok(())
  614. }
  615. #[instrument(skip_all)]
  616. async fn get_mint_quote(
  617. &mut self,
  618. quote_id: &str,
  619. ) -> Result<Option<MintQuote>, database::Error> {
  620. let txn = self.txn()?;
  621. let table = txn.open_table(MINT_QUOTES_TABLE).map_err(Error::from)?;
  622. if let Some(mint_info) = table.get(quote_id).map_err(Error::from)? {
  623. return Ok(serde_json::from_str(mint_info.value()).map_err(Error::from)?);
  624. }
  625. Ok(None)
  626. }
  627. #[instrument(skip_all)]
  628. async fn add_mint_quote(&mut self, quote: MintQuote) -> Result<(), database::Error> {
  629. let txn = self.txn()?;
  630. let mut table = txn.open_table(MINT_QUOTES_TABLE).map_err(Error::from)?;
  631. table
  632. .insert(
  633. quote.id.as_str(),
  634. serde_json::to_string(&quote).map_err(Error::from)?.as_str(),
  635. )
  636. .map_err(Error::from)?;
  637. Ok(())
  638. }
  639. #[instrument(skip_all)]
  640. async fn remove_mint_quote(&mut self, quote_id: &str) -> Result<(), database::Error> {
  641. let txn = self.txn()?;
  642. let mut table = txn.open_table(MINT_QUOTES_TABLE).map_err(Error::from)?;
  643. table.remove(quote_id).map_err(Error::from)?;
  644. Ok(())
  645. }
  646. #[instrument(skip_all)]
  647. async fn get_melt_quote(
  648. &mut self,
  649. quote_id: &str,
  650. ) -> Result<Option<wallet::MeltQuote>, database::Error> {
  651. let txn = self.txn()?;
  652. let table = txn.open_table(MELT_QUOTES_TABLE).map_err(Error::from)?;
  653. if let Some(mint_info) = table.get(quote_id).map_err(Error::from)? {
  654. return Ok(serde_json::from_str(mint_info.value()).map_err(Error::from)?);
  655. }
  656. Ok(None)
  657. }
  658. #[instrument(skip_all)]
  659. async fn add_melt_quote(&mut self, quote: wallet::MeltQuote) -> Result<(), database::Error> {
  660. let txn = self.txn()?;
  661. let mut table = txn.open_table(MELT_QUOTES_TABLE).map_err(Error::from)?;
  662. table
  663. .insert(
  664. quote.id.as_str(),
  665. serde_json::to_string(&quote).map_err(Error::from)?.as_str(),
  666. )
  667. .map_err(Error::from)?;
  668. Ok(())
  669. }
  670. #[instrument(skip_all)]
  671. async fn remove_melt_quote(&mut self, quote_id: &str) -> Result<(), database::Error> {
  672. let txn = self.txn()?;
  673. let mut table = txn.open_table(MELT_QUOTES_TABLE).map_err(Error::from)?;
  674. table.remove(quote_id).map_err(Error::from)?;
  675. Ok(())
  676. }
  677. #[instrument(skip_all)]
  678. async fn add_keys(&mut self, keyset: KeySet) -> Result<(), database::Error> {
  679. let txn = self.txn()?;
  680. keyset.verify_id()?;
  681. let mut table = txn.open_table(MINT_KEYS_TABLE).map_err(Error::from)?;
  682. let existing_keys = table
  683. .insert(
  684. keyset.id.to_string().as_str(),
  685. serde_json::to_string(&keyset.keys)
  686. .map_err(Error::from)?
  687. .as_str(),
  688. )
  689. .map_err(Error::from)?
  690. .is_some();
  691. let mut table = txn.open_table(KEYSET_U32_MAPPING).map_err(Error::from)?;
  692. let existing = table
  693. .insert(u32::from(keyset.id), keyset.id.to_string().as_str())
  694. .map_err(Error::from)?;
  695. let existing_u32 = match existing {
  696. None => false,
  697. Some(id) => {
  698. let id = Id::from_str(id.value())?;
  699. id != keyset.id
  700. }
  701. };
  702. if existing_keys || existing_u32 {
  703. tracing::warn!("Keys already exist for keyset id");
  704. return Err(database::Error::Duplicate);
  705. }
  706. Ok(())
  707. }
  708. #[instrument(skip(self), fields(keyset_id = %keyset_id))]
  709. async fn remove_keys(&mut self, keyset_id: &Id) -> Result<(), database::Error> {
  710. let txn = self.txn()?;
  711. let mut table = txn.open_table(MINT_KEYS_TABLE).map_err(Error::from)?;
  712. table
  713. .remove(keyset_id.to_string().as_str())
  714. .map_err(Error::from)?;
  715. Ok(())
  716. }
  717. #[instrument(skip_all)]
  718. async fn get_proofs(
  719. &mut self,
  720. mint_url: Option<MintUrl>,
  721. unit: Option<CurrencyUnit>,
  722. state: Option<Vec<State>>,
  723. spending_conditions: Option<Vec<SpendingConditions>>,
  724. ) -> Result<Vec<ProofInfo>, database::Error> {
  725. let txn = self.txn()?;
  726. let table = txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
  727. let proofs: Vec<ProofInfo> = table
  728. .iter()
  729. .map_err(Error::from)?
  730. .flatten()
  731. .filter_map(|(_k, v)| {
  732. let mut proof = None;
  733. if let Ok(proof_info) = serde_json::from_str::<ProofInfo>(v.value()) {
  734. if proof_info.matches_conditions(&mint_url, &unit, &state, &spending_conditions)
  735. {
  736. proof = Some(proof_info)
  737. }
  738. }
  739. proof
  740. })
  741. .collect();
  742. Ok(proofs)
  743. }
  744. #[instrument(skip(self, added, deleted_ys))]
  745. async fn update_proofs(
  746. &mut self,
  747. added: Vec<ProofInfo>,
  748. deleted_ys: Vec<PublicKey>,
  749. ) -> Result<(), database::Error> {
  750. let txn = self.txn()?;
  751. let mut table = txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
  752. for proof_info in added.iter() {
  753. table
  754. .insert(
  755. proof_info.y.to_bytes().as_slice(),
  756. serde_json::to_string(&proof_info)
  757. .map_err(Error::from)?
  758. .as_str(),
  759. )
  760. .map_err(Error::from)?;
  761. }
  762. for y in deleted_ys.iter() {
  763. table.remove(y.to_bytes().as_slice()).map_err(Error::from)?;
  764. }
  765. Ok(())
  766. }
  767. async fn update_proofs_state(
  768. &mut self,
  769. ys: Vec<PublicKey>,
  770. state: State,
  771. ) -> Result<(), database::Error> {
  772. let txn = self.txn()?;
  773. let mut table = txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
  774. for y in ys {
  775. let y_slice = y.to_bytes();
  776. let proof = table
  777. .get(y_slice.as_slice())
  778. .map_err(Error::from)?
  779. .ok_or(Error::UnknownY)?;
  780. let mut proof_info =
  781. serde_json::from_str::<ProofInfo>(proof.value()).map_err(Error::from)?;
  782. drop(proof);
  783. proof_info.state = state;
  784. table
  785. .insert(
  786. y_slice.as_slice(),
  787. serde_json::to_string(&proof_info)
  788. .map_err(Error::from)?
  789. .as_str(),
  790. )
  791. .map_err(Error::from)?;
  792. }
  793. Ok(())
  794. }
  795. #[instrument(skip(self), fields(keyset_id = %keyset_id))]
  796. async fn increment_keyset_counter(
  797. &mut self,
  798. keyset_id: &Id,
  799. count: u32,
  800. ) -> Result<u32, database::Error> {
  801. let txn = self.txn()?;
  802. let mut table = txn.open_table(KEYSET_COUNTER).map_err(Error::from)?;
  803. let current_counter = table
  804. .get(keyset_id.to_string().as_str())
  805. .map_err(Error::from)?
  806. .map(|x| x.value())
  807. .unwrap_or_default();
  808. let new_counter = current_counter + count;
  809. table
  810. .insert(keyset_id.to_string().as_str(), new_counter)
  811. .map_err(Error::from)?;
  812. Ok(new_counter)
  813. }
  814. #[instrument(skip(self))]
  815. async fn add_transaction(&mut self, transaction: Transaction) -> Result<(), database::Error> {
  816. let id = transaction.id();
  817. let txn = self.txn()?;
  818. let mut table = txn.open_table(TRANSACTIONS_TABLE).map_err(Error::from)?;
  819. table
  820. .insert(
  821. id.as_slice(),
  822. serde_json::to_string(&transaction)
  823. .map_err(Error::from)?
  824. .as_str(),
  825. )
  826. .map_err(Error::from)?;
  827. Ok(())
  828. }
  829. #[instrument(skip(self))]
  830. async fn remove_transaction(
  831. &mut self,
  832. transaction_id: TransactionId,
  833. ) -> Result<(), database::Error> {
  834. let txn = self.txn()?;
  835. let mut table = txn.open_table(TRANSACTIONS_TABLE).map_err(Error::from)?;
  836. table
  837. .remove(transaction_id.as_slice())
  838. .map_err(Error::from)?;
  839. Ok(())
  840. }
  841. }
  842. #[async_trait]
  843. impl cdk_common::database::DbTransactionFinalizer for RedbWalletTransaction {
  844. type Err = database::Error;
  845. async fn commit(mut self: Box<Self>) -> Result<(), database::Error> {
  846. if let Some(txn) = self.write_txn.take() {
  847. txn.commit().map_err(Error::from)?;
  848. }
  849. Ok(())
  850. }
  851. async fn rollback(mut self: Box<Self>) -> Result<(), database::Error> {
  852. if let Some(txn) = self.write_txn.take() {
  853. txn.abort().map_err(Error::from)?;
  854. }
  855. Ok(())
  856. }
  857. }
  858. impl Drop for RedbWalletTransaction {
  859. fn drop(&mut self) {
  860. if let Some(txn) = self.write_txn.take() {
  861. let _ = txn.abort();
  862. }
  863. }
  864. }