mod.rs 66 KB

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