From 2eca18007ddf30609460c2903ca2395f87aac13e Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Sun, 14 Apr 2024 22:55:00 +0100 Subject: [PATCH] refactor: mint redb database --- Cargo.toml | 1 + crates/cdk-redb/Cargo.toml | 1 + crates/cdk-redb/src/lib.rs | 2 + .../src/mint_redb.rs} | 63 +++- crates/cdk-redb/src/wallet_redb.rs | 306 ++++++------------ .../memory.rs => cdk_database/mint_memory.rs} | 57 ++-- crates/cdk/src/cdk_database/mod.rs | 63 +++- crates/cdk/src/mint/mod.rs | 21 +- 8 files changed, 264 insertions(+), 250 deletions(-) rename crates/{cdk/src/mint/localstore/redb_store.rs => cdk-redb/src/mint_redb.rs} (91%) rename crates/cdk/src/{mint/localstore/memory.rs => cdk_database/mint_memory.rs} (87%) diff --git a/Cargo.toml b/Cargo.toml index 33c0e04b..3337909e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ tokio = { version = "1.32", default-features = false } cdk = { path = "./crates/cdk", default-features = false } thiserror = "1.0.50" async-trait = "0.1.74" +tracing = { version = "0.1", default-features = false } [profile] diff --git a/crates/cdk-redb/Cargo.toml b/crates/cdk-redb/Cargo.toml index db184f96..2bf3483d 100644 --- a/crates/cdk-redb/Cargo.toml +++ b/crates/cdk-redb/Cargo.toml @@ -15,4 +15,5 @@ cdk.workspace = true redb = "2.0.0" tokio.workspace = true thiserror.workspace = true +tracing.workspace = true serde_json = "1.0.96" diff --git a/crates/cdk-redb/src/lib.rs b/crates/cdk-redb/src/lib.rs index 567166b4..72e5c14e 100644 --- a/crates/cdk-redb/src/lib.rs +++ b/crates/cdk-redb/src/lib.rs @@ -1,3 +1,5 @@ +pub mod mint_redb; pub mod wallet_redb; +pub use mint_redb::MintRedbDatabase; pub use wallet_redb::RedbWalletDatabase; diff --git a/crates/cdk/src/mint/localstore/redb_store.rs b/crates/cdk-redb/src/mint_redb.rs similarity index 91% rename from crates/cdk/src/mint/localstore/redb_store.rs rename to crates/cdk-redb/src/mint_redb.rs index d8bdaae4..2836fd4e 100644 --- a/crates/cdk/src/mint/localstore/redb_store.rs +++ b/crates/cdk-redb/src/mint_redb.rs @@ -1,19 +1,20 @@ use std::collections::HashMap; +use std::num::ParseIntError; use std::str::FromStr; use std::sync::Arc; use async_trait::async_trait; -use redb::{Database, ReadableTable, TableDefinition}; -use tokio::sync::Mutex; -use tracing::debug; - -use super::{Error, LocalStore}; -use crate::dhke::hash_to_curve; -use crate::nuts::{ +use cdk::cdk_database::{self, MintDatabase}; +use cdk::dhke::hash_to_curve; +use cdk::nuts::{ BlindSignature, CurrencyUnit, Id, MintInfo, MintKeySet as KeySet, Proof, PublicKey, }; -use crate::secret::Secret; -use crate::types::{MeltQuote, MintQuote}; +use cdk::secret::Secret; +use cdk::types::{MeltQuote, MintQuote}; +use redb::{Database, ReadableTable, TableDefinition}; +use thiserror::Error; +use tokio::sync::Mutex; +use tracing::debug; const ACTIVE_KEYSETS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("active_keysets"); const KEYSETS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("keysets"); @@ -29,12 +30,48 @@ const BLINDED_SIGNATURES: TableDefinition<[u8; 33], &str> = const DATABASE_VERSION: u64 = 0; +#[derive(Debug, Error)] +pub enum Error { + #[error(transparent)] + Redb(#[from] redb::Error), + #[error(transparent)] + Database(#[from] redb::DatabaseError), + #[error(transparent)] + Transaction(#[from] redb::TransactionError), + #[error(transparent)] + Commit(#[from] redb::CommitError), + #[error(transparent)] + Table(#[from] redb::TableError), + #[error(transparent)] + Storage(#[from] redb::StorageError), + #[error(transparent)] + Serde(#[from] serde_json::Error), + #[error(transparent)] + ParseInt(#[from] ParseIntError), + #[error(transparent)] + CDKDatabase(#[from] cdk_database::Error), + #[error(transparent)] + CDK(#[from] cdk::error::Error), + #[error(transparent)] + CDKNUT02(#[from] cdk::nuts::nut02::Error), + #[error(transparent)] + CDKNUT00(#[from] cdk::nuts::nut00::Error), + #[error("Unknown Mint Info")] + UnknownMintInfo, +} + +impl From for cdk_database::Error { + fn from(e: Error) -> Self { + Self::Database(Box::new(e)) + } +} + #[derive(Debug, Clone)] -pub struct RedbLocalStore { +pub struct MintRedbDatabase { db: Arc>, } -impl RedbLocalStore { +impl MintRedbDatabase { pub fn new(path: &str) -> Result { let db = Database::create(path)?; @@ -78,7 +115,9 @@ impl RedbLocalStore { } #[async_trait] -impl LocalStore for RedbLocalStore { +impl MintDatabase for MintRedbDatabase { + type Err = Error; + async fn set_mint_info(&self, mint_info: &MintInfo) -> Result<(), Error> { let db = self.db.lock().await; diff --git a/crates/cdk-redb/src/wallet_redb.rs b/crates/cdk-redb/src/wallet_redb.rs index 7a6e2163..be8c87c9 100644 --- a/crates/cdk-redb/src/wallet_redb.rs +++ b/crates/cdk-redb/src/wallet_redb.rs @@ -30,6 +30,8 @@ pub enum Error { Serde(#[from] serde_json::Error), #[error(transparent)] ParseInt(#[from] ParseIntError), + #[error(transparent)] + CDKDatabase(#[from] cdk_database::Error), } impl From for cdk_database::Error { @@ -102,7 +104,7 @@ impl RedbWalletDatabase { #[async_trait] impl WalletDatabase for RedbWalletDatabase { - type Err = cdk_database::Error; + type Err = Error; async fn add_mint( &self, @@ -111,22 +113,20 @@ impl WalletDatabase for RedbWalletDatabase { ) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { let mut table = write_txn .open_table(MINTS_TABLE) .map_err(Into::::into)?; - table - .insert( - mint_url.to_string().as_str(), - serde_json::to_string(&mint_info) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + table.insert( + mint_url.to_string().as_str(), + serde_json::to_string(&mint_info) + .map_err(Into::::into)? + .as_str(), + )?; } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } @@ -134,15 +134,10 @@ impl WalletDatabase for RedbWalletDatabase { async fn get_mint(&self, mint_url: UncheckedUrl) -> Result, Self::Err> { let db = self.db.lock().await; let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_table(MINTS_TABLE) - .map_err(Into::::into)?; + let table = read_txn.open_table(MINTS_TABLE)?; - if let Some(mint_info) = table - .get(mint_url.to_string().as_str()) - .map_err(Into::::into)? - { - return Ok(serde_json::from_str(mint_info.value()).map_err(Into::::into)?); + if let Some(mint_info) = table.get(mint_url.to_string().as_str())? { + return Ok(serde_json::from_str(mint_info.value())?); } Ok(None) @@ -156,8 +151,7 @@ impl WalletDatabase for RedbWalletDatabase { .map_err(Into::::into)?; let mints = table - .iter() - .map_err(Into::::into)? + .iter()? .flatten() .map(|(mint, mint_info)| { ( @@ -177,25 +171,19 @@ impl WalletDatabase for RedbWalletDatabase { ) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_multimap_table(MINT_KEYSETS_TABLE) - .map_err(Into::::into)?; + let mut table = write_txn.open_multimap_table(MINT_KEYSETS_TABLE)?; for keyset in keysets { - table - .insert( - mint_url.to_string().as_str(), - serde_json::to_string(&keyset) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + table.insert( + mint_url.to_string().as_str(), + serde_json::to_string(&keyset)?.as_str(), + )?; } } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } @@ -206,13 +194,10 @@ impl WalletDatabase for RedbWalletDatabase { ) -> Result>, Self::Err> { let db = self.db.lock().await; let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_multimap_table(MINT_KEYSETS_TABLE) - .map_err(Into::::into)?; + let table = read_txn.open_multimap_table(MINT_KEYSETS_TABLE)?; let keysets = table - .get(mint_url.to_string().as_str()) - .map_err(Into::::into)? + .get(mint_url.to_string().as_str())? .flatten() .flat_map(|k| serde_json::from_str(k.value())) .collect(); @@ -222,19 +207,12 @@ impl WalletDatabase for RedbWalletDatabase { async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_table(MINT_QUOTES_TABLE) - .map_err(Into::::into)?; + let mut table = write_txn.open_table(MINT_QUOTES_TABLE)?; table - .insert( - quote.id.as_str(), - serde_json::to_string("e) - .map_err(Into::::into)? - .as_str(), - ) + .insert(quote.id.as_str(), serde_json::to_string("e)?.as_str()) .map_err(Into::::into)?; } @@ -246,12 +224,10 @@ impl WalletDatabase for RedbWalletDatabase { async fn get_mint_quote(&self, quote_id: &str) -> Result, Self::Err> { let db = self.db.lock().await; let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_table(MINT_QUOTES_TABLE) - .map_err(Into::::into)?; + let table = read_txn.open_table(MINT_QUOTES_TABLE)?; - if let Some(mint_info) = table.get(quote_id).map_err(Into::::into)? { - return Ok(serde_json::from_str(mint_info.value()).map_err(Into::::into)?); + if let Some(mint_info) = table.get(quote_id)? { + return Ok(serde_json::from_str(mint_info.value())?); } Ok(None) @@ -259,52 +235,39 @@ impl WalletDatabase for RedbWalletDatabase { async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_table(MINT_QUOTES_TABLE) - .map_err(Into::::into)?; - table.remove(quote_id).map_err(Into::::into)?; + let mut table = write_txn.open_table(MINT_QUOTES_TABLE)?; + table.remove(quote_id)?; } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_table(MELT_QUOTES_TABLE) - .map_err(Into::::into)?; - table - .insert( - quote.id.as_str(), - serde_json::to_string("e) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + let mut table = write_txn.open_table(MELT_QUOTES_TABLE)?; + table.insert(quote.id.as_str(), serde_json::to_string("e)?.as_str())?; } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } async fn get_melt_quote(&self, quote_id: &str) -> Result, Self::Err> { let db = self.db.lock().await; - let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_table(MELT_QUOTES_TABLE) - .map_err(Into::::into)?; + let read_txn = db.begin_read()?; + let table = read_txn.open_table(MELT_QUOTES_TABLE)?; - if let Some(mint_info) = table.get(quote_id).map_err(Into::::into)? { - return Ok(serde_json::from_str(mint_info.value()).map_err(Into::::into)?); + if let Some(mint_info) = table.get(quote_id)? { + return Ok(serde_json::from_str(mint_info.value())?); } Ok(None) @@ -312,55 +275,42 @@ impl WalletDatabase for RedbWalletDatabase { async fn remove_melt_quote(&self, quote_id: &str) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_table(MELT_QUOTES_TABLE) - .map_err(Into::::into)?; - table.remove(quote_id).map_err(Into::::into)?; + let mut table = write_txn.open_table(MELT_QUOTES_TABLE)?; + table.remove(quote_id)?; } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } async fn add_keys(&self, keys: Keys) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_table(MINT_KEYS_TABLE) - .map_err(Into::::into)?; - table - .insert( - Id::from(&keys).to_string().as_str(), - serde_json::to_string(&keys) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + let mut table = write_txn.open_table(MINT_KEYS_TABLE)?; + table.insert( + Id::from(&keys).to_string().as_str(), + serde_json::to_string(&keys)?.as_str(), + )?; } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } async fn get_keys(&self, id: &Id) -> Result, Self::Err> { let db = self.db.lock().await; - let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_table(MINT_KEYS_TABLE) - .map_err(Into::::into)?; + let read_txn = db.begin_read()?; + let table = read_txn.open_table(MINT_KEYS_TABLE)?; - if let Some(mint_info) = table - .get(id.to_string().as_str()) - .map_err(Into::::into)? - { - return Ok(serde_json::from_str(mint_info.value()).map_err(Into::::into)?); + if let Some(mint_info) = table.get(id.to_string().as_str())? { + return Ok(serde_json::from_str(mint_info.value())?); } Ok(None) @@ -368,19 +318,15 @@ impl WalletDatabase for RedbWalletDatabase { async fn remove_keys(&self, id: &Id) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_table(MINT_KEYS_TABLE) - .map_err(Into::::into)?; + let mut table = write_txn.open_table(MINT_KEYS_TABLE)?; - table - .remove(id.to_string().as_str()) - .map_err(Into::::into)?; + table.remove(id.to_string().as_str())?; } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } @@ -388,39 +334,30 @@ impl WalletDatabase for RedbWalletDatabase { async fn add_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_multimap_table(PROOFS_TABLE) - .map_err(Into::::into)?; + let mut table = write_txn.open_multimap_table(PROOFS_TABLE)?; for proof in proofs { - table - .insert( - mint_url.to_string().as_str(), - serde_json::to_string(&proof) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + table.insert( + mint_url.to_string().as_str(), + serde_json::to_string(&proof)?.as_str(), + )?; } } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result, Self::Err> { let db = self.db.lock().await; - let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_multimap_table(PROOFS_TABLE) - .map_err(Into::::into)?; + let read_txn = db.begin_read()?; + let table = read_txn.open_multimap_table(PROOFS_TABLE)?; let proofs = table - .get(mint_url.to_string().as_str()) - .map_err(Into::::into)? + .get(mint_url.to_string().as_str())? .flatten() .flat_map(|k| serde_json::from_str(k.value())) .collect(); @@ -435,25 +372,19 @@ impl WalletDatabase for RedbWalletDatabase { ) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_multimap_table(PROOFS_TABLE) - .map_err(Into::::into)?; + let mut table = write_txn.open_multimap_table(PROOFS_TABLE)?; for proof in proofs { - table - .remove( - mint_url.to_string().as_str(), - serde_json::to_string(&proof) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + table.remove( + mint_url.to_string().as_str(), + serde_json::to_string(&proof)?.as_str(), + )?; } } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } @@ -465,25 +396,19 @@ impl WalletDatabase for RedbWalletDatabase { ) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_multimap_table(PENDING_PROOFS_TABLE) - .map_err(Into::::into)?; + let mut table = write_txn.open_multimap_table(PENDING_PROOFS_TABLE)?; for proof in proofs { - table - .insert( - mint_url.to_string().as_str(), - serde_json::to_string(&proof) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + table.insert( + mint_url.to_string().as_str(), + serde_json::to_string(&proof)?.as_str(), + )?; } } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } @@ -493,14 +418,11 @@ impl WalletDatabase for RedbWalletDatabase { mint_url: UncheckedUrl, ) -> Result, Self::Err> { let db = self.db.lock().await; - let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_multimap_table(PENDING_PROOFS_TABLE) - .map_err(Into::::into)?; + let read_txn = db.begin_read()?; + let table = read_txn.open_multimap_table(PENDING_PROOFS_TABLE)?; let proofs = table - .get(mint_url.to_string().as_str()) - .map_err(Into::::into)? + .get(mint_url.to_string().as_str())? .flatten() .flat_map(|k| serde_json::from_str(k.value())) .collect(); @@ -515,25 +437,19 @@ impl WalletDatabase for RedbWalletDatabase { ) -> Result<(), Self::Err> { let db = self.db.lock().await; - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_multimap_table(PENDING_PROOFS_TABLE) - .map_err(Into::::into)?; + let mut table = write_txn.open_multimap_table(PENDING_PROOFS_TABLE)?; for proof in proofs { - table - .remove( - mint_url.to_string().as_str(), - serde_json::to_string(&proof) - .map_err(Into::::into)? - .as_str(), - ) - .map_err(Into::::into)?; + table.remove( + mint_url.to_string().as_str(), + serde_json::to_string(&proof)?.as_str(), + )?; } } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } @@ -543,13 +459,9 @@ impl WalletDatabase for RedbWalletDatabase { let current_counter; { - let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_table(KEYSET_COUNTER) - .map_err(Into::::into)?; - let counter = table - .get(keyset_id.to_string().as_str()) - .map_err(Into::::into)?; + let read_txn = db.begin_read()?; + let table = read_txn.open_table(KEYSET_COUNTER)?; + let counter = table.get(keyset_id.to_string().as_str())?; current_counter = match counter { Some(c) => c.value(), @@ -557,32 +469,24 @@ impl WalletDatabase for RedbWalletDatabase { }; } - let write_txn = db.begin_write().map_err(Into::::into)?; + let write_txn = db.begin_write()?; { - let mut table = write_txn - .open_table(KEYSET_COUNTER) - .map_err(Into::::into)?; + let mut table = write_txn.open_table(KEYSET_COUNTER)?; let new_counter = current_counter + count; - table - .insert(keyset_id.to_string().as_str(), new_counter) - .map_err(Into::::into)?; + table.insert(keyset_id.to_string().as_str(), new_counter)?; } - write_txn.commit().map_err(Into::::into)?; + write_txn.commit()?; Ok(()) } async fn get_keyset_counter(&self, keyset_id: &Id) -> Result, Self::Err> { let db = self.db.lock().await; - let read_txn = db.begin_read().map_err(Into::::into)?; - let table = read_txn - .open_table(KEYSET_COUNTER) - .map_err(Into::::into)?; + let read_txn = db.begin_read()?; + let table = read_txn.open_table(KEYSET_COUNTER)?; - let counter = table - .get(keyset_id.to_string().as_str()) - .map_err(Into::::into)?; + let counter = table.get(keyset_id.to_string().as_str())?; Ok(counter.map(|c| c.value())) } diff --git a/crates/cdk/src/mint/localstore/memory.rs b/crates/cdk/src/cdk_database/mint_memory.rs similarity index 87% rename from crates/cdk/src/mint/localstore/memory.rs rename to crates/cdk/src/cdk_database/mint_memory.rs index e43ed955..c6a9ac61 100644 --- a/crates/cdk/src/mint/localstore/memory.rs +++ b/crates/cdk/src/cdk_database/mint_memory.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use async_trait::async_trait; use tokio::sync::Mutex; -use super::{Error, LocalStore}; +use super::{Error, MintDatabase}; use crate::dhke::hash_to_curve; use crate::nuts::nut02::MintKeySet; use crate::nuts::{BlindSignature, CurrencyUnit, Id, MintInfo, Proof, Proofs, PublicKey}; @@ -12,7 +12,7 @@ use crate::secret::Secret; use crate::types::{MeltQuote, MintQuote}; #[derive(Debug, Clone)] -pub struct MemoryLocalStore { +pub struct MintMemoryDatabase { mint_info: Arc>, active_keysets: Arc>>, keysets: Arc>>, @@ -23,7 +23,7 @@ pub struct MemoryLocalStore { blinded_signatures: Arc>>, } -impl MemoryLocalStore { +impl MintMemoryDatabase { #[allow(clippy::too_many_arguments)] pub fn new( mint_info: MintInfo, @@ -63,25 +63,27 @@ impl MemoryLocalStore { } #[async_trait] -impl LocalStore for MemoryLocalStore { - async fn set_mint_info(&self, mint_info: &MintInfo) -> Result<(), Error> { +impl MintDatabase for MintMemoryDatabase { + type Err = Error; + + async fn set_mint_info(&self, mint_info: &MintInfo) -> Result<(), Self::Err> { let mut mi = self.mint_info.lock().await; *mi = mint_info.clone(); Ok(()) } - async fn get_mint_info(&self) -> Result { + async fn get_mint_info(&self) -> Result { Ok(self.mint_info.lock().await.clone()) } - async fn add_active_keyset(&self, unit: CurrencyUnit, id: Id) -> Result<(), Error> { + async fn add_active_keyset(&self, unit: CurrencyUnit, id: Id) -> Result<(), Self::Err> { self.active_keysets.lock().await.insert(unit, id); Ok(()) } - async fn get_active_keyset_id(&self, unit: &CurrencyUnit) -> Result, Error> { + async fn get_active_keyset_id(&self, unit: &CurrencyUnit) -> Result, Self::Err> { Ok(self.active_keysets.lock().await.get(unit).cloned()) } - async fn get_active_keysets(&self) -> Result, Error> { + async fn get_active_keysets(&self) -> Result, Self::Err> { Ok(self.active_keysets.lock().await.clone()) } @@ -106,21 +108,21 @@ impl LocalStore for MemoryLocalStore { Ok(()) } - async fn get_mint_quote(&self, quote_id: &str) -> Result, Error> { + async fn get_mint_quote(&self, quote_id: &str) -> Result, Self::Err> { Ok(self.mint_quotes.lock().await.get(quote_id).cloned()) } - async fn get_mint_quotes(&self) -> Result, Error> { + async fn get_mint_quotes(&self) -> Result, Self::Err> { Ok(self.mint_quotes.lock().await.values().cloned().collect()) } - async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Error> { + async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Self::Err> { self.mint_quotes.lock().await.remove(quote_id); Ok(()) } - async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), Error> { + async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), Self::Err> { self.melt_quotes .lock() .await @@ -128,21 +130,21 @@ impl LocalStore for MemoryLocalStore { Ok(()) } - async fn get_melt_quote(&self, quote_id: &str) -> Result, Error> { + async fn get_melt_quote(&self, quote_id: &str) -> Result, Self::Err> { Ok(self.melt_quotes.lock().await.get(quote_id).cloned()) } - async fn get_melt_quotes(&self) -> Result, Error> { + async fn get_melt_quotes(&self) -> Result, Self::Err> { Ok(self.melt_quotes.lock().await.values().cloned().collect()) } - async fn remove_melt_quote(&self, quote_id: &str) -> Result<(), Error> { + async fn remove_melt_quote(&self, quote_id: &str) -> Result<(), Self::Err> { self.melt_quotes.lock().await.remove(quote_id); Ok(()) } - async fn add_spent_proof(&self, proof: Proof) -> Result<(), Error> { + async fn add_spent_proof(&self, proof: Proof) -> Result<(), Self::Err> { let secret_point = hash_to_curve(&proof.secret.to_bytes())?; self.spent_proofs .lock() @@ -151,7 +153,7 @@ impl LocalStore for MemoryLocalStore { Ok(()) } - async fn get_spent_proof_by_secret(&self, secret: &Secret) -> Result, Error> { + async fn get_spent_proof_by_secret(&self, secret: &Secret) -> Result, Self::Err> { Ok(self .spent_proofs .lock() @@ -160,11 +162,11 @@ impl LocalStore for MemoryLocalStore { .cloned()) } - async fn get_spent_proof_by_y(&self, y: &PublicKey) -> Result, Error> { + async fn get_spent_proof_by_y(&self, y: &PublicKey) -> Result, Self::Err> { Ok(self.spent_proofs.lock().await.get(&y.to_bytes()).cloned()) } - async fn add_pending_proof(&self, proof: Proof) -> Result<(), Error> { + async fn add_pending_proof(&self, proof: Proof) -> Result<(), Self::Err> { self.pending_proofs .lock() .await @@ -172,7 +174,10 @@ impl LocalStore for MemoryLocalStore { Ok(()) } - async fn get_pending_proof_by_secret(&self, secret: &Secret) -> Result, Error> { + async fn get_pending_proof_by_secret( + &self, + secret: &Secret, + ) -> Result, Self::Err> { let secret_point = hash_to_curve(&secret.to_bytes())?; Ok(self .pending_proofs @@ -182,11 +187,11 @@ impl LocalStore for MemoryLocalStore { .cloned()) } - async fn get_pending_proof_by_y(&self, y: &PublicKey) -> Result, Error> { + async fn get_pending_proof_by_y(&self, y: &PublicKey) -> Result, Self::Err> { Ok(self.pending_proofs.lock().await.get(&y.to_bytes()).cloned()) } - async fn remove_pending_proof(&self, secret: &Secret) -> Result<(), Error> { + async fn remove_pending_proof(&self, secret: &Secret) -> Result<(), Self::Err> { let secret_point = hash_to_curve(&secret.to_bytes())?; self.pending_proofs .lock() @@ -199,7 +204,7 @@ impl LocalStore for MemoryLocalStore { &self, blinded_message: PublicKey, blinded_signature: BlindSignature, - ) -> Result<(), Error> { + ) -> Result<(), Self::Err> { self.blinded_signatures .lock() .await @@ -210,7 +215,7 @@ impl LocalStore for MemoryLocalStore { async fn get_blinded_signature( &self, blinded_message: &PublicKey, - ) -> Result, Error> { + ) -> Result, Self::Err> { Ok(self .blinded_signatures .lock() @@ -222,7 +227,7 @@ impl LocalStore for MemoryLocalStore { async fn get_blinded_signatures( &self, blinded_messages: Vec, - ) -> Result>, Error> { + ) -> Result>, Self::Err> { let mut signatures = Vec::with_capacity(blinded_messages.len()); let blinded_signatures = self.blinded_signatures.lock().await; diff --git a/crates/cdk/src/cdk_database/mod.rs b/crates/cdk/src/cdk_database/mod.rs index 2cc90855..8818cae1 100644 --- a/crates/cdk/src/cdk_database/mod.rs +++ b/crates/cdk/src/cdk_database/mod.rs @@ -5,21 +5,28 @@ use std::collections::HashMap; use async_trait::async_trait; use thiserror::Error; -use crate::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs}; +use crate::nuts::{ + BlindSignature, CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, MintKeySet, Proof, Proofs, + PublicKey, +}; +use crate::secret::Secret; use crate::types::{MeltQuote, MintQuote}; use crate::url::UncheckedUrl; +pub mod mint_memory; pub mod wallet_memory; #[derive(Debug, Error)] pub enum Error { #[error(transparent)] Database(Box), + #[error(transparent)] + Cdk(#[from] crate::error::Error), } #[async_trait] pub trait WalletDatabase { - type Err: Into; + type Err: Into + From; async fn add_mint( &self, @@ -71,3 +78,55 @@ pub trait WalletDatabase { async fn increment_keyset_counter(&self, keyset_id: &Id, count: u64) -> Result<(), Self::Err>; async fn get_keyset_counter(&self, keyset_id: &Id) -> Result, Self::Err>; } + +#[async_trait] +pub trait MintDatabase { + type Err: Into; + + async fn set_mint_info(&self, mint_info: &MintInfo) -> Result<(), Self::Err>; + async fn get_mint_info(&self) -> Result; + + async fn add_active_keyset(&self, unit: CurrencyUnit, id: Id) -> Result<(), Self::Err>; + async fn get_active_keyset_id(&self, unit: &CurrencyUnit) -> Result, Self::Err>; + async fn get_active_keysets(&self) -> Result, Self::Err>; + + async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err>; + async fn get_mint_quote(&self, quote_id: &str) -> Result, Self::Err>; + async fn get_mint_quotes(&self) -> Result, Self::Err>; + async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Self::Err>; + + async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), Self::Err>; + async fn get_melt_quote(&self, quote_id: &str) -> Result, Self::Err>; + async fn get_melt_quotes(&self) -> Result, Self::Err>; + async fn remove_melt_quote(&self, quote_id: &str) -> Result<(), Self::Err>; + + async fn add_keyset(&self, keyset: MintKeySet) -> Result<(), Self::Err>; + async fn get_keyset(&self, id: &Id) -> Result, Self::Err>; + async fn get_keysets(&self) -> Result, Self::Err>; + + async fn add_spent_proof(&self, proof: Proof) -> Result<(), Self::Err>; + async fn get_spent_proof_by_secret(&self, secret: &Secret) -> Result, Self::Err>; + async fn get_spent_proof_by_y(&self, y: &PublicKey) -> Result, Self::Err>; + + async fn add_pending_proof(&self, proof: Proof) -> Result<(), Self::Err>; + async fn get_pending_proof_by_secret( + &self, + secret: &Secret, + ) -> Result, Self::Err>; + async fn get_pending_proof_by_y(&self, y: &PublicKey) -> Result, Self::Err>; + async fn remove_pending_proof(&self, secret: &Secret) -> Result<(), Self::Err>; + + async fn add_blinded_signature( + &self, + blinded_message: PublicKey, + blinded_signature: BlindSignature, + ) -> Result<(), Self::Err>; + async fn get_blinded_signature( + &self, + blinded_message: &PublicKey, + ) -> Result, Self::Err>; + async fn get_blinded_signatures( + &self, + blinded_messages: Vec, + ) -> Result>, Self::Err>; +} diff --git a/crates/cdk/src/mint/mod.rs b/crates/cdk/src/mint/mod.rs index e6fd2c49..fa20f455 100644 --- a/crates/cdk/src/mint/mod.rs +++ b/crates/cdk/src/mint/mod.rs @@ -7,11 +7,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use tracing::{debug, error, info}; -pub mod localstore; - -#[cfg(all(not(target_arch = "wasm32"), feature = "redb"))] -pub use self::localstore::RedbLocalStore; -pub use self::localstore::{LocalStore, MemoryLocalStore}; +use crate::cdk_database::{self, MintDatabase}; use crate::dhke::{hash_to_curve, sign_message, verify_message}; use crate::error::ErrorResponse; use crate::nuts::*; @@ -43,8 +39,6 @@ pub enum Error { #[error(transparent)] Cashu(#[from] crate::error::Error), #[error(transparent)] - Localstore(#[from] localstore::Error), - #[error(transparent)] Secret(#[from] crate::secret::Error), #[error(transparent)] NUT00(#[from] crate::nuts::nut00::Error), @@ -52,6 +46,9 @@ pub enum Error { NUT11(#[from] crate::nuts::nut11::Error), #[error(transparent)] Nut12(#[from] crate::nuts::nut12::Error), + /// Database Error + #[error(transparent)] + Database(#[from] crate::cdk_database::Error), #[error("Unknown quote")] UnknownQuote, #[error("Unknown secret kind")] @@ -62,6 +59,12 @@ pub enum Error { BlindedMessageAlreadySigned, } +impl From for cdk_database::Error { + fn from(e: Error) -> Self { + Self::Database(Box::new(e)) + } +} + impl From for ErrorResponse { fn from(err: Error) -> ErrorResponse { ErrorResponse { @@ -83,12 +86,12 @@ pub struct Mint { // pub pubkey: PublicKey mnemonic: Mnemonic, pub fee_reserve: FeeReserve, - pub localstore: Arc, + pub localstore: Arc + Send + Sync>, } impl Mint { pub async fn new( - localstore: Arc, + localstore: Arc + Send + Sync>, mnemonic: Mnemonic, keysets_info: HashSet, min_fee_reserve: Amount,