diff --git a/crates/cdk-redb/src/mint/migrations.rs b/crates/cdk-redb/src/mint/migrations.rs index 35671221..e1daad0e 100644 --- a/crates/cdk-redb/src/mint/migrations.rs +++ b/crates/cdk-redb/src/mint/migrations.rs @@ -8,7 +8,7 @@ use cdk::mint_url::MintUrl; use cdk::nuts::{CurrencyUnit, MintQuoteState, Proof, State}; use cdk::Amount; use lightning_invoice::Bolt11Invoice; -use redb::{Database, ReadableTable, TableDefinition}; +use redb::{Database, MultimapTableDefinition, ReadableTable, TableDefinition}; use serde::{Deserialize, Serialize}; use super::{Error, PROOFS_STATE_TABLE, PROOFS_TABLE}; @@ -17,6 +17,8 @@ const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("min const PENDING_PROOFS_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("pending_proofs"); const SPENT_PROOFS_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("spent_proofs"); +const QUOTE_PROOFS_TABLE: MultimapTableDefinition<&str, [u8; 33]> = + MultimapTableDefinition::new("quote_proofs"); pub fn migrate_01_to_02(db: Arc) -> Result { migrate_mint_quotes_01_to_02(db)?; @@ -27,6 +29,11 @@ pub fn migrate_02_to_03(db: Arc) -> Result { migrate_mint_proofs_02_to_03(db)?; Ok(3) } +pub fn migrate_03_to_04(db: Arc) -> Result { + let write_txn = db.begin_write()?; + let _ = write_txn.open_multimap_table(QUOTE_PROOFS_TABLE)?; + Ok(4) +} /// Mint Quote Info #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] diff --git a/crates/cdk-redb/src/mint/mod.rs b/crates/cdk-redb/src/mint/mod.rs index ec7d58e7..49279679 100644 --- a/crates/cdk-redb/src/mint/mod.rs +++ b/crates/cdk-redb/src/mint/mod.rs @@ -16,11 +16,11 @@ use cdk::nuts::{ }; use cdk::{cdk_database, mint}; use migrations::migrate_01_to_02; -use redb::{Database, ReadableTable, TableDefinition}; +use redb::{Database, MultimapTableDefinition, ReadableTable, TableDefinition}; use super::error::Error; use crate::migrations::migrate_00_to_01; -use crate::mint::migrations::migrate_02_to_03; +use crate::mint::migrations::{migrate_02_to_03, migrate_03_to_04}; mod migrations; @@ -34,8 +34,10 @@ const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config") // Key is hex blinded_message B_ value is blinded_signature const BLINDED_SIGNATURES: TableDefinition<[u8; 33], &str> = TableDefinition::new("blinded_signatures"); +const QUOTE_PROOFS_TABLE: MultimapTableDefinition<&str, [u8; 33]> = + MultimapTableDefinition::new("quote_proofs"); -const DATABASE_VERSION: u32 = 3; +const DATABASE_VERSION: u32 = 4; /// Mint Redbdatabase #[derive(Debug, Clone)] @@ -81,6 +83,10 @@ impl MintRedbDatabase { current_file_version = migrate_02_to_03(Arc::clone(&db))?; } + if current_file_version == 3 { + current_file_version = migrate_03_to_04(Arc::clone(&db))?; + } + if current_file_version != DATABASE_VERSION { tracing::warn!( "Database upgrade did not complete at {} current is {}", @@ -125,6 +131,7 @@ impl MintRedbDatabase { let _ = write_txn.open_table(PROOFS_TABLE)?; let _ = write_txn.open_table(PROOFS_STATE_TABLE)?; let _ = write_txn.open_table(BLINDED_SIGNATURES)?; + let _ = write_txn.open_multimap_table(QUOTE_PROOFS_TABLE)?; table.insert("db_version", DATABASE_VERSION.to_string().as_str())?; } @@ -483,21 +490,31 @@ impl MintDatabase for MintRedbDatabase { Ok(()) } - async fn add_proofs(&self, proofs: Proofs) -> Result<(), Self::Err> { + async fn add_proofs(&self, proofs: Proofs, quote_id: Option) -> Result<(), Self::Err> { let write_txn = self.db.begin_write().map_err(Error::from)?; { let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?; + let mut quote_proofs_table = write_txn + .open_multimap_table(QUOTE_PROOFS_TABLE) + .map_err(Error::from)?; for proof in proofs { let y: PublicKey = hash_to_curve(&proof.secret.to_bytes()).map_err(Error::from)?; - if table.get(y.to_bytes()).map_err(Error::from)?.is_none() { + let y = y.to_bytes(); + if table.get(y).map_err(Error::from)?.is_none() { table .insert( - y.to_bytes(), + y, serde_json::to_string(&proof).map_err(Error::from)?.as_str(), ) .map_err(Error::from)?; } + + if let Some(quote_id) = "e_id { + quote_proofs_table + .insert(quote_id.as_str(), y) + .map_err(Error::from)?; + } } } write_txn.commit().map_err(Error::from)?; diff --git a/crates/cdk-sqlite/src/mint/migrations/20240919103407_proofs_quote_id.sql b/crates/cdk-sqlite/src/mint/migrations/20240919103407_proofs_quote_id.sql new file mode 100644 index 00000000..d6c3102c --- /dev/null +++ b/crates/cdk-sqlite/src/mint/migrations/20240919103407_proofs_quote_id.sql @@ -0,0 +1 @@ +ALTER TABLE proof ADD COLUMN quote_id TEXT; diff --git a/crates/cdk-sqlite/src/mint/mod.rs b/crates/cdk-sqlite/src/mint/mod.rs index c3f6591d..f2d62676 100644 --- a/crates/cdk-sqlite/src/mint/mod.rs +++ b/crates/cdk-sqlite/src/mint/mod.rs @@ -746,14 +746,14 @@ FROM keyset; } } - async fn add_proofs(&self, proofs: Proofs) -> Result<(), Self::Err> { + async fn add_proofs(&self, proofs: Proofs, quote_id: Option) -> Result<(), Self::Err> { let mut transaction = self.pool.begin().await.map_err(Error::from)?; for proof in proofs { if let Err(err) = sqlx::query( r#" INSERT INTO proof -(y, amount, keyset_id, secret, c, witness, state) -VALUES (?, ?, ?, ?, ?, ?, ?); +(y, amount, keyset_id, secret, c, witness, state, quote_id) +VALUES (?, ?, ?, ?, ?, ?, ?, ?); "#, ) .bind(proof.y()?.to_bytes().to_vec()) @@ -763,6 +763,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?); .bind(proof.c.to_bytes().to_vec()) .bind(proof.witness.map(|w| serde_json::to_string(&w).unwrap())) .bind("UNSPENT") + .bind(quote_id.clone()) .execute(&mut transaction) .await .map_err(Error::from) @@ -774,6 +775,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?); Ok(()) } + async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result>, Self::Err> { let mut transaction = self.pool.begin().await.map_err(Error::from)?; diff --git a/crates/cdk/src/cdk_database/mint_memory.rs b/crates/cdk/src/cdk_database/mint_memory.rs index 8c3a80c3..b32af4b4 100644 --- a/crates/cdk/src/cdk_database/mint_memory.rs +++ b/crates/cdk/src/cdk_database/mint_memory.rs @@ -24,6 +24,7 @@ pub struct MintMemoryDatabase { melt_quotes: Arc>>, proofs: Arc>>, proof_state: Arc>>, + quote_proofs: Arc>>>, blinded_signatures: Arc>>, } @@ -37,6 +38,7 @@ impl MintMemoryDatabase { melt_quotes: Vec, pending_proofs: Proofs, spent_proofs: Proofs, + quote_proofs: HashMap>, blinded_signatures: HashMap<[u8; 33], BlindSignature>, ) -> Result { let mut proofs = HashMap::new(); @@ -68,6 +70,7 @@ impl MintMemoryDatabase { proofs: Arc::new(RwLock::new(proofs)), proof_state: Arc::new(Mutex::new(proof_states)), blinded_signatures: Arc::new(RwLock::new(blinded_signatures)), + quote_proofs: Arc::new(Mutex::new(quote_proofs)), }) } } @@ -219,13 +222,26 @@ impl MintDatabase for MintMemoryDatabase { Ok(()) } - async fn add_proofs(&self, proofs: Proofs) -> Result<(), Self::Err> { + async fn add_proofs(&self, proofs: Proofs, quote_id: Option) -> Result<(), Self::Err> { let mut db_proofs = self.proofs.write().await; + let mut ys = Vec::with_capacity(proofs.capacity()); + for proof in proofs { - let secret_point = hash_to_curve(&proof.secret.to_bytes())?; - db_proofs.insert(secret_point.to_bytes(), proof); + let y = hash_to_curve(&proof.secret.to_bytes())?; + ys.push(y); + + let y = y.to_bytes(); + + db_proofs.insert(y, proof); } + + if let Some(quote_id) = quote_id { + let mut db_quote_proofs = self.quote_proofs.lock().await; + + db_quote_proofs.insert(quote_id, ys); + } + Ok(()) } diff --git a/crates/cdk/src/cdk_database/mod.rs b/crates/cdk/src/cdk_database/mod.rs index 2a55279c..3dd86dc4 100644 --- a/crates/cdk/src/cdk_database/mod.rs +++ b/crates/cdk/src/cdk_database/mod.rs @@ -228,7 +228,7 @@ pub trait MintDatabase { async fn get_keyset_infos(&self) -> Result, Self::Err>; /// Add spent [`Proofs`] - async fn add_proofs(&self, proof: Proofs) -> Result<(), Self::Err>; + async fn add_proofs(&self, proof: Proofs, quote_id: Option) -> Result<(), Self::Err>; /// Get [`Proofs`] by ys async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result>, Self::Err>; /// Get [`Proofs`] state diff --git a/crates/cdk/src/mint/mod.rs b/crates/cdk/src/mint/mod.rs index beab031d..5ffbf985 100644 --- a/crates/cdk/src/mint/mod.rs +++ b/crates/cdk/src/mint/mod.rs @@ -783,7 +783,7 @@ impl Mint { .collect::, _>>()?; self.localstore - .add_proofs(swap_request.inputs.clone()) + .add_proofs(swap_request.inputs.clone(), None) .await?; self.check_ys_spendable(&input_ys, State::Pending).await?; @@ -1024,7 +1024,10 @@ impl Mint { } self.localstore - .add_proofs(melt_request.inputs.clone()) + .add_proofs( + melt_request.inputs.clone(), + Some(melt_request.quote.clone()), + ) .await?; self.check_ys_spendable(&ys, State::Pending).await?; @@ -1549,6 +1552,7 @@ mod tests { pending_proofs: Proofs, spent_proofs: Proofs, blinded_signatures: HashMap<[u8; 33], BlindSignature>, + quote_proofs: HashMap>, mint_url: &'a str, seed: &'a [u8], mint_info: MintInfo, @@ -1564,6 +1568,7 @@ mod tests { config.melt_quotes, config.pending_proofs, config.spent_proofs, + config.quote_proofs, config.blinded_signatures, ) .unwrap(), diff --git a/flake.nix b/flake.nix index 56e38248..1e69cb1c 100644 --- a/flake.nix +++ b/flake.nix @@ -70,17 +70,18 @@ lnd clightning bitcoind + sqlx-cli ] ++ libsDarwin; # WASM deps - WASMInputs = with pkgs; [ - ]; + # WASMInputs = with pkgs; [ + # ]; - nativeBuildInputs = with pkgs; [ - # Add additional build inputs here - ] ++ lib.optionals isDarwin [ - # Additional darwin specific native inputs can be set here - ]; + # nativeBuildInputs = with pkgs; [ + # Add additional build inputs here + #] ++ lib.optionals isDarwin [ + # Additional darwin specific native inputs can be set here + # ]; in { checks = {