Modify WalletDatabase trait to better support db transactions

This commit is contained in:
David Caseria
2024-08-21 08:12:43 -04:00
committed by thesimplekid
parent 9a009ef125
commit d0d7281c77
6 changed files with 335 additions and 261 deletions

View File

@@ -10,7 +10,7 @@ use async_trait::async_trait;
use cdk::cdk_database::WalletDatabase; use cdk::cdk_database::WalletDatabase;
use cdk::mint_url::MintUrl; use cdk::mint_url::MintUrl;
use cdk::nuts::{ use cdk::nuts::{
CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State, CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, PublicKey, SpendingConditions, State,
}; };
use cdk::types::ProofInfo; use cdk::types::ProofInfo;
use cdk::util::unix_time; use cdk::util::unix_time;
@@ -151,6 +151,47 @@ impl WalletRedbDatabase {
db: Arc::new(Mutex::new(db)), db: Arc::new(Mutex::new(db)),
}) })
} }
async fn update_proof_states(
&self,
ys: Vec<PublicKey>,
state: State,
) -> Result<(), cdk_database::Error> {
let db = self.db.lock().await;
let read_txn = db.begin_read().map_err(Error::from)?;
let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
let write_txn = db.begin_write().map_err(Error::from)?;
for y in ys {
let y_slice = y.to_bytes();
let proof = table
.get(y_slice.as_slice())
.map_err(Error::from)?
.ok_or(Error::UnknownY)?;
let mut proof_info =
serde_json::from_str::<ProofInfo>(proof.value()).map_err(Error::from)?;
proof_info.state = state;
{
let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
table
.insert(
y_slice.as_slice(),
serde_json::to_string(&proof_info)
.map_err(Error::from)?
.as_str(),
)
.map_err(Error::from)?;
}
}
write_txn.commit().map_err(Error::from)?;
Ok(())
}
} }
#[async_trait] #[async_trait]
@@ -260,7 +301,7 @@ impl WalletDatabase for WalletRedbDatabase {
.collect(); .collect();
if !updated_proofs.is_empty() { if !updated_proofs.is_empty() {
self.add_proofs(updated_proofs).await?; self.update_proofs(updated_proofs, vec![]).await?;
} }
} }
@@ -566,8 +607,12 @@ impl WalletDatabase for WalletRedbDatabase {
Ok(()) Ok(())
} }
#[instrument(skip(self, proofs_info))] #[instrument(skip(self, added, deleted_ys))]
async fn add_proofs(&self, proofs_info: Vec<ProofInfo>) -> Result<(), Self::Err> { async fn update_proofs(
&self,
added: Vec<ProofInfo>,
deleted_ys: Vec<PublicKey>,
) -> Result<(), Self::Err> {
let db = self.db.lock().await; let db = self.db.lock().await;
let write_txn = db.begin_write().map_err(Error::from)?; let write_txn = db.begin_write().map_err(Error::from)?;
@@ -575,7 +620,7 @@ impl WalletDatabase for WalletRedbDatabase {
{ {
let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?; let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
for proof_info in proofs_info.iter() { for proof_info in added.iter() {
table table
.insert( .insert(
proof_info.y.to_bytes().as_slice(), proof_info.y.to_bytes().as_slice(),
@@ -585,12 +630,31 @@ impl WalletDatabase for WalletRedbDatabase {
) )
.map_err(Error::from)?; .map_err(Error::from)?;
} }
for y in deleted_ys.iter() {
table.remove(y.to_bytes().as_slice()).map_err(Error::from)?;
}
} }
write_txn.commit().map_err(Error::from)?; write_txn.commit().map_err(Error::from)?;
Ok(()) Ok(())
} }
#[instrument(skip(self, ys))]
async fn set_pending_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
self.update_proof_states(ys, State::Pending).await
}
#[instrument(skip(self, ys))]
async fn reserve_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
self.update_proof_states(ys, State::Reserved).await
}
#[instrument(skip(self, ys))]
async fn set_unspent_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
self.update_proof_states(ys, State::Unspent).await
}
#[instrument(skip_all)] #[instrument(skip_all)]
async fn get_proofs( async fn get_proofs(
&self, &self,
@@ -630,61 +694,6 @@ impl WalletDatabase for WalletRedbDatabase {
Ok(proofs) Ok(proofs)
} }
#[instrument(skip(self, proofs))]
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {
let db = self.db.lock().await;
let write_txn = db.begin_write().map_err(Error::from)?;
{
let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
for proof in proofs {
let y_slice = proof.y().map_err(Error::from)?.to_bytes();
table.remove(y_slice.as_slice()).map_err(Error::from)?;
}
}
write_txn.commit().map_err(Error::from)?;
Ok(())
}
#[instrument(skip(self, y))]
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err> {
let db = self.db.lock().await;
let read_txn = db.begin_read().map_err(Error::from)?;
let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
let y_slice = y.to_bytes();
let proof = table
.get(y_slice.as_slice())
.map_err(Error::from)?
.ok_or(Error::UnknownY)?;
let write_txn = db.begin_write().map_err(Error::from)?;
let mut proof_info =
serde_json::from_str::<ProofInfo>(proof.value()).map_err(Error::from)?;
proof_info.state = state;
{
let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
table
.insert(
y_slice.as_slice(),
serde_json::to_string(&proof_info)
.map_err(Error::from)?
.as_str(),
)
.map_err(Error::from)?;
}
write_txn.commit().map_err(Error::from)?;
Ok(())
}
#[instrument(skip(self), fields(keyset_id = %keyset_id))] #[instrument(skip(self), fields(keyset_id = %keyset_id))]
async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err> { async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err> {
let db = self.db.lock().await; let db = self.db.lock().await;

View File

@@ -5,10 +5,10 @@ use std::rc::Rc;
use std::result::Result; use std::result::Result;
use async_trait::async_trait; use async_trait::async_trait;
use cdk::cdk_database::WalletDatabase; use cdk::cdk_database::{self, WalletDatabase};
use cdk::mint_url::MintUrl; use cdk::mint_url::MintUrl;
use cdk::nuts::{ use cdk::nuts::{
CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State, CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, PublicKey, SpendingConditions, State,
}; };
use cdk::types::ProofInfo; use cdk::types::ProofInfo;
use cdk::util::unix_time; use cdk::util::unix_time;
@@ -108,6 +108,44 @@ impl WalletRexieDatabase {
db: Rc::new(Mutex::new(rexie)), db: Rc::new(Mutex::new(rexie)),
}) })
} }
async fn set_proof_states(
&self,
ys: Vec<PublicKey>,
state: State,
) -> Result<(), cdk_database::Error> {
let rexie = self.db.lock().await;
let transaction = rexie
.transaction(&[PROOFS], TransactionMode::ReadWrite)
.map_err(Error::from)?;
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
for y in ys {
let y = serde_wasm_bindgen::to_value(&y).map_err(Error::from)?;
let mut proof: ProofInfo = proofs_store
.get(y.clone())
.await
.map_err(Error::from)?
.and_then(|p| serde_wasm_bindgen::from_value(p).ok())
.ok_or(Error::NotFound)?;
proof.state = state;
let proof = serde_wasm_bindgen::to_value(&proof).map_err(Error::from)?;
proofs_store
.put(&proof, Some(&y))
.await
.map_err(Error::from)?;
}
transaction.done().await.map_err(Error::from)?;
Ok(())
}
} }
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -224,7 +262,7 @@ impl WalletDatabase for WalletRexieDatabase {
.collect(); .collect();
if !updated_proofs.is_empty() { if !updated_proofs.is_empty() {
self.add_proofs(updated_proofs).await?; self.update_proofs(updated_proofs, vec![]).await?;
} }
// Update mint quotes // Update mint quotes
@@ -567,7 +605,11 @@ impl WalletDatabase for WalletRexieDatabase {
Ok(()) Ok(())
} }
async fn add_proofs(&self, proofs: Vec<ProofInfo>) -> Result<(), Self::Err> { async fn update_proofs(
&self,
added: Vec<ProofInfo>,
removed_ys: Vec<PublicKey>,
) -> Result<(), Self::Err> {
let rexie = self.db.lock().await; let rexie = self.db.lock().await;
let transaction = rexie let transaction = rexie
@@ -576,9 +618,8 @@ impl WalletDatabase for WalletRexieDatabase {
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?; let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
for proof in proofs { for proof in added {
let y = proof.y; let y = serde_wasm_bindgen::to_value(&proof.y).map_err(Error::from)?;
let y = serde_wasm_bindgen::to_value(&y).map_err(Error::from)?;
let proof = serde_wasm_bindgen::to_value(&proof).map_err(Error::from)?; let proof = serde_wasm_bindgen::to_value(&proof).map_err(Error::from)?;
proofs_store proofs_store
@@ -587,11 +628,29 @@ impl WalletDatabase for WalletRexieDatabase {
.map_err(Error::from)?; .map_err(Error::from)?;
} }
for y in removed_ys {
let y = serde_wasm_bindgen::to_value(&y).map_err(Error::from)?;
proofs_store.delete(y).await.map_err(Error::from)?;
}
transaction.done().await.map_err(Error::from)?; transaction.done().await.map_err(Error::from)?;
Ok(()) Ok(())
} }
async fn set_pending_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
self.set_proof_states(ys, State::Pending).await
}
async fn reserve_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
self.set_proof_states(ys, State::Reserved).await
}
async fn set_unspent_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
self.set_proof_states(ys, State::Unspent).await
}
async fn get_proofs( async fn get_proofs(
&self, &self,
mint_url: Option<MintUrl>, mint_url: Option<MintUrl>,
@@ -638,58 +697,6 @@ impl WalletDatabase for WalletRexieDatabase {
Ok(proofs) Ok(proofs)
} }
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {
let rexie = self.db.lock().await;
let transaction = rexie
.transaction(&[PROOFS], TransactionMode::ReadWrite)
.map_err(Error::from)?;
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
for proof in proofs {
let y = serde_wasm_bindgen::to_value(&proof.y()?).map_err(Error::from)?;
proofs_store.delete(y).await.map_err(Error::from)?;
}
transaction.done().await.map_err(Error::from)?;
Ok(())
}
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err> {
let rexie = self.db.lock().await;
let transaction = rexie
.transaction(&[PROOFS], TransactionMode::ReadWrite)
.map_err(Error::from)?;
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
let y = serde_wasm_bindgen::to_value(&y).map_err(Error::from)?;
let mut proof: ProofInfo = proofs_store
.get(y.clone())
.await
.map_err(Error::from)?
.and_then(|p| serde_wasm_bindgen::from_value(p).ok())
.ok_or(Error::NotFound)?;
proof.state = state;
let proof = serde_wasm_bindgen::to_value(&proof).map_err(Error::from)?;
proofs_store
.put(&proof, Some(&y))
.await
.map_err(Error::from)?;
transaction.done().await.map_err(Error::from)?;
Ok(())
}
async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err> { async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err> {
let rexie = self.db.lock().await; let rexie = self.db.lock().await;

View File

@@ -9,8 +9,8 @@ use cdk::amount::Amount;
use cdk::cdk_database::{self, WalletDatabase}; use cdk::cdk_database::{self, WalletDatabase};
use cdk::mint_url::MintUrl; use cdk::mint_url::MintUrl;
use cdk::nuts::{ use cdk::nuts::{
CurrencyUnit, Id, KeySetInfo, Keys, MeltQuoteState, MintInfo, MintQuoteState, Proof, Proofs, CurrencyUnit, Id, KeySetInfo, Keys, MeltQuoteState, MintInfo, MintQuoteState, Proof, PublicKey,
PublicKey, SpendingConditions, State, SpendingConditions, State,
}; };
use cdk::secret::Secret; use cdk::secret::Secret;
use cdk::types::ProofInfo; use cdk::types::ProofInfo;
@@ -53,6 +53,23 @@ impl WalletSqliteDatabase {
.await .await
.expect("Could not run migrations"); .expect("Could not run migrations");
} }
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), cdk_database::Error> {
sqlx::query(
r#"
UPDATE proof
SET state=?
WHERE y IS ?;
"#,
)
.bind(state.to_string())
.bind(y.to_bytes().to_vec())
.execute(&self.pool)
.await
.map_err(Error::from)?;
Ok(())
}
} }
#[async_trait] #[async_trait]
@@ -513,9 +530,12 @@ WHERE id=?
Ok(()) Ok(())
} }
#[instrument(skip_all)] async fn update_proofs(
async fn add_proofs(&self, proof_info: Vec<ProofInfo>) -> Result<(), Self::Err> { &self,
for proof in proof_info { added: Vec<ProofInfo>,
removed_ys: Vec<PublicKey>,
) -> Result<(), Self::Err> {
for proof in added {
sqlx::query( sqlx::query(
r#" r#"
INSERT OR REPLACE INTO proof INSERT OR REPLACE INTO proof
@@ -547,6 +567,44 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
.map_err(Error::from)?; .map_err(Error::from)?;
} }
// TODO: Generate a IN clause
for y in removed_ys {
sqlx::query(
r#"
DELETE FROM proof
WHERE y = ?
"#,
)
.bind(y.to_bytes().to_vec())
.execute(&self.pool)
.await
.map_err(Error::from)?;
}
Ok(())
}
async fn set_pending_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
for y in ys {
self.set_proof_state(y, State::Pending).await?;
}
Ok(())
}
async fn reserve_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
for y in ys {
self.set_proof_state(y, State::Reserved).await?;
}
Ok(())
}
async fn set_unspent_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err> {
for y in ys {
self.set_proof_state(y, State::Unspent).await?;
}
Ok(()) Ok(())
} }
@@ -602,43 +660,6 @@ FROM proof;
} }
} }
#[instrument(skip_all)]
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {
// TODO: Generate a IN clause
for proof in proofs {
sqlx::query(
r#"
DELETE FROM proof
WHERE y = ?
"#,
)
.bind(proof.y()?.to_bytes().to_vec())
.execute(&self.pool)
.await
.map_err(Error::from)?;
}
Ok(())
}
#[instrument(skip(self, y))]
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err> {
sqlx::query(
r#"
UPDATE proof
SET state=?
WHERE y IS ?;
"#,
)
.bind(state.to_string())
.bind(y.to_bytes().to_vec())
.execute(&self.pool)
.await
.map_err(Error::from)?;
Ok(())
}
#[instrument(skip(self), fields(keyset_id = %keyset_id))] #[instrument(skip(self), fields(keyset_id = %keyset_id))]
async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err> { async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err> {
sqlx::query( sqlx::query(

View File

@@ -17,9 +17,9 @@ use crate::mint::MintQuote as MintMintQuote;
#[cfg(feature = "wallet")] #[cfg(feature = "wallet")]
use crate::mint_url::MintUrl; use crate::mint_url::MintUrl;
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
use crate::nuts::{BlindSignature, MeltQuoteState, MintQuoteState, Proof}; use crate::nuts::{BlindSignature, MeltQuoteState, MintQuoteState, Proof, Proofs};
#[cfg(any(feature = "wallet", feature = "mint"))] #[cfg(any(feature = "wallet", feature = "mint"))]
use crate::nuts::{CurrencyUnit, Id, Proofs, PublicKey, State}; use crate::nuts::{CurrencyUnit, Id, PublicKey, State};
#[cfg(feature = "wallet")] #[cfg(feature = "wallet")]
use crate::nuts::{KeySetInfo, Keys, MintInfo, SpendingConditions}; use crate::nuts::{KeySetInfo, Keys, MintInfo, SpendingConditions};
#[cfg(feature = "wallet")] #[cfg(feature = "wallet")]
@@ -124,8 +124,18 @@ pub trait WalletDatabase: Debug {
/// Remove [`Keys`] from storage /// Remove [`Keys`] from storage
async fn remove_keys(&self, id: &Id) -> Result<(), Self::Err>; async fn remove_keys(&self, id: &Id) -> Result<(), Self::Err>;
/// Add [`Proofs`] to storage /// Update the proofs in storage by adding new proofs or removing proofs by their Y value.
async fn add_proofs(&self, proof_info: Vec<ProofInfo>) -> Result<(), Self::Err>; async fn update_proofs(
&self,
added: Vec<ProofInfo>,
removed_ys: Vec<PublicKey>,
) -> Result<(), Self::Err>;
/// Set proofs as pending in storage. Proofs are identified by their Y value.
async fn set_pending_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err>;
/// Reserve proofs in storage. Proofs are identified by their Y value.
async fn reserve_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err>;
/// Set proofs as unspent in storage. Proofs are identified by their Y value.
async fn set_unspent_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Self::Err>;
/// Get proofs from storage /// Get proofs from storage
async fn get_proofs( async fn get_proofs(
&self, &self,
@@ -134,11 +144,6 @@ pub trait WalletDatabase: Debug {
state: Option<Vec<State>>, state: Option<Vec<State>>,
spending_conditions: Option<Vec<SpendingConditions>>, spending_conditions: Option<Vec<SpendingConditions>>,
) -> Result<Vec<ProofInfo>, Self::Err>; ) -> Result<Vec<ProofInfo>, Self::Err>;
/// Remove proofs from storage
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err>;
/// Set Proof state
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err>;
/// Increment Keyset counter /// Increment Keyset counter
async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err>; async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err>;

View File

@@ -10,7 +10,7 @@ use super::WalletDatabase;
use crate::cdk_database::Error; use crate::cdk_database::Error;
use crate::mint_url::MintUrl; use crate::mint_url::MintUrl;
use crate::nuts::{ use crate::nuts::{
CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State, CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, PublicKey, SpendingConditions, State,
}; };
use crate::types::ProofInfo; use crate::types::ProofInfo;
use crate::util::unix_time; use crate::util::unix_time;
@@ -109,7 +109,7 @@ impl WalletDatabase for WalletMemoryDatabase {
}) })
.collect(); .collect();
self.add_proofs(updated_proofs).await?; self.update_proofs(updated_proofs, vec![]).await?;
} }
// Update mint quotes // Update mint quotes
@@ -238,13 +238,57 @@ impl WalletDatabase for WalletMemoryDatabase {
Ok(()) Ok(())
} }
async fn add_proofs(&self, proofs_info: Vec<ProofInfo>) -> Result<(), Error> { async fn update_proofs(
&self,
added: Vec<ProofInfo>,
removed_ys: Vec<PublicKey>,
) -> Result<(), Error> {
let mut all_proofs = self.proofs.write().await; let mut all_proofs = self.proofs.write().await;
for proof_info in proofs_info.into_iter() { for proof_info in added.into_iter() {
all_proofs.insert(proof_info.y, proof_info); all_proofs.insert(proof_info.y, proof_info);
} }
for y in removed_ys.into_iter() {
all_proofs.remove(&y);
}
Ok(())
}
async fn set_pending_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Error> {
let mut all_proofs = self.proofs.write().await;
for y in ys.into_iter() {
if let Some(proof_info) = all_proofs.get_mut(&y) {
proof_info.state = State::Pending;
}
}
Ok(())
}
async fn reserve_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Error> {
let mut all_proofs = self.proofs.write().await;
for y in ys.into_iter() {
if let Some(proof_info) = all_proofs.get_mut(&y) {
proof_info.state = State::Reserved;
}
}
Ok(())
}
async fn set_unspent_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Error> {
let mut all_proofs = self.proofs.write().await;
for y in ys.into_iter() {
if let Some(proof_info) = all_proofs.get_mut(&y) {
proof_info.state = State::Unspent;
}
}
Ok(()) Ok(())
} }
@@ -272,34 +316,6 @@ impl WalletDatabase for WalletMemoryDatabase {
Ok(proofs) Ok(proofs)
} }
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Error> {
let mut mint_proofs = self.proofs.write().await;
for proof in proofs {
mint_proofs.remove(&proof.y().map_err(Error::from)?);
}
Ok(())
}
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err> {
let mint_proofs = self.proofs.read().await;
let mint_proof = mint_proofs.get(&y).cloned();
drop(mint_proofs);
let mut mint_proofs = self.proofs.write().await;
if let Some(proof_info) = mint_proof {
let mut proof_info = proof_info.clone();
proof_info.state = state;
mint_proofs.insert(y, proof_info);
}
Ok(())
}
async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Error> { async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Error> {
let keyset_counter = self.keyset_counter.read().await; let keyset_counter = self.keyset_counter.read().await;
let current_counter = keyset_counter.get(keyset_id).cloned().unwrap_or(0); let current_counter = keyset_counter.get(keyset_id).cloned().unwrap_or(0);

View File

@@ -259,11 +259,7 @@ impl Wallet {
/// Return proofs to unspent allowing them to be selected and spent /// Return proofs to unspent allowing them to be selected and spent
#[instrument(skip(self))] #[instrument(skip(self))]
pub async fn unreserve_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Error> { pub async fn unreserve_proofs(&self, ys: Vec<PublicKey>) -> Result<(), Error> {
for y in ys { Ok(self.localstore.set_unspent_proofs(ys).await?)
self.localstore.set_proof_state(y, State::Unspent).await?;
}
Ok(())
} }
/// Qeury mint for current mint information /// Qeury mint for current mint information
@@ -461,7 +457,10 @@ impl Wallet {
let amount = pending_proofs.iter().map(|p| p.proof.amount).sum(); let amount = pending_proofs.iter().map(|p| p.proof.amount).sum();
self.localstore self.localstore
.remove_proofs(&non_pending_proofs.into_iter().map(|p| p.proof).collect()) .update_proofs(
vec![],
non_pending_proofs.into_iter().map(|p| p.y).collect(),
)
.await?; .await?;
balance += amount; balance += amount;
@@ -701,7 +700,7 @@ impl Wallet {
.collect::<Result<Vec<ProofInfo>, _>>()?; .collect::<Result<Vec<ProofInfo>, _>>()?;
// Add new proofs to store // Add new proofs to store
self.localstore.add_proofs(proofs).await?; self.localstore.update_proofs(proofs, vec![]).await?;
Ok(minted_amount) Ok(minted_amount)
} }
@@ -776,12 +775,8 @@ impl Wallet {
// Desired amount is either amount passed or value of all proof // Desired amount is either amount passed or value of all proof
let proofs_total: Amount = proofs.iter().map(|p| p.amount).sum(); let proofs_total: Amount = proofs.iter().map(|p| p.amount).sum();
for proof in proofs.iter() { let ys: Vec<PublicKey> = proofs.iter().map(|p| p.y()).collect::<Result<_, _>>()?;
self.localstore self.localstore.set_pending_proofs(ys).await?;
.set_proof_state(proof.y()?, State::Pending)
.await
.ok();
}
let fee = self.get_proofs_fee(&proofs).await?; let fee = self.get_proofs_fee(&proofs).await?;
@@ -932,9 +927,9 @@ impl Wallet {
.increment_keyset_counter(&active_keyset_id, pre_swap.derived_secret_count) .increment_keyset_counter(&active_keyset_id, pre_swap.derived_secret_count)
.await?; .await?;
let mut added_proofs = Vec::new();
let change_proofs; let change_proofs;
let send_proofs; let send_proofs;
match amount { match amount {
Some(amount) => { Some(amount) => {
let (proofs_with_condition, proofs_without_condition): (Proofs, Proofs) = let (proofs_with_condition, proofs_without_condition): (Proofs, Proofs) =
@@ -982,8 +977,7 @@ impl Wallet {
.into_iter() .into_iter()
.map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Reserved, *unit)) .map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Reserved, *unit))
.collect::<Result<Vec<ProofInfo>, _>>()?; .collect::<Result<Vec<ProofInfo>, _>>()?;
added_proofs = send_proofs_info;
self.localstore.add_proofs(send_proofs_info).await?;
change_proofs = proofs_to_keep; change_proofs = proofs_to_keep;
send_proofs = Some(proofs_to_send); send_proofs = Some(proofs_to_send);
@@ -998,12 +992,17 @@ impl Wallet {
.into_iter() .into_iter()
.map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent, *unit)) .map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent, *unit))
.collect::<Result<Vec<ProofInfo>, _>>()?; .collect::<Result<Vec<ProofInfo>, _>>()?;
added_proofs.extend(keep_proofs);
self.localstore.add_proofs(keep_proofs).await?;
// Remove spent proofs used as inputs // Remove spent proofs used as inputs
self.localstore.remove_proofs(&input_proofs).await?; let deleted_ys = input_proofs
.into_iter()
.map(|proof| proof.y())
.collect::<Result<Vec<PublicKey>, _>>()?;
self.localstore
.update_proofs(added_proofs, deleted_ys)
.await?;
Ok(send_proofs) Ok(send_proofs)
} }
@@ -1053,11 +1052,11 @@ impl Wallet {
/// Send specific proofs /// Send specific proofs
#[instrument(skip(self))] #[instrument(skip(self))]
pub async fn send_proofs(&self, memo: Option<String>, proofs: Proofs) -> Result<Token, Error> { pub async fn send_proofs(&self, memo: Option<String>, proofs: Proofs) -> Result<Token, Error> {
for proof in proofs.iter() { let ys = proofs
self.localstore .iter()
.set_proof_state(proof.y()?, State::Reserved) .map(|p| p.y())
.await?; .collect::<Result<Vec<PublicKey>, _>>()?;
} self.localstore.reserve_proofs(ys).await?;
Ok(Token::new( Ok(Token::new(
self.mint_url.clone(), self.mint_url.clone(),
@@ -1358,11 +1357,11 @@ impl Wallet {
return Err(Error::QuoteUnknown); return Err(Error::QuoteUnknown);
}; };
for proof in proofs.iter() { let ys = proofs
self.localstore .iter()
.set_proof_state(proof.y()?, State::Pending) .map(|p| p.y())
.await?; .collect::<Result<Vec<PublicKey>, _>>()?;
} self.localstore.set_pending_proofs(ys).await?;
let active_keyset_id = self.get_active_mint_keyset().await?.id; let active_keyset_id = self.get_active_mint_keyset().await?.id;
@@ -1429,7 +1428,8 @@ impl Wallet {
change: change_proofs.clone(), change: change_proofs.clone(),
}; };
if let Some(change_proofs) = change_proofs { let change_proof_infos = match change_proofs {
Some(change_proofs) => {
tracing::debug!( tracing::debug!(
"Change amount returned from melt: {}", "Change amount returned from melt: {}",
change_proofs.iter().map(|p| p.amount).sum::<Amount>() change_proofs.iter().map(|p| p.amount).sum::<Amount>()
@@ -1440,7 +1440,7 @@ impl Wallet {
.increment_keyset_counter(&active_keyset_id, change_proofs.len() as u32) .increment_keyset_counter(&active_keyset_id, change_proofs.len() as u32)
.await?; .await?;
let change_proofs_info = change_proofs change_proofs
.into_iter() .into_iter()
.map(|proof| { .map(|proof| {
ProofInfo::new( ProofInfo::new(
@@ -1450,14 +1450,20 @@ impl Wallet {
quote_info.unit, quote_info.unit,
) )
}) })
.collect::<Result<Vec<ProofInfo>, _>>()?; .collect::<Result<Vec<ProofInfo>, _>>()?
self.localstore.add_proofs(change_proofs_info).await?;
} }
None => Vec::new(),
};
self.localstore.remove_melt_quote(&quote_info.id).await?; self.localstore.remove_melt_quote(&quote_info.id).await?;
self.localstore.remove_proofs(&proofs).await?; let deleted_ys = proofs
.iter()
.map(|p| p.y())
.collect::<Result<Vec<PublicKey>, _>>()?;
self.localstore
.update_proofs(change_proof_infos, deleted_ys)
.await?;
Ok(melted) Ok(melted)
} }
@@ -1716,6 +1722,14 @@ impl Wallet {
} }
} }
// Since the proofs are unknown they need to be added to the database
let proofs_info = proofs
.clone()
.into_iter()
.map(|p| ProofInfo::new(p, self.mint_url.clone(), State::Pending, self.unit))
.collect::<Result<Vec<ProofInfo>, _>>()?;
self.localstore.update_proofs(proofs_info, vec![]).await?;
let mut pre_swap = self let mut pre_swap = self
.create_swap(None, amount_split_target, proofs, None, false) .create_swap(None, amount_split_target, proofs, None, false)
.await?; .await?;
@@ -1755,7 +1769,7 @@ impl Wallet {
.into_iter() .into_iter()
.map(|proof| ProofInfo::new(proof, mint.clone(), State::Unspent, self.unit)) .map(|proof| ProofInfo::new(proof, mint.clone(), State::Unspent, self.unit))
.collect::<Result<Vec<ProofInfo>, _>>()?; .collect::<Result<Vec<ProofInfo>, _>>()?;
self.localstore.add_proofs(proofs).await?; self.localstore.update_proofs(proofs, vec![]).await?;
} }
Ok(total_amount) Ok(total_amount)
@@ -1919,7 +1933,9 @@ impl Wallet {
}) })
.collect::<Result<Vec<ProofInfo>, _>>()?; .collect::<Result<Vec<ProofInfo>, _>>()?;
self.localstore.add_proofs(unspent_proofs).await?; self.localstore
.update_proofs(unspent_proofs, vec![])
.await?;
empty_batch = 0; empty_batch = 0;
start_counter += 100; start_counter += 100;