mod.rs 55 KB

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