mod.rs 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887
  1. //! SQLite Mint
  2. use std::collections::{HashMap, HashSet};
  3. use std::path::Path;
  4. use std::str::FromStr;
  5. use async_trait::async_trait;
  6. use bitcoin::bip32::DerivationPath;
  7. use cdk_common::common::{PaymentProcessorKey, QuoteTTL};
  8. use cdk_common::database::{self, MintDatabase};
  9. use cdk_common::mint::{self, MintKeySetInfo, MintQuote};
  10. use cdk_common::nut00::ProofsMethods;
  11. use cdk_common::nut05::QuoteState;
  12. use cdk_common::secret::Secret;
  13. use cdk_common::{
  14. Amount, BlindSignature, BlindSignatureDleq, CurrencyUnit, Id, MeltBolt11Request,
  15. MeltQuoteState, MintInfo, MintQuoteState, PaymentMethod, Proof, Proofs, PublicKey, SecretKey,
  16. State,
  17. };
  18. use error::Error;
  19. use lightning_invoice::Bolt11Invoice;
  20. use sqlx::sqlite::SqliteRow;
  21. use sqlx::{Executor, Pool, Row, Sqlite};
  22. use uuid::fmt::Hyphenated;
  23. use uuid::Uuid;
  24. use crate::common::create_sqlite_pool;
  25. #[cfg(feature = "auth")]
  26. mod auth;
  27. pub mod error;
  28. pub mod memory;
  29. #[cfg(feature = "auth")]
  30. pub use auth::MintSqliteAuthDatabase;
  31. /// Mint SQLite Database
  32. #[derive(Debug, Clone)]
  33. pub struct MintSqliteDatabase {
  34. pool: Pool<Sqlite>,
  35. }
  36. impl MintSqliteDatabase {
  37. /// Check if any proofs are spent
  38. async fn check_for_spent_proofs<'e, 'c: 'e, E>(
  39. &self,
  40. transaction: E,
  41. ys: &[PublicKey],
  42. ) -> Result<bool, database::Error>
  43. where
  44. E: Executor<'c, Database = Sqlite>,
  45. {
  46. if ys.is_empty() {
  47. return Ok(false);
  48. }
  49. let check_sql = format!(
  50. "SELECT state FROM proof WHERE y IN ({}) AND state = 'SPENT'",
  51. std::iter::repeat("?")
  52. .take(ys.len())
  53. .collect::<Vec<_>>()
  54. .join(",")
  55. );
  56. let spent_count = ys
  57. .iter()
  58. .fold(sqlx::query(&check_sql), |query, y| {
  59. query.bind(y.to_bytes().to_vec())
  60. })
  61. .fetch_all(transaction)
  62. .await
  63. .map_err(Error::from)?
  64. .len();
  65. Ok(spent_count > 0)
  66. }
  67. /// Create new [`MintSqliteDatabase`]
  68. #[cfg(not(feature = "sqlcipher"))]
  69. pub async fn new<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
  70. Ok(Self {
  71. pool: create_sqlite_pool(path.as_ref().to_str().ok_or(Error::InvalidDbPath)?).await?,
  72. })
  73. }
  74. /// Create new [`MintSqliteDatabase`]
  75. #[cfg(feature = "sqlcipher")]
  76. pub async fn new<P: AsRef<Path>>(path: P, password: String) -> Result<Self, Error> {
  77. Ok(Self {
  78. pool: create_sqlite_pool(
  79. path.as_ref().to_str().ok_or(Error::InvalidDbPath)?,
  80. password,
  81. )
  82. .await?,
  83. })
  84. }
  85. /// Migrate [`MintSqliteDatabase`]
  86. pub async fn migrate(&self) {
  87. sqlx::migrate!("./src/mint/migrations")
  88. .run(&self.pool)
  89. .await
  90. .expect("Could not run migrations");
  91. }
  92. }
  93. #[async_trait]
  94. impl MintDatabase for MintSqliteDatabase {
  95. type Err = database::Error;
  96. async fn set_active_keyset(&self, unit: CurrencyUnit, id: Id) -> Result<(), Self::Err> {
  97. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  98. let update_res = sqlx::query(
  99. r#"
  100. UPDATE keyset
  101. SET active=FALSE
  102. WHERE unit IS ?;
  103. "#,
  104. )
  105. .bind(unit.to_string())
  106. .execute(&mut *transaction)
  107. .await;
  108. match update_res {
  109. Ok(_) => (),
  110. Err(err) => {
  111. tracing::error!("SQLite Could not update keyset");
  112. if let Err(err) = transaction.rollback().await {
  113. tracing::error!("Could not rollback sql transaction: {}", err);
  114. }
  115. return Err(Error::from(err).into());
  116. }
  117. };
  118. let update_res = sqlx::query(
  119. r#"
  120. UPDATE keyset
  121. SET active=TRUE
  122. WHERE unit IS ?
  123. AND id IS ?;
  124. "#,
  125. )
  126. .bind(unit.to_string())
  127. .bind(id.to_string())
  128. .execute(&mut *transaction)
  129. .await;
  130. match update_res {
  131. Ok(_) => (),
  132. Err(err) => {
  133. tracing::error!("SQLite Could not update keyset");
  134. if let Err(err) = transaction.rollback().await {
  135. tracing::error!("Could not rollback sql transaction: {}", err);
  136. }
  137. return Err(Error::from(err).into());
  138. }
  139. };
  140. transaction.commit().await.map_err(Error::from)?;
  141. Ok(())
  142. }
  143. async fn get_active_keyset_id(&self, unit: &CurrencyUnit) -> Result<Option<Id>, Self::Err> {
  144. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  145. let rec = sqlx::query(
  146. r#"
  147. SELECT id
  148. FROM keyset
  149. WHERE active = 1
  150. AND unit IS ?
  151. "#,
  152. )
  153. .bind(unit.to_string())
  154. .fetch_one(&mut *transaction)
  155. .await;
  156. let rec = match rec {
  157. Ok(rec) => {
  158. transaction.commit().await.map_err(Error::from)?;
  159. rec
  160. }
  161. Err(err) => match err {
  162. sqlx::Error::RowNotFound => {
  163. transaction.commit().await.map_err(Error::from)?;
  164. return Ok(None);
  165. }
  166. _ => {
  167. return {
  168. if let Err(err) = transaction.rollback().await {
  169. tracing::error!("Could not rollback sql transaction: {}", err);
  170. }
  171. Err(Error::SQLX(err).into())
  172. }
  173. }
  174. },
  175. };
  176. Ok(Some(
  177. Id::from_str(rec.try_get("id").map_err(Error::from)?).map_err(Error::from)?,
  178. ))
  179. }
  180. async fn get_active_keysets(&self) -> Result<HashMap<CurrencyUnit, Id>, Self::Err> {
  181. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  182. let recs = sqlx::query(
  183. r#"
  184. SELECT id, unit
  185. FROM keyset
  186. WHERE active = 1
  187. "#,
  188. )
  189. .fetch_all(&mut *transaction)
  190. .await;
  191. match recs {
  192. Ok(recs) => {
  193. transaction.commit().await.map_err(Error::from)?;
  194. let keysets = recs
  195. .iter()
  196. .filter_map(|r| match Id::from_str(r.get("id")) {
  197. Ok(id) => Some((
  198. CurrencyUnit::from_str(r.get::<'_, &str, &str>("unit")).unwrap(),
  199. id,
  200. )),
  201. Err(_) => None,
  202. })
  203. .collect();
  204. Ok(keysets)
  205. }
  206. Err(err) => {
  207. tracing::error!("SQLite could not get active keyset");
  208. if let Err(err) = transaction.rollback().await {
  209. tracing::error!("Could not rollback sql transaction: {}", err);
  210. }
  211. Err(Error::from(err).into())
  212. }
  213. }
  214. }
  215. async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err> {
  216. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  217. let res = sqlx::query(
  218. r#"
  219. INSERT INTO mint_quote
  220. (id, amount, unit, request, state, expiry, request_lookup_id, pubkey)
  221. VALUES (?, ?, ?, ?, ?, ?, ?, ?)
  222. ON CONFLICT(id) DO UPDATE SET
  223. amount = excluded.amount,
  224. unit = excluded.unit,
  225. request = excluded.request,
  226. state = excluded.state,
  227. expiry = excluded.expiry,
  228. request_lookup_id = excluded.request_lookup_id
  229. ON CONFLICT(request_lookup_id) DO UPDATE SET
  230. amount = excluded.amount,
  231. unit = excluded.unit,
  232. request = excluded.request,
  233. state = excluded.state,
  234. expiry = excluded.expiry,
  235. id = excluded.id
  236. "#,
  237. )
  238. .bind(quote.id.to_string())
  239. .bind(u64::from(quote.amount) as i64)
  240. .bind(quote.unit.to_string())
  241. .bind(quote.request)
  242. .bind(quote.state.to_string())
  243. .bind(quote.expiry as i64)
  244. .bind(quote.request_lookup_id)
  245. .bind(quote.pubkey.map(|p| p.to_string()))
  246. .execute(&mut *transaction)
  247. .await;
  248. match res {
  249. Ok(_) => {
  250. transaction.commit().await.map_err(Error::from)?;
  251. Ok(())
  252. }
  253. Err(err) => {
  254. tracing::error!("SQLite Could not update keyset");
  255. if let Err(err) = transaction.rollback().await {
  256. tracing::error!("Could not rollback sql transaction: {}", err);
  257. }
  258. Err(Error::from(err).into())
  259. }
  260. }
  261. }
  262. async fn get_mint_quote(&self, quote_id: &Uuid) -> Result<Option<MintQuote>, Self::Err> {
  263. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  264. let rec = sqlx::query(
  265. r#"
  266. SELECT *
  267. FROM mint_quote
  268. WHERE id=?;
  269. "#,
  270. )
  271. .bind(quote_id.as_hyphenated())
  272. .fetch_one(&mut *transaction)
  273. .await;
  274. match rec {
  275. Ok(rec) => {
  276. transaction.commit().await.map_err(Error::from)?;
  277. Ok(Some(sqlite_row_to_mint_quote(rec)?))
  278. }
  279. Err(err) => match err {
  280. sqlx::Error::RowNotFound => {
  281. transaction.commit().await.map_err(Error::from)?;
  282. Ok(None)
  283. }
  284. _ => {
  285. if let Err(err) = transaction.rollback().await {
  286. tracing::error!("Could not rollback sql transaction: {}", err);
  287. }
  288. Err(Error::SQLX(err).into())
  289. }
  290. },
  291. }
  292. }
  293. async fn get_mint_quote_by_request(
  294. &self,
  295. request: &str,
  296. ) -> Result<Option<MintQuote>, Self::Err> {
  297. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  298. let rec = sqlx::query(
  299. r#"
  300. SELECT *
  301. FROM mint_quote
  302. WHERE request=?;
  303. "#,
  304. )
  305. .bind(request)
  306. .fetch_one(&mut *transaction)
  307. .await;
  308. match rec {
  309. Ok(rec) => {
  310. transaction.commit().await.map_err(Error::from)?;
  311. Ok(Some(sqlite_row_to_mint_quote(rec)?))
  312. }
  313. Err(err) => match err {
  314. sqlx::Error::RowNotFound => {
  315. transaction.commit().await.map_err(Error::from)?;
  316. Ok(None)
  317. }
  318. _ => {
  319. if let Err(err) = transaction.rollback().await {
  320. tracing::error!("Could not rollback sql transaction: {}", err);
  321. }
  322. Err(Error::SQLX(err).into())
  323. }
  324. },
  325. }
  326. }
  327. async fn get_mint_quote_by_request_lookup_id(
  328. &self,
  329. request_lookup_id: &str,
  330. ) -> Result<Option<MintQuote>, Self::Err> {
  331. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  332. let rec = sqlx::query(
  333. r#"
  334. SELECT *
  335. FROM mint_quote
  336. WHERE request_lookup_id=?;
  337. "#,
  338. )
  339. .bind(request_lookup_id)
  340. .fetch_one(&mut *transaction)
  341. .await;
  342. match rec {
  343. Ok(rec) => {
  344. transaction.commit().await.map_err(Error::from)?;
  345. Ok(Some(sqlite_row_to_mint_quote(rec)?))
  346. }
  347. Err(err) => match err {
  348. sqlx::Error::RowNotFound => {
  349. transaction.commit().await.map_err(Error::from)?;
  350. Ok(None)
  351. }
  352. _ => {
  353. if let Err(err) = transaction.rollback().await {
  354. tracing::error!("Could not rollback sql transaction: {}", err);
  355. }
  356. Err(Error::SQLX(err).into())
  357. }
  358. },
  359. }
  360. }
  361. async fn update_mint_quote_state(
  362. &self,
  363. quote_id: &Uuid,
  364. state: MintQuoteState,
  365. ) -> Result<MintQuoteState, Self::Err> {
  366. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  367. let rec = sqlx::query(
  368. r#"
  369. SELECT *
  370. FROM mint_quote
  371. WHERE id=?;
  372. "#,
  373. )
  374. .bind(quote_id.as_hyphenated())
  375. .fetch_one(&mut *transaction)
  376. .await;
  377. let quote = match rec {
  378. Ok(row) => sqlite_row_to_mint_quote(row)?,
  379. Err(err) => {
  380. tracing::error!("SQLite Could not update keyset");
  381. if let Err(err) = transaction.rollback().await {
  382. tracing::error!("Could not rollback sql transaction: {}", err);
  383. }
  384. return Err(Error::from(err).into());
  385. }
  386. };
  387. let update = sqlx::query(
  388. r#"
  389. UPDATE mint_quote SET state = ? WHERE id = ?
  390. "#,
  391. )
  392. .bind(state.to_string())
  393. .bind(quote_id.as_hyphenated())
  394. .execute(&mut *transaction)
  395. .await;
  396. match update {
  397. Ok(_) => {
  398. transaction.commit().await.map_err(Error::from)?;
  399. Ok(quote.state)
  400. }
  401. Err(err) => {
  402. tracing::error!("SQLite Could not update keyset");
  403. if let Err(err) = transaction.rollback().await {
  404. tracing::error!("Could not rollback sql transaction: {}", err);
  405. }
  406. return Err(Error::from(err).into());
  407. }
  408. }
  409. }
  410. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err> {
  411. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  412. let rec = sqlx::query(
  413. r#"
  414. SELECT *
  415. FROM mint_quote
  416. "#,
  417. )
  418. .fetch_all(&mut *transaction)
  419. .await;
  420. match rec {
  421. Ok(rows) => {
  422. transaction.commit().await.map_err(Error::from)?;
  423. let mint_quotes = rows
  424. .into_iter()
  425. .map(sqlite_row_to_mint_quote)
  426. .collect::<Result<Vec<MintQuote>, _>>()?;
  427. Ok(mint_quotes)
  428. }
  429. Err(err) => {
  430. tracing::error!("SQLite get mint quotes");
  431. if let Err(err) = transaction.rollback().await {
  432. tracing::error!("Could not rollback sql transaction: {}", err);
  433. }
  434. return Err(Error::from(err).into());
  435. }
  436. }
  437. }
  438. async fn get_mint_quotes_with_state(
  439. &self,
  440. state: MintQuoteState,
  441. ) -> Result<Vec<MintQuote>, Self::Err> {
  442. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  443. let rec = sqlx::query(
  444. r#"
  445. SELECT *
  446. FROM mint_quote
  447. WHERE state = ?
  448. "#,
  449. )
  450. .bind(state.to_string())
  451. .fetch_all(&mut *transaction)
  452. .await;
  453. match rec {
  454. Ok(rows) => {
  455. transaction.commit().await.map_err(Error::from)?;
  456. let mint_quotes = rows
  457. .into_iter()
  458. .map(sqlite_row_to_mint_quote)
  459. .collect::<Result<Vec<MintQuote>, _>>()?;
  460. Ok(mint_quotes)
  461. }
  462. Err(err) => {
  463. tracing::error!("SQLite get mint quotes with state");
  464. if let Err(err) = transaction.rollback().await {
  465. tracing::error!("Could not rollback sql transaction: {}", err);
  466. }
  467. return Err(Error::from(err).into());
  468. }
  469. }
  470. }
  471. async fn remove_mint_quote(&self, quote_id: &Uuid) -> Result<(), Self::Err> {
  472. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  473. let res = sqlx::query(
  474. r#"
  475. DELETE FROM mint_quote
  476. WHERE id=?
  477. "#,
  478. )
  479. .bind(quote_id.as_hyphenated())
  480. .execute(&mut *transaction)
  481. .await;
  482. match res {
  483. Ok(_) => {
  484. transaction.commit().await.map_err(Error::from)?;
  485. Ok(())
  486. }
  487. Err(err) => {
  488. tracing::error!("SQLite Could not remove mint quote");
  489. if let Err(err) = transaction.rollback().await {
  490. tracing::error!("Could not rollback sql transaction: {}", err);
  491. }
  492. Err(Error::from(err).into())
  493. }
  494. }
  495. }
  496. async fn add_melt_quote(&self, quote: mint::MeltQuote) -> Result<(), Self::Err> {
  497. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  498. let res = sqlx::query(
  499. r#"
  500. INSERT INTO melt_quote
  501. (id, unit, amount, request, fee_reserve, state, expiry, payment_preimage, request_lookup_id, msat_to_pay)
  502. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  503. ON CONFLICT(id) DO UPDATE SET
  504. unit = excluded.unit,
  505. amount = excluded.amount,
  506. request = excluded.request,
  507. fee_reserve = excluded.fee_reserve,
  508. state = excluded.state,
  509. expiry = excluded.expiry,
  510. payment_preimage = excluded.payment_preimage,
  511. request_lookup_id = excluded.request_lookup_id,
  512. msat_to_pay = excluded.msat_to_pay
  513. ON CONFLICT(request_lookup_id) DO UPDATE SET
  514. unit = excluded.unit,
  515. amount = excluded.amount,
  516. request = excluded.request,
  517. fee_reserve = excluded.fee_reserve,
  518. state = excluded.state,
  519. expiry = excluded.expiry,
  520. payment_preimage = excluded.payment_preimage,
  521. id = excluded.id;
  522. "#,
  523. )
  524. .bind(quote.id.to_string())
  525. .bind(quote.unit.to_string())
  526. .bind(u64::from(quote.amount) as i64)
  527. .bind(quote.request)
  528. .bind(u64::from(quote.fee_reserve) as i64)
  529. .bind(quote.state.to_string())
  530. .bind(quote.expiry as i64)
  531. .bind(quote.payment_preimage)
  532. .bind(quote.request_lookup_id)
  533. .bind(quote.msat_to_pay.map(|a| u64::from(a) as i64))
  534. .execute(&mut *transaction)
  535. .await;
  536. match res {
  537. Ok(_) => {
  538. transaction.commit().await.map_err(Error::from)?;
  539. Ok(())
  540. }
  541. Err(err) => {
  542. tracing::error!("SQLite Could not remove mint quote");
  543. if let Err(err) = transaction.rollback().await {
  544. tracing::error!("Could not rollback sql transaction: {}", err);
  545. }
  546. Err(Error::from(err).into())
  547. }
  548. }
  549. }
  550. async fn get_melt_quote(&self, quote_id: &Uuid) -> Result<Option<mint::MeltQuote>, Self::Err> {
  551. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  552. let rec = sqlx::query(
  553. r#"
  554. SELECT *
  555. FROM melt_quote
  556. WHERE id=?;
  557. "#,
  558. )
  559. .bind(quote_id.as_hyphenated())
  560. .fetch_one(&mut *transaction)
  561. .await;
  562. match rec {
  563. Ok(rec) => {
  564. transaction.commit().await.map_err(Error::from)?;
  565. Ok(Some(sqlite_row_to_melt_quote(rec)?))
  566. }
  567. Err(err) => match err {
  568. sqlx::Error::RowNotFound => {
  569. transaction.commit().await.map_err(Error::from)?;
  570. Ok(None)
  571. }
  572. _ => {
  573. if let Err(err) = transaction.rollback().await {
  574. tracing::error!("Could not rollback sql transaction: {}", err);
  575. }
  576. Err(Error::SQLX(err).into())
  577. }
  578. },
  579. }
  580. }
  581. async fn get_melt_quotes(&self) -> Result<Vec<mint::MeltQuote>, Self::Err> {
  582. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  583. let rec = sqlx::query(
  584. r#"
  585. SELECT *
  586. FROM melt_quote
  587. "#,
  588. )
  589. .fetch_all(&mut *transaction)
  590. .await
  591. .map_err(Error::from);
  592. match rec {
  593. Ok(rec) => {
  594. let melt_quotes = rec
  595. .into_iter()
  596. .map(sqlite_row_to_melt_quote)
  597. .collect::<Result<Vec<mint::MeltQuote>, _>>()?;
  598. Ok(melt_quotes)
  599. }
  600. Err(err) => {
  601. if let Err(err) = transaction.rollback().await {
  602. tracing::error!("Could not rollback sql transaction: {}", err);
  603. }
  604. Err(err.into())
  605. }
  606. }
  607. }
  608. async fn update_melt_quote_state(
  609. &self,
  610. quote_id: &Uuid,
  611. state: MeltQuoteState,
  612. ) -> Result<MeltQuoteState, Self::Err> {
  613. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  614. let rec = sqlx::query(
  615. r#"
  616. SELECT *
  617. FROM melt_quote
  618. WHERE id=?;
  619. "#,
  620. )
  621. .bind(quote_id.as_hyphenated())
  622. .fetch_one(&mut *transaction)
  623. .await;
  624. let quote = match rec {
  625. Ok(rec) => sqlite_row_to_melt_quote(rec)?,
  626. Err(err) => {
  627. tracing::error!("SQLite Could not update keyset");
  628. if let Err(err) = transaction.rollback().await {
  629. tracing::error!("Could not rollback sql transaction: {}", err);
  630. }
  631. return Err(Error::from(err).into());
  632. }
  633. };
  634. let rec = sqlx::query(
  635. r#"
  636. UPDATE melt_quote SET state = ? WHERE id = ?
  637. "#,
  638. )
  639. .bind(state.to_string())
  640. .bind(quote_id.as_hyphenated())
  641. .execute(&mut *transaction)
  642. .await;
  643. match rec {
  644. Ok(_) => {
  645. transaction.commit().await.map_err(Error::from)?;
  646. }
  647. Err(err) => {
  648. tracing::error!("SQLite Could not update melt quote");
  649. if let Err(err) = transaction.rollback().await {
  650. tracing::error!("Could not rollback sql transaction: {}", err);
  651. }
  652. return Err(Error::from(err).into());
  653. }
  654. };
  655. Ok(quote.state)
  656. }
  657. async fn remove_melt_quote(&self, quote_id: &Uuid) -> Result<(), Self::Err> {
  658. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  659. let res = sqlx::query(
  660. r#"
  661. DELETE FROM melt_quote
  662. WHERE id=?
  663. "#,
  664. )
  665. .bind(quote_id.as_hyphenated())
  666. .execute(&mut *transaction)
  667. .await;
  668. match res {
  669. Ok(_) => {
  670. transaction.commit().await.map_err(Error::from)?;
  671. Ok(())
  672. }
  673. Err(err) => {
  674. tracing::error!("SQLite Could not update melt quote");
  675. if let Err(err) = transaction.rollback().await {
  676. tracing::error!("Could not rollback sql transaction: {}", err);
  677. }
  678. Err(Error::from(err).into())
  679. }
  680. }
  681. }
  682. async fn add_keyset_info(&self, keyset: MintKeySetInfo) -> Result<(), Self::Err> {
  683. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  684. let res = sqlx::query(
  685. r#"
  686. INSERT INTO keyset
  687. (id, unit, active, valid_from, valid_to, derivation_path, max_order, input_fee_ppk, derivation_path_index)
  688. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
  689. ON CONFLICT(id) DO UPDATE SET
  690. unit = excluded.unit,
  691. active = excluded.active,
  692. valid_from = excluded.valid_from,
  693. valid_to = excluded.valid_to,
  694. derivation_path = excluded.derivation_path,
  695. max_order = excluded.max_order,
  696. input_fee_ppk = excluded.input_fee_ppk,
  697. derivation_path_index = excluded.derivation_path_index
  698. "#,
  699. )
  700. .bind(keyset.id.to_string())
  701. .bind(keyset.unit.to_string())
  702. .bind(keyset.active)
  703. .bind(keyset.valid_from as i64)
  704. .bind(keyset.valid_to.map(|v| v as i64))
  705. .bind(keyset.derivation_path.to_string())
  706. .bind(keyset.max_order)
  707. .bind(keyset.input_fee_ppk as i64)
  708. .bind(keyset.derivation_path_index)
  709. .execute(&mut *transaction)
  710. .await;
  711. match res {
  712. Ok(_) => {
  713. transaction.commit().await.map_err(Error::from)?;
  714. Ok(())
  715. }
  716. Err(err) => {
  717. tracing::error!("SQLite could not add keyset info");
  718. if let Err(err) = transaction.rollback().await {
  719. tracing::error!("Could not rollback sql transaction: {}", err);
  720. }
  721. Err(Error::from(err).into())
  722. }
  723. }
  724. }
  725. async fn get_keyset_info(&self, id: &Id) -> Result<Option<MintKeySetInfo>, Self::Err> {
  726. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  727. let rec = sqlx::query(
  728. r#"
  729. SELECT *
  730. FROM keyset
  731. WHERE id=?;
  732. "#,
  733. )
  734. .bind(id.to_string())
  735. .fetch_one(&mut *transaction)
  736. .await;
  737. match rec {
  738. Ok(rec) => {
  739. transaction.commit().await.map_err(Error::from)?;
  740. Ok(Some(sqlite_row_to_keyset_info(rec)?))
  741. }
  742. Err(err) => match err {
  743. sqlx::Error::RowNotFound => {
  744. transaction.commit().await.map_err(Error::from)?;
  745. return Ok(None);
  746. }
  747. _ => {
  748. tracing::error!("SQLite could not get keyset info");
  749. if let Err(err) = transaction.rollback().await {
  750. tracing::error!("Could not rollback sql transaction: {}", err);
  751. }
  752. return Err(Error::SQLX(err).into());
  753. }
  754. },
  755. }
  756. }
  757. async fn get_keyset_infos(&self) -> Result<Vec<MintKeySetInfo>, Self::Err> {
  758. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  759. let recs = sqlx::query(
  760. r#"
  761. SELECT *
  762. FROM keyset;
  763. "#,
  764. )
  765. .fetch_all(&mut *transaction)
  766. .await
  767. .map_err(Error::from);
  768. match recs {
  769. Ok(recs) => {
  770. transaction.commit().await.map_err(Error::from)?;
  771. Ok(recs
  772. .into_iter()
  773. .map(sqlite_row_to_keyset_info)
  774. .collect::<Result<_, _>>()?)
  775. }
  776. Err(err) => {
  777. tracing::error!("SQLite could not get keyset info");
  778. if let Err(err) = transaction.rollback().await {
  779. tracing::error!("Could not rollback sql transaction: {}", err);
  780. }
  781. Err(err.into())
  782. }
  783. }
  784. }
  785. async fn add_proofs(&self, proofs: Proofs, quote_id: Option<Uuid>) -> Result<(), Self::Err> {
  786. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  787. for proof in proofs {
  788. let result = sqlx::query(
  789. r#"
  790. INSERT OR IGNORE INTO proof
  791. (y, amount, keyset_id, secret, c, witness, state, quote_id)
  792. VALUES (?, ?, ?, ?, ?, ?, ?, ?);
  793. "#,
  794. )
  795. .bind(proof.y()?.to_bytes().to_vec())
  796. .bind(u64::from(proof.amount) as i64)
  797. .bind(proof.keyset_id.to_string())
  798. .bind(proof.secret.to_string())
  799. .bind(proof.c.to_bytes().to_vec())
  800. .bind(proof.witness.map(|w| serde_json::to_string(&w).unwrap()))
  801. .bind("UNSPENT")
  802. .bind(quote_id.map(|q| q.hyphenated()))
  803. .execute(&mut *transaction)
  804. .await;
  805. // We still need to check for foreign key constraint errors
  806. if let Err(err) = result {
  807. if let sqlx::Error::Database(db_err) = &err {
  808. if db_err.message().contains("FOREIGN KEY constraint failed") {
  809. tracing::error!(
  810. "Foreign key constraint failed when adding proof: {:?}",
  811. err
  812. );
  813. transaction.rollback().await.map_err(Error::from)?;
  814. return Err(database::Error::InvalidKeysetId);
  815. }
  816. }
  817. // For any other error, roll back and return the error
  818. tracing::error!("Error adding proof: {:?}", err);
  819. transaction.rollback().await.map_err(Error::from)?;
  820. return Err(Error::from(err).into());
  821. }
  822. }
  823. transaction.commit().await.map_err(Error::from)?;
  824. Ok(())
  825. }
  826. async fn remove_proofs(
  827. &self,
  828. ys: &[PublicKey],
  829. _quote_id: Option<Uuid>,
  830. ) -> Result<(), Self::Err> {
  831. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  832. if self.check_for_spent_proofs(&mut *transaction, ys).await? {
  833. transaction.rollback().await.map_err(Error::from)?;
  834. return Err(Self::Err::AttemptRemoveSpentProof);
  835. }
  836. // If no proofs are spent, proceed with deletion
  837. let delete_sql = format!(
  838. "DELETE FROM proof WHERE y IN ({})",
  839. std::iter::repeat("?")
  840. .take(ys.len())
  841. .collect::<Vec<_>>()
  842. .join(",")
  843. );
  844. ys.iter()
  845. .fold(sqlx::query(&delete_sql), |query, y| {
  846. query.bind(y.to_bytes().to_vec())
  847. })
  848. .execute(&mut *transaction)
  849. .await
  850. .map_err(Error::from)?;
  851. transaction.commit().await.map_err(Error::from)?;
  852. Ok(())
  853. }
  854. async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result<Vec<Option<Proof>>, Self::Err> {
  855. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  856. let sql = format!(
  857. "SELECT * FROM proof WHERE y IN ({})",
  858. "?,".repeat(ys.len()).trim_end_matches(',')
  859. );
  860. let mut proofs = ys
  861. .iter()
  862. .fold(sqlx::query(&sql), |query, y| {
  863. query.bind(y.to_bytes().to_vec())
  864. })
  865. .fetch_all(&mut *transaction)
  866. .await
  867. .map_err(|err| {
  868. tracing::error!("SQLite could not get state of proof: {err:?}");
  869. Error::SQLX(err)
  870. })?
  871. .into_iter()
  872. .map(|row| {
  873. PublicKey::from_slice(row.get("y"))
  874. .map_err(Error::from)
  875. .and_then(|y| sqlite_row_to_proof(row).map(|proof| (y, proof)))
  876. })
  877. .collect::<Result<HashMap<_, _>, _>>()?;
  878. Ok(ys.iter().map(|y| proofs.remove(y)).collect())
  879. }
  880. async fn get_proof_ys_by_quote_id(&self, quote_id: &Uuid) -> Result<Vec<PublicKey>, Self::Err> {
  881. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  882. let rec = sqlx::query(
  883. r#"
  884. SELECT *
  885. FROM proof
  886. WHERE quote_id=?;
  887. "#,
  888. )
  889. .bind(quote_id.as_hyphenated())
  890. .fetch_all(&mut *transaction)
  891. .await;
  892. let ys = match rec {
  893. Ok(rec) => {
  894. transaction.commit().await.map_err(Error::from)?;
  895. let proofs = rec
  896. .into_iter()
  897. .map(sqlite_row_to_proof)
  898. .collect::<Result<Vec<Proof>, _>>()?;
  899. proofs.ys()?
  900. }
  901. Err(err) => match err {
  902. sqlx::Error::RowNotFound => {
  903. transaction.commit().await.map_err(Error::from)?;
  904. vec![]
  905. }
  906. _ => {
  907. if let Err(err) = transaction.rollback().await {
  908. tracing::error!("Could not rollback sql transaction: {}", err);
  909. }
  910. return Err(Error::SQLX(err).into());
  911. }
  912. },
  913. };
  914. Ok(ys)
  915. }
  916. async fn get_proofs_states(&self, ys: &[PublicKey]) -> Result<Vec<Option<State>>, Self::Err> {
  917. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  918. let sql = format!(
  919. "SELECT y, state FROM proof WHERE y IN ({})",
  920. "?,".repeat(ys.len()).trim_end_matches(',')
  921. );
  922. let mut current_states = ys
  923. .iter()
  924. .fold(sqlx::query(&sql), |query, y| {
  925. query.bind(y.to_bytes().to_vec())
  926. })
  927. .fetch_all(&mut *transaction)
  928. .await
  929. .map_err(|err| {
  930. tracing::error!("SQLite could not get state of proof: {err:?}");
  931. Error::SQLX(err)
  932. })?
  933. .into_iter()
  934. .map(|row| {
  935. PublicKey::from_slice(row.get("y"))
  936. .map_err(Error::from)
  937. .and_then(|y| {
  938. let state: String = row.get("state");
  939. State::from_str(&state)
  940. .map_err(Error::from)
  941. .map(|state| (y, state))
  942. })
  943. })
  944. .collect::<Result<HashMap<_, _>, _>>()?;
  945. Ok(ys.iter().map(|y| current_states.remove(y)).collect())
  946. }
  947. async fn get_proofs_by_keyset_id(
  948. &self,
  949. keyset_id: &Id,
  950. ) -> Result<(Proofs, Vec<Option<State>>), Self::Err> {
  951. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  952. let rec = sqlx::query(
  953. r#"
  954. SELECT *
  955. FROM proof
  956. WHERE keyset_id=?;
  957. "#,
  958. )
  959. .bind(keyset_id.to_string())
  960. .fetch_all(&mut *transaction)
  961. .await;
  962. match rec {
  963. Ok(rec) => {
  964. transaction.commit().await.map_err(Error::from)?;
  965. let mut proofs_for_id = vec![];
  966. let mut states = vec![];
  967. for row in rec {
  968. let (proof, state) = sqlite_row_to_proof_with_state(row)?;
  969. proofs_for_id.push(proof);
  970. states.push(state);
  971. }
  972. Ok((proofs_for_id, states))
  973. }
  974. Err(err) => {
  975. tracing::error!("SQLite could not get proofs by keysets id");
  976. if let Err(err) = transaction.rollback().await {
  977. tracing::error!("Could not rollback sql transaction: {}", err);
  978. }
  979. return Err(Error::from(err).into());
  980. }
  981. }
  982. }
  983. async fn update_proofs_states(
  984. &self,
  985. ys: &[PublicKey],
  986. proofs_state: State,
  987. ) -> Result<Vec<Option<State>>, Self::Err> {
  988. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  989. let sql = format!(
  990. "SELECT y, state FROM proof WHERE y IN ({})",
  991. "?,".repeat(ys.len()).trim_end_matches(',')
  992. );
  993. let rows = ys
  994. .iter()
  995. .fold(sqlx::query(&sql), |query, y| {
  996. query.bind(y.to_bytes().to_vec())
  997. })
  998. .fetch_all(&mut *transaction)
  999. .await
  1000. .map_err(|err| {
  1001. tracing::error!("SQLite could not get state of proof: {err:?}");
  1002. Error::SQLX(err)
  1003. })?;
  1004. // Check if all proofs exist
  1005. if rows.len() != ys.len() {
  1006. transaction.rollback().await.map_err(Error::from)?;
  1007. tracing::warn!("Attempted to update state of non-existent proof");
  1008. return Err(database::Error::ProofNotFound);
  1009. }
  1010. let mut current_states = rows
  1011. .into_iter()
  1012. .map(|row| {
  1013. PublicKey::from_slice(row.get("y"))
  1014. .map_err(Error::from)
  1015. .and_then(|y| {
  1016. let state: String = row.get("state");
  1017. State::from_str(&state)
  1018. .map_err(Error::from)
  1019. .map(|state| (y, state))
  1020. })
  1021. })
  1022. .collect::<Result<HashMap<_, _>, _>>()?;
  1023. let states = current_states.values().collect::<HashSet<_>>();
  1024. if states.contains(&State::Spent) {
  1025. transaction.rollback().await.map_err(Error::from)?;
  1026. tracing::warn!("Attempted to update state of spent proof");
  1027. return Err(database::Error::AttemptUpdateSpentProof);
  1028. }
  1029. // If no proofs are spent, proceed with update
  1030. let update_sql = format!(
  1031. "UPDATE proof SET state = ? WHERE y IN ({})",
  1032. "?,".repeat(ys.len()).trim_end_matches(',')
  1033. );
  1034. ys.iter()
  1035. .fold(
  1036. sqlx::query(&update_sql).bind(proofs_state.to_string()),
  1037. |query, y| query.bind(y.to_bytes().to_vec()),
  1038. )
  1039. .execute(&mut *transaction)
  1040. .await
  1041. .map_err(|err| {
  1042. tracing::error!("SQLite could not update proof state: {err:?}");
  1043. Error::SQLX(err)
  1044. })?;
  1045. transaction.commit().await.map_err(Error::from)?;
  1046. Ok(ys.iter().map(|y| current_states.remove(y)).collect())
  1047. }
  1048. async fn add_blind_signatures(
  1049. &self,
  1050. blinded_messages: &[PublicKey],
  1051. blinded_signatures: &[BlindSignature],
  1052. quote_id: Option<Uuid>,
  1053. ) -> Result<(), Self::Err> {
  1054. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1055. for (message, signature) in blinded_messages.iter().zip(blinded_signatures) {
  1056. let res = sqlx::query(
  1057. r#"
  1058. INSERT INTO blind_signature
  1059. (y, amount, keyset_id, c, quote_id, dleq_e, dleq_s)
  1060. VALUES (?, ?, ?, ?, ?, ?, ?);
  1061. "#,
  1062. )
  1063. .bind(message.to_bytes().to_vec())
  1064. .bind(u64::from(signature.amount) as i64)
  1065. .bind(signature.keyset_id.to_string())
  1066. .bind(signature.c.to_bytes().to_vec())
  1067. .bind(quote_id.map(|q| q.hyphenated()))
  1068. .bind(signature.dleq.as_ref().map(|dleq| dleq.e.to_secret_hex()))
  1069. .bind(signature.dleq.as_ref().map(|dleq| dleq.s.to_secret_hex()))
  1070. .execute(&mut *transaction)
  1071. .await;
  1072. if let Err(err) = res {
  1073. tracing::error!("SQLite could not add blind signature");
  1074. if let Err(err) = transaction.rollback().await {
  1075. tracing::error!("Could not rollback sql transaction: {}", err);
  1076. }
  1077. return Err(Error::SQLX(err).into());
  1078. }
  1079. }
  1080. transaction.commit().await.map_err(Error::from)?;
  1081. Ok(())
  1082. }
  1083. async fn get_blind_signatures(
  1084. &self,
  1085. blinded_messages: &[PublicKey],
  1086. ) -> Result<Vec<Option<BlindSignature>>, Self::Err> {
  1087. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1088. let sql = format!(
  1089. "SELECT * FROM blind_signature WHERE y IN ({})",
  1090. "?,".repeat(blinded_messages.len()).trim_end_matches(',')
  1091. );
  1092. let mut blinded_signatures = blinded_messages
  1093. .iter()
  1094. .fold(sqlx::query(&sql), |query, y| {
  1095. query.bind(y.to_bytes().to_vec())
  1096. })
  1097. .fetch_all(&mut *transaction)
  1098. .await
  1099. .map_err(|err| {
  1100. tracing::error!("SQLite could not get state of proof: {err:?}");
  1101. Error::SQLX(err)
  1102. })?
  1103. .into_iter()
  1104. .map(|row| {
  1105. PublicKey::from_slice(row.get("y"))
  1106. .map_err(Error::from)
  1107. .and_then(|y| sqlite_row_to_blind_signature(row).map(|blinded| (y, blinded)))
  1108. })
  1109. .collect::<Result<HashMap<_, _>, _>>()?;
  1110. Ok(blinded_messages
  1111. .iter()
  1112. .map(|y| blinded_signatures.remove(y))
  1113. .collect())
  1114. }
  1115. async fn get_blind_signatures_for_keyset(
  1116. &self,
  1117. keyset_id: &Id,
  1118. ) -> Result<Vec<BlindSignature>, Self::Err> {
  1119. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1120. let rec = sqlx::query(
  1121. r#"
  1122. SELECT *
  1123. FROM blind_signature
  1124. WHERE keyset_id=?;
  1125. "#,
  1126. )
  1127. .bind(keyset_id.to_string())
  1128. .fetch_all(&mut *transaction)
  1129. .await;
  1130. match rec {
  1131. Ok(rec) => {
  1132. transaction.commit().await.map_err(Error::from)?;
  1133. let sigs = rec
  1134. .into_iter()
  1135. .map(sqlite_row_to_blind_signature)
  1136. .collect::<Result<Vec<BlindSignature>, _>>()?;
  1137. Ok(sigs)
  1138. }
  1139. Err(err) => {
  1140. tracing::error!("SQLite could not get vlinf signatures for keyset");
  1141. if let Err(err) = transaction.rollback().await {
  1142. tracing::error!("Could not rollback sql transaction: {}", err);
  1143. }
  1144. return Err(Error::from(err).into());
  1145. }
  1146. }
  1147. }
  1148. async fn add_melt_request(
  1149. &self,
  1150. melt_request: MeltBolt11Request<Uuid>,
  1151. ln_key: PaymentProcessorKey,
  1152. ) -> Result<(), Self::Err> {
  1153. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1154. let res = sqlx::query(
  1155. r#"
  1156. INSERT INTO melt_request
  1157. (id, inputs, outputs, method, unit)
  1158. VALUES (?, ?, ?, ?, ?)
  1159. ON CONFLICT(id) DO UPDATE SET
  1160. inputs = excluded.inputs,
  1161. outputs = excluded.outputs,
  1162. method = excluded.method,
  1163. unit = excluded.unit
  1164. "#,
  1165. )
  1166. .bind(melt_request.quote)
  1167. .bind(serde_json::to_string(&melt_request.inputs)?)
  1168. .bind(serde_json::to_string(&melt_request.outputs)?)
  1169. .bind(ln_key.method.to_string())
  1170. .bind(ln_key.unit.to_string())
  1171. .execute(&mut *transaction)
  1172. .await;
  1173. match res {
  1174. Ok(_) => {
  1175. transaction.commit().await.map_err(Error::from)?;
  1176. Ok(())
  1177. }
  1178. Err(err) => {
  1179. tracing::error!("SQLite Could not update keyset");
  1180. if let Err(err) = transaction.rollback().await {
  1181. tracing::error!("Could not rollback sql transaction: {}", err);
  1182. }
  1183. Err(Error::from(err).into())
  1184. }
  1185. }
  1186. }
  1187. async fn get_melt_request(
  1188. &self,
  1189. quote_id: &Uuid,
  1190. ) -> Result<Option<(MeltBolt11Request<Uuid>, PaymentProcessorKey)>, Self::Err> {
  1191. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1192. let rec = sqlx::query(
  1193. r#"
  1194. SELECT *
  1195. FROM melt_request
  1196. WHERE id=?;
  1197. "#,
  1198. )
  1199. .bind(quote_id.as_hyphenated())
  1200. .fetch_one(&mut *transaction)
  1201. .await;
  1202. match rec {
  1203. Ok(rec) => {
  1204. transaction.commit().await.map_err(Error::from)?;
  1205. let (request, key) = sqlite_row_to_melt_request(rec)?;
  1206. Ok(Some((request, key)))
  1207. }
  1208. Err(err) => match err {
  1209. sqlx::Error::RowNotFound => {
  1210. transaction.commit().await.map_err(Error::from)?;
  1211. return Ok(None);
  1212. }
  1213. _ => {
  1214. return {
  1215. if let Err(err) = transaction.rollback().await {
  1216. tracing::error!("Could not rollback sql transaction: {}", err);
  1217. }
  1218. Err(Error::SQLX(err).into())
  1219. }
  1220. }
  1221. },
  1222. }
  1223. }
  1224. /// Get [`BlindSignature`]s for quote
  1225. async fn get_blind_signatures_for_quote(
  1226. &self,
  1227. quote_id: &Uuid,
  1228. ) -> Result<Vec<BlindSignature>, Self::Err> {
  1229. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1230. let recs = sqlx::query(
  1231. r#"
  1232. SELECT *
  1233. FROM blind_signature
  1234. WHERE quote_id=?;
  1235. "#,
  1236. )
  1237. .bind(quote_id.as_hyphenated())
  1238. .fetch_all(&mut *transaction)
  1239. .await;
  1240. match recs {
  1241. Ok(recs) => {
  1242. transaction.commit().await.map_err(Error::from)?;
  1243. let keysets = recs
  1244. .into_iter()
  1245. .map(sqlite_row_to_blind_signature)
  1246. .collect::<Result<Vec<_>, _>>()?;
  1247. Ok(keysets)
  1248. }
  1249. Err(err) => {
  1250. tracing::error!("SQLite could not get active keyset");
  1251. if let Err(err) = transaction.rollback().await {
  1252. tracing::error!("Could not rollback sql transaction: {}", err);
  1253. }
  1254. Err(Error::from(err).into())
  1255. }
  1256. }
  1257. }
  1258. async fn set_mint_info(&self, mint_info: MintInfo) -> Result<(), Self::Err> {
  1259. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1260. let res = sqlx::query(
  1261. r#"
  1262. INSERT INTO config
  1263. (id, value)
  1264. VALUES (?, ?)
  1265. ON CONFLICT(id) DO UPDATE SET
  1266. value = excluded.value
  1267. ;
  1268. "#,
  1269. )
  1270. .bind("mint_info")
  1271. .bind(serde_json::to_string(&mint_info)?)
  1272. .execute(&mut *transaction)
  1273. .await;
  1274. match res {
  1275. Ok(_) => {
  1276. transaction.commit().await.map_err(Error::from)?;
  1277. Ok(())
  1278. }
  1279. Err(err) => {
  1280. tracing::error!("SQLite Could not update mint info");
  1281. if let Err(err) = transaction.rollback().await {
  1282. tracing::error!("Could not rollback sql transaction: {}", err);
  1283. }
  1284. Err(Error::from(err).into())
  1285. }
  1286. }
  1287. }
  1288. async fn get_mint_info(&self) -> Result<MintInfo, Self::Err> {
  1289. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1290. let rec = sqlx::query(
  1291. r#"
  1292. SELECT *
  1293. FROM config
  1294. WHERE id=?;
  1295. "#,
  1296. )
  1297. .bind("mint_info")
  1298. .fetch_one(&mut *transaction)
  1299. .await;
  1300. match rec {
  1301. Ok(rec) => {
  1302. transaction.commit().await.map_err(Error::from)?;
  1303. let value: String = rec.try_get("value").map_err(Error::from)?;
  1304. let mint_info = serde_json::from_str(&value)?;
  1305. Ok(mint_info)
  1306. }
  1307. Err(err) => match err {
  1308. sqlx::Error::RowNotFound => {
  1309. transaction.commit().await.map_err(Error::from)?;
  1310. return Err(Error::UnknownMintInfo.into());
  1311. }
  1312. _ => {
  1313. return {
  1314. if let Err(err) = transaction.rollback().await {
  1315. tracing::error!("Could not rollback sql transaction: {}", err);
  1316. }
  1317. Err(Error::SQLX(err).into())
  1318. }
  1319. }
  1320. },
  1321. }
  1322. }
  1323. async fn set_quote_ttl(&self, quote_ttl: QuoteTTL) -> Result<(), Self::Err> {
  1324. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1325. let res = sqlx::query(
  1326. r#"
  1327. INSERT INTO config
  1328. (id, value)
  1329. VALUES (?, ?)
  1330. ON CONFLICT(id) DO UPDATE SET
  1331. value = excluded.value
  1332. ;
  1333. "#,
  1334. )
  1335. .bind("quote_ttl")
  1336. .bind(serde_json::to_string(&quote_ttl)?)
  1337. .execute(&mut *transaction)
  1338. .await;
  1339. match res {
  1340. Ok(_) => {
  1341. transaction.commit().await.map_err(Error::from)?;
  1342. Ok(())
  1343. }
  1344. Err(err) => {
  1345. tracing::error!("SQLite Could not update mint info");
  1346. if let Err(err) = transaction.rollback().await {
  1347. tracing::error!("Could not rollback sql transaction: {}", err);
  1348. }
  1349. Err(Error::from(err).into())
  1350. }
  1351. }
  1352. }
  1353. async fn get_quote_ttl(&self) -> Result<QuoteTTL, Self::Err> {
  1354. let mut transaction = self.pool.begin().await.map_err(Error::from)?;
  1355. let rec = sqlx::query(
  1356. r#"
  1357. SELECT *
  1358. FROM config
  1359. WHERE id=?;
  1360. "#,
  1361. )
  1362. .bind("quote_ttl")
  1363. .fetch_one(&mut *transaction)
  1364. .await;
  1365. match rec {
  1366. Ok(rec) => {
  1367. transaction.commit().await.map_err(Error::from)?;
  1368. let value: String = rec.try_get("value").map_err(Error::from)?;
  1369. let quote_ttl = serde_json::from_str(&value)?;
  1370. Ok(quote_ttl)
  1371. }
  1372. Err(err) => match err {
  1373. sqlx::Error::RowNotFound => {
  1374. transaction.commit().await.map_err(Error::from)?;
  1375. return Err(Error::UnknownQuoteTTL.into());
  1376. }
  1377. _ => {
  1378. return {
  1379. if let Err(err) = transaction.rollback().await {
  1380. tracing::error!("Could not rollback sql transaction: {}", err);
  1381. }
  1382. Err(Error::SQLX(err).into())
  1383. }
  1384. }
  1385. },
  1386. }
  1387. }
  1388. }
  1389. fn sqlite_row_to_keyset_info(row: SqliteRow) -> Result<MintKeySetInfo, Error> {
  1390. let row_id: String = row.try_get("id").map_err(Error::from)?;
  1391. let row_unit: String = row.try_get("unit").map_err(Error::from)?;
  1392. let row_active: bool = row.try_get("active").map_err(Error::from)?;
  1393. let row_valid_from: i64 = row.try_get("valid_from").map_err(Error::from)?;
  1394. let row_valid_to: Option<i64> = row.try_get("valid_to").map_err(Error::from)?;
  1395. let row_derivation_path: String = row.try_get("derivation_path").map_err(Error::from)?;
  1396. let row_max_order: u8 = row.try_get("max_order").map_err(Error::from)?;
  1397. let row_keyset_ppk: Option<i64> = row.try_get("input_fee_ppk").ok();
  1398. let row_derivation_path_index: Option<i64> =
  1399. row.try_get("derivation_path_index").map_err(Error::from)?;
  1400. Ok(MintKeySetInfo {
  1401. id: Id::from_str(&row_id).map_err(Error::from)?,
  1402. unit: CurrencyUnit::from_str(&row_unit).map_err(Error::from)?,
  1403. active: row_active,
  1404. valid_from: row_valid_from as u64,
  1405. valid_to: row_valid_to.map(|v| v as u64),
  1406. derivation_path: DerivationPath::from_str(&row_derivation_path).map_err(Error::from)?,
  1407. derivation_path_index: row_derivation_path_index.map(|d| d as u32),
  1408. max_order: row_max_order,
  1409. input_fee_ppk: row_keyset_ppk.unwrap_or(0) as u64,
  1410. })
  1411. }
  1412. fn sqlite_row_to_mint_quote(row: SqliteRow) -> Result<MintQuote, Error> {
  1413. let row_id: Hyphenated = row.try_get("id").map_err(Error::from)?;
  1414. let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
  1415. let row_unit: String = row.try_get("unit").map_err(Error::from)?;
  1416. let row_request: String = row.try_get("request").map_err(Error::from)?;
  1417. let row_state: String = row.try_get("state").map_err(Error::from)?;
  1418. let row_expiry: i64 = row.try_get("expiry").map_err(Error::from)?;
  1419. let row_request_lookup_id: Option<String> =
  1420. row.try_get("request_lookup_id").map_err(Error::from)?;
  1421. let row_pubkey: Option<String> = row.try_get("pubkey").map_err(Error::from)?;
  1422. let request_lookup_id = match row_request_lookup_id {
  1423. Some(id) => id,
  1424. None => match Bolt11Invoice::from_str(&row_request) {
  1425. Ok(invoice) => invoice.payment_hash().to_string(),
  1426. Err(_) => row_request.clone(),
  1427. },
  1428. };
  1429. let pubkey = row_pubkey
  1430. .map(|key| PublicKey::from_str(&key))
  1431. .transpose()?;
  1432. Ok(MintQuote {
  1433. id: row_id.into_uuid(),
  1434. amount: Amount::from(row_amount as u64),
  1435. unit: CurrencyUnit::from_str(&row_unit).map_err(Error::from)?,
  1436. request: row_request,
  1437. state: MintQuoteState::from_str(&row_state).map_err(Error::from)?,
  1438. expiry: row_expiry as u64,
  1439. request_lookup_id,
  1440. pubkey,
  1441. })
  1442. }
  1443. fn sqlite_row_to_melt_quote(row: SqliteRow) -> Result<mint::MeltQuote, Error> {
  1444. let row_id: Hyphenated = row.try_get("id").map_err(Error::from)?;
  1445. let row_unit: String = row.try_get("unit").map_err(Error::from)?;
  1446. let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
  1447. let row_request: String = row.try_get("request").map_err(Error::from)?;
  1448. let row_fee_reserve: i64 = row.try_get("fee_reserve").map_err(Error::from)?;
  1449. let row_state: String = row.try_get("state").map_err(Error::from)?;
  1450. let row_expiry: i64 = row.try_get("expiry").map_err(Error::from)?;
  1451. let row_preimage: Option<String> = row.try_get("payment_preimage").map_err(Error::from)?;
  1452. let row_request_lookup: Option<String> =
  1453. row.try_get("request_lookup_id").map_err(Error::from)?;
  1454. let request_lookup_id = row_request_lookup.unwrap_or(row_request.clone());
  1455. let row_msat_to_pay: Option<i64> = row.try_get("msat_to_pay").map_err(Error::from)?;
  1456. Ok(mint::MeltQuote {
  1457. id: row_id.into_uuid(),
  1458. amount: Amount::from(row_amount as u64),
  1459. unit: CurrencyUnit::from_str(&row_unit).map_err(Error::from)?,
  1460. request: row_request,
  1461. fee_reserve: Amount::from(row_fee_reserve as u64),
  1462. state: QuoteState::from_str(&row_state)?,
  1463. expiry: row_expiry as u64,
  1464. payment_preimage: row_preimage,
  1465. request_lookup_id,
  1466. msat_to_pay: row_msat_to_pay.map(|a| Amount::from(a as u64)),
  1467. })
  1468. }
  1469. fn sqlite_row_to_proof(row: SqliteRow) -> Result<Proof, Error> {
  1470. let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
  1471. let keyset_id: String = row.try_get("keyset_id").map_err(Error::from)?;
  1472. let row_secret: String = row.try_get("secret").map_err(Error::from)?;
  1473. let row_c: Vec<u8> = row.try_get("c").map_err(Error::from)?;
  1474. let row_witness: Option<String> = row.try_get("witness").map_err(Error::from)?;
  1475. Ok(Proof {
  1476. amount: Amount::from(row_amount as u64),
  1477. keyset_id: Id::from_str(&keyset_id)?,
  1478. secret: Secret::from_str(&row_secret)?,
  1479. c: PublicKey::from_slice(&row_c)?,
  1480. witness: row_witness.and_then(|w| serde_json::from_str(&w).ok()),
  1481. dleq: None,
  1482. })
  1483. }
  1484. fn sqlite_row_to_proof_with_state(row: SqliteRow) -> Result<(Proof, Option<State>), Error> {
  1485. let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
  1486. let keyset_id: String = row.try_get("keyset_id").map_err(Error::from)?;
  1487. let row_secret: String = row.try_get("secret").map_err(Error::from)?;
  1488. let row_c: Vec<u8> = row.try_get("c").map_err(Error::from)?;
  1489. let row_witness: Option<String> = row.try_get("witness").map_err(Error::from)?;
  1490. let row_state: Option<String> = row.try_get("state").map_err(Error::from)?;
  1491. let state = row_state.and_then(|s| State::from_str(&s).ok());
  1492. Ok((
  1493. Proof {
  1494. amount: Amount::from(row_amount as u64),
  1495. keyset_id: Id::from_str(&keyset_id)?,
  1496. secret: Secret::from_str(&row_secret)?,
  1497. c: PublicKey::from_slice(&row_c)?,
  1498. witness: row_witness.and_then(|w| serde_json::from_str(&w).ok()),
  1499. dleq: None,
  1500. },
  1501. state,
  1502. ))
  1503. }
  1504. fn sqlite_row_to_blind_signature(row: SqliteRow) -> Result<BlindSignature, Error> {
  1505. let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
  1506. let keyset_id: String = row.try_get("keyset_id").map_err(Error::from)?;
  1507. let row_c: Vec<u8> = row.try_get("c").map_err(Error::from)?;
  1508. let row_dleq_e: Option<String> = row.try_get("dleq_e").map_err(Error::from)?;
  1509. let row_dleq_s: Option<String> = row.try_get("dleq_s").map_err(Error::from)?;
  1510. let dleq = match (row_dleq_e, row_dleq_s) {
  1511. (Some(e), Some(s)) => Some(BlindSignatureDleq {
  1512. e: SecretKey::from_hex(e)?,
  1513. s: SecretKey::from_hex(s)?,
  1514. }),
  1515. _ => None,
  1516. };
  1517. Ok(BlindSignature {
  1518. amount: Amount::from(row_amount as u64),
  1519. keyset_id: Id::from_str(&keyset_id)?,
  1520. c: PublicKey::from_slice(&row_c)?,
  1521. dleq,
  1522. })
  1523. }
  1524. fn sqlite_row_to_melt_request(
  1525. row: SqliteRow,
  1526. ) -> Result<(MeltBolt11Request<Uuid>, PaymentProcessorKey), Error> {
  1527. let quote_id: Hyphenated = row.try_get("id").map_err(Error::from)?;
  1528. let row_inputs: String = row.try_get("inputs").map_err(Error::from)?;
  1529. let row_outputs: Option<String> = row.try_get("outputs").map_err(Error::from)?;
  1530. let row_method: String = row.try_get("method").map_err(Error::from)?;
  1531. let row_unit: String = row.try_get("unit").map_err(Error::from)?;
  1532. let melt_request = MeltBolt11Request {
  1533. quote: quote_id.into_uuid(),
  1534. inputs: serde_json::from_str(&row_inputs)?,
  1535. outputs: row_outputs.and_then(|o| serde_json::from_str(&o).ok()),
  1536. };
  1537. let ln_key = PaymentProcessorKey {
  1538. unit: CurrencyUnit::from_str(&row_unit)?,
  1539. method: PaymentMethod::from_str(&row_method)?,
  1540. };
  1541. Ok((melt_request, ln_key))
  1542. }
  1543. #[cfg(test)]
  1544. mod tests {
  1545. use cdk_common::mint::MintKeySetInfo;
  1546. use cdk_common::Amount;
  1547. use super::*;
  1548. #[tokio::test]
  1549. async fn test_remove_spent_proofs() {
  1550. let db = memory::empty().await.unwrap();
  1551. // Create a keyset and add it to the database
  1552. let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
  1553. let keyset_info = MintKeySetInfo {
  1554. id: keyset_id,
  1555. unit: CurrencyUnit::Sat,
  1556. active: true,
  1557. valid_from: 0,
  1558. valid_to: None,
  1559. derivation_path: bitcoin::bip32::DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  1560. derivation_path_index: Some(0),
  1561. max_order: 32,
  1562. input_fee_ppk: 0,
  1563. };
  1564. db.add_keyset_info(keyset_info).await.unwrap();
  1565. let proofs = vec![
  1566. Proof {
  1567. amount: Amount::from(100),
  1568. keyset_id,
  1569. secret: Secret::generate(),
  1570. c: SecretKey::generate().public_key(),
  1571. witness: None,
  1572. dleq: None,
  1573. },
  1574. Proof {
  1575. amount: Amount::from(200),
  1576. keyset_id,
  1577. secret: Secret::generate(),
  1578. c: SecretKey::generate().public_key(),
  1579. witness: None,
  1580. dleq: None,
  1581. },
  1582. ];
  1583. // Add proofs to database
  1584. db.add_proofs(proofs.clone(), None).await.unwrap();
  1585. // Mark one proof as spent
  1586. db.update_proofs_states(&[proofs[0].y().unwrap()], State::Spent)
  1587. .await
  1588. .unwrap();
  1589. // Try to remove both proofs - should fail because one is spent
  1590. let result = db
  1591. .remove_proofs(&[proofs[0].y().unwrap(), proofs[1].y().unwrap()], None)
  1592. .await;
  1593. assert!(result.is_err());
  1594. assert!(matches!(
  1595. result.unwrap_err(),
  1596. database::Error::AttemptRemoveSpentProof
  1597. ));
  1598. // Verify both proofs still exist
  1599. let states = db
  1600. .get_proofs_states(&[proofs[0].y().unwrap(), proofs[1].y().unwrap()])
  1601. .await
  1602. .unwrap();
  1603. assert_eq!(states.len(), 2);
  1604. assert_eq!(states[0], Some(State::Spent));
  1605. assert_eq!(states[1], Some(State::Unspent));
  1606. }
  1607. #[tokio::test]
  1608. async fn test_update_spent_proofs() {
  1609. let db = memory::empty().await.unwrap();
  1610. // Create a keyset and add it to the database
  1611. let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
  1612. let keyset_info = MintKeySetInfo {
  1613. id: keyset_id,
  1614. unit: CurrencyUnit::Sat,
  1615. active: true,
  1616. valid_from: 0,
  1617. valid_to: None,
  1618. derivation_path: bitcoin::bip32::DerivationPath::from_str("m/0'/0'/0'").unwrap(),
  1619. derivation_path_index: Some(0),
  1620. max_order: 32,
  1621. input_fee_ppk: 0,
  1622. };
  1623. db.add_keyset_info(keyset_info).await.unwrap();
  1624. let proofs = vec![
  1625. Proof {
  1626. amount: Amount::from(100),
  1627. keyset_id,
  1628. secret: Secret::generate(),
  1629. c: SecretKey::generate().public_key(),
  1630. witness: None,
  1631. dleq: None,
  1632. },
  1633. Proof {
  1634. amount: Amount::from(200),
  1635. keyset_id,
  1636. secret: Secret::generate(),
  1637. c: SecretKey::generate().public_key(),
  1638. witness: None,
  1639. dleq: None,
  1640. },
  1641. ];
  1642. // Add proofs to database
  1643. db.add_proofs(proofs.clone(), None).await.unwrap();
  1644. // Mark one proof as spent
  1645. db.update_proofs_states(&[proofs[0].y().unwrap()], State::Spent)
  1646. .await
  1647. .unwrap();
  1648. // Try to update both proofs - should fail because one is spent
  1649. let result = db
  1650. .update_proofs_states(
  1651. &[proofs[0].y().unwrap(), proofs[1].y().unwrap()],
  1652. State::Reserved,
  1653. )
  1654. .await;
  1655. assert!(result.is_err());
  1656. assert!(matches!(
  1657. result.unwrap_err(),
  1658. database::Error::AttemptUpdateSpentProof
  1659. ));
  1660. // Verify states haven't changed
  1661. let states = db
  1662. .get_proofs_states(&[proofs[0].y().unwrap(), proofs[1].y().unwrap()])
  1663. .await
  1664. .unwrap();
  1665. assert_eq!(states.len(), 2);
  1666. assert_eq!(states[0], Some(State::Spent));
  1667. assert_eq!(states[1], Some(State::Unspent));
  1668. }
  1669. }