mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-23 14:06:56 +01:00
refactor(wallet/database): get_proofs returns Vec<ProofInfo> instead of Option<Vec<ProofInfo>>
This commit is contained in:
@@ -29,9 +29,10 @@
|
||||
### Changed
|
||||
- cdk(wallet): `fn send` returns `Token` so the user can use the struct of convert it to a v3 or v4 string ([thesimplekid]).
|
||||
- cdk(wallet): Publicly export `MultiMintWallet` ([thesimplekid]).
|
||||
- cdk(cdk-database): Get `pending` and `spent` `proofs` by `ys` or `secrets` instead of a single proofs ([thesimplekid]).
|
||||
- cdk(cdk-database): Change `add_blind_signature` to `add_blind_signatures` ([thesimplekid]).
|
||||
- cdk(cdk-database): Rename `add_active_keyset` to `set_active_keyset` ([thesimplekid]).
|
||||
- cdk(cdk-database/mint): Get `pending` and `spent` `proofs` by `ys` or `secrets` instead of a single proofs ([thesimplekid]).
|
||||
- cdk(cdk-database/mint): Change `add_blind_signature` to `add_blind_signatures` ([thesimplekid]).
|
||||
- cdk(cdk-database/mint): Rename `add_active_keyset` to `set_active_keyset` ([thesimplekid]).
|
||||
- cdk(cdk-database/wallet): Change `get_proofs` to return `Vec<ProofInfo>` instead of `Option<Vec<ProofInfo>>` ([thesimplekid]).
|
||||
|
||||
### Added
|
||||
- cdk(NUT-11): Add `Copy` on `SigFlag` ([thesimplekid]).
|
||||
|
||||
@@ -231,19 +231,17 @@ impl WalletDatabase for WalletRedbDatabase {
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
|
||||
if let Some(proofs) = proofs {
|
||||
// Proofs with new url
|
||||
let updated_proofs: Vec<ProofInfo> = proofs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|mut p| {
|
||||
p.mint_url = new_mint_url.clone();
|
||||
p
|
||||
})
|
||||
.collect();
|
||||
|
||||
println!("{:?}", updated_proofs);
|
||||
// Proofs with new url
|
||||
let updated_proofs: Vec<ProofInfo> = proofs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|mut p| {
|
||||
p.mint_url = new_mint_url.clone();
|
||||
p
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !updated_proofs.is_empty() {
|
||||
self.add_proofs(updated_proofs).await?;
|
||||
}
|
||||
}
|
||||
@@ -577,7 +575,7 @@ impl WalletDatabase for WalletRedbDatabase {
|
||||
unit: Option<CurrencyUnit>,
|
||||
state: Option<Vec<State>>,
|
||||
spending_conditions: Option<Vec<SpendingConditions>>,
|
||||
) -> Result<Option<Vec<ProofInfo>>, Self::Err> {
|
||||
) -> Result<Vec<ProofInfo>, Self::Err> {
|
||||
let db = self.db.lock().await;
|
||||
let read_txn = db.begin_read().map_err(Error::from)?;
|
||||
|
||||
@@ -606,11 +604,7 @@ impl WalletDatabase for WalletRedbDatabase {
|
||||
})
|
||||
.collect();
|
||||
|
||||
if proofs.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(proofs))
|
||||
Ok(proofs)
|
||||
}
|
||||
|
||||
#[instrument(skip(self, proofs))]
|
||||
|
||||
@@ -211,16 +211,15 @@ impl WalletDatabase for WalletRexieDatabase {
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
|
||||
if let Some(proofs) = proofs {
|
||||
let updated_proofs: Vec<ProofInfo> = proofs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|mut p| {
|
||||
p.mint_url = new_mint_url.clone();
|
||||
p
|
||||
})
|
||||
.collect();
|
||||
let updated_proofs: Vec<ProofInfo> = proofs
|
||||
.into_iter()
|
||||
.map(|mut p| {
|
||||
p.mint_url = new_mint_url.clone();
|
||||
p
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !updated_proofs.is_empty() {
|
||||
self.add_proofs(updated_proofs).await?;
|
||||
}
|
||||
|
||||
@@ -583,7 +582,7 @@ impl WalletDatabase for WalletRexieDatabase {
|
||||
unit: Option<CurrencyUnit>,
|
||||
state: Option<Vec<State>>,
|
||||
spending_conditions: Option<Vec<SpendingConditions>>,
|
||||
) -> Result<Option<Vec<ProofInfo>>, Self::Err> {
|
||||
) -> Result<Vec<ProofInfo>, Self::Err> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
let transaction = rexie
|
||||
@@ -620,11 +619,7 @@ impl WalletDatabase for WalletRexieDatabase {
|
||||
|
||||
transaction.done().await.map_err(Error::from)?;
|
||||
|
||||
if proofs.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(proofs))
|
||||
Ok(proofs)
|
||||
}
|
||||
|
||||
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {
|
||||
|
||||
@@ -507,7 +507,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
unit: Option<CurrencyUnit>,
|
||||
state: Option<Vec<State>>,
|
||||
spending_conditions: Option<Vec<SpendingConditions>>,
|
||||
) -> Result<Option<Vec<ProofInfo>>, Self::Err> {
|
||||
) -> Result<Vec<ProofInfo>, Self::Err> {
|
||||
let recs = sqlx::query(
|
||||
r#"
|
||||
SELECT *
|
||||
@@ -520,13 +520,11 @@ FROM proof;
|
||||
let recs = match recs {
|
||||
Ok(rec) => rec,
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => return Ok(None),
|
||||
sqlx::Error::RowNotFound => return Ok(vec![]),
|
||||
_ => return Err(Error::SQLX(err).into()),
|
||||
},
|
||||
};
|
||||
|
||||
tracing::debug!("{}", recs.len());
|
||||
|
||||
let proofs: Vec<ProofInfo> = recs
|
||||
.iter()
|
||||
.filter_map(|p| match sqlite_row_to_proof_info(p) {
|
||||
@@ -547,11 +545,10 @@ FROM proof;
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
tracing::debug!("{}", proofs.len());
|
||||
|
||||
match proofs.is_empty() {
|
||||
false => Ok(Some(proofs)),
|
||||
true => return Ok(None),
|
||||
false => Ok(proofs),
|
||||
true => return Ok(vec![]),
|
||||
}
|
||||
}
|
||||
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {
|
||||
|
||||
@@ -131,7 +131,7 @@ pub trait WalletDatabase: Debug {
|
||||
unit: Option<CurrencyUnit>,
|
||||
state: Option<Vec<State>>,
|
||||
spending_conditions: Option<Vec<SpendingConditions>>,
|
||||
) -> Result<Option<Vec<ProofInfo>>, Self::Err>;
|
||||
) -> Result<Vec<ProofInfo>, Self::Err>;
|
||||
/// Remove proofs from storage
|
||||
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err>;
|
||||
|
||||
|
||||
@@ -99,9 +99,9 @@ impl WalletDatabase for WalletMemoryDatabase {
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
|
||||
if let Some(proofs) = proofs {
|
||||
// Update proofs
|
||||
{
|
||||
let updated_proofs: Vec<ProofInfo> = proofs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|mut p| {
|
||||
p.mint_url = new_mint_url.clone();
|
||||
@@ -257,7 +257,7 @@ impl WalletDatabase for WalletMemoryDatabase {
|
||||
unit: Option<CurrencyUnit>,
|
||||
state: Option<Vec<State>>,
|
||||
spending_conditions: Option<Vec<SpendingConditions>>,
|
||||
) -> Result<Option<Vec<ProofInfo>>, Error> {
|
||||
) -> Result<Vec<ProofInfo>, Error> {
|
||||
let proofs = self.proofs.read().await;
|
||||
|
||||
let proofs: Vec<ProofInfo> = proofs
|
||||
@@ -272,11 +272,7 @@ impl WalletDatabase for WalletMemoryDatabase {
|
||||
})
|
||||
.collect();
|
||||
|
||||
if proofs.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(proofs))
|
||||
Ok(proofs)
|
||||
}
|
||||
|
||||
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Error> {
|
||||
|
||||
@@ -113,7 +113,7 @@ impl Wallet {
|
||||
/// Total unspent balance of wallet
|
||||
#[instrument(skip(self))]
|
||||
pub async fn total_balance(&self) -> Result<Amount, Error> {
|
||||
if let Some(proofs) = self
|
||||
let proofs = self
|
||||
.localstore
|
||||
.get_proofs(
|
||||
Some(self.mint_url.clone()),
|
||||
@@ -121,22 +121,16 @@ impl Wallet {
|
||||
Some(vec![State::Unspent]),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
let balance = proofs.iter().map(|p| p.proof.amount).sum::<Amount>();
|
||||
.await?;
|
||||
let balance = proofs.iter().map(|p| p.proof.amount).sum::<Amount>();
|
||||
|
||||
return Ok(balance);
|
||||
}
|
||||
|
||||
Ok(Amount::ZERO)
|
||||
Ok(balance)
|
||||
}
|
||||
|
||||
/// Total pending balance
|
||||
#[instrument(skip(self))]
|
||||
pub async fn total_pending_balance(&self) -> Result<HashMap<CurrencyUnit, Amount>, Error> {
|
||||
let mut balances = HashMap::new();
|
||||
|
||||
if let Some(proofs) = self
|
||||
let proofs = self
|
||||
.localstore
|
||||
.get_proofs(
|
||||
Some(self.mint_url.clone()),
|
||||
@@ -144,15 +138,12 @@ impl Wallet {
|
||||
Some(vec![State::Pending]),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
for proof in proofs {
|
||||
balances
|
||||
.entry(proof.unit)
|
||||
.and_modify(|ps| *ps += proof.proof.amount)
|
||||
.or_insert(proof.proof.amount);
|
||||
}
|
||||
}
|
||||
.await?;
|
||||
|
||||
let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
|
||||
*acc.entry(proof.unit).or_insert(Amount::ZERO) += proof.proof.amount;
|
||||
acc
|
||||
});
|
||||
|
||||
Ok(balances)
|
||||
}
|
||||
@@ -160,9 +151,7 @@ impl Wallet {
|
||||
/// Total reserved balance
|
||||
#[instrument(skip(self))]
|
||||
pub async fn total_reserved_balance(&self) -> Result<HashMap<CurrencyUnit, Amount>, Error> {
|
||||
let mut balances = HashMap::new();
|
||||
|
||||
if let Some(proofs) = self
|
||||
let proofs = self
|
||||
.localstore
|
||||
.get_proofs(
|
||||
Some(self.mint_url.clone()),
|
||||
@@ -170,15 +159,12 @@ impl Wallet {
|
||||
Some(vec![State::Reserved]),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
for proof in proofs {
|
||||
balances
|
||||
.entry(proof.unit)
|
||||
.and_modify(|ps| *ps += proof.proof.amount)
|
||||
.or_insert(proof.proof.amount);
|
||||
}
|
||||
}
|
||||
.await?;
|
||||
|
||||
let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
|
||||
*acc.entry(proof.unit).or_insert(Amount::ZERO) += proof.proof.amount;
|
||||
acc
|
||||
});
|
||||
|
||||
Ok(balances)
|
||||
}
|
||||
@@ -208,8 +194,9 @@ impl Wallet {
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
.map(|p| p.into_iter().map(|p| p.proof).collect())
|
||||
.unwrap_or_default())
|
||||
.into_iter()
|
||||
.map(|p| p.proof)
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Get pending [`Proofs`]
|
||||
@@ -224,8 +211,9 @@ impl Wallet {
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
.map(|p| p.into_iter().map(|p| p.proof).collect())
|
||||
.unwrap_or_default())
|
||||
.into_iter()
|
||||
.map(|p| p.proof)
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Get reserved [`Proofs`]
|
||||
@@ -240,8 +228,9 @@ impl Wallet {
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
.map(|p| p.into_iter().map(|p| p.proof).collect())
|
||||
.unwrap_or_default())
|
||||
.into_iter()
|
||||
.map(|p| p.proof)
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Return proofs to unspent allowing them to be selected and spent
|
||||
@@ -405,7 +394,7 @@ impl Wallet {
|
||||
pub async fn check_all_pending_proofs(&self) -> Result<Amount, Error> {
|
||||
let mut balance = Amount::ZERO;
|
||||
|
||||
if let Some(proofs) = self
|
||||
let proofs = self
|
||||
.localstore
|
||||
.get_proofs(
|
||||
Some(self.mint_url.clone()),
|
||||
@@ -413,34 +402,37 @@ impl Wallet {
|
||||
Some(vec![State::Pending, State::Reserved]),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
let states = self
|
||||
.check_proofs_spent(proofs.clone().into_iter().map(|p| p.proof).collect())
|
||||
.await?;
|
||||
.await?;
|
||||
|
||||
// Both `State::Pending` and `State::Unspent` should be included in the pending table.
|
||||
// This is because a proof that has been crated to send will be stored in the pending table
|
||||
// in order to avoid accidentally double spending but to allow it to be explicitly reclaimed
|
||||
let pending_states: HashSet<PublicKey> = states
|
||||
.into_iter()
|
||||
.filter(|s| s.state.ne(&State::Spent))
|
||||
.map(|s| s.y)
|
||||
.collect();
|
||||
|
||||
let (pending_proofs, non_pending_proofs): (Vec<ProofInfo>, Vec<ProofInfo>) = proofs
|
||||
.into_iter()
|
||||
.partition(|p| pending_states.contains(&p.y));
|
||||
|
||||
let amount = pending_proofs.iter().map(|p| p.proof.amount).sum();
|
||||
|
||||
self.localstore
|
||||
.remove_proofs(&non_pending_proofs.into_iter().map(|p| p.proof).collect())
|
||||
.await?;
|
||||
|
||||
balance += amount;
|
||||
if proofs.is_empty() {
|
||||
return Ok(Amount::ZERO);
|
||||
}
|
||||
|
||||
let states = self
|
||||
.check_proofs_spent(proofs.clone().into_iter().map(|p| p.proof).collect())
|
||||
.await?;
|
||||
|
||||
// Both `State::Pending` and `State::Unspent` should be included in the pending table.
|
||||
// This is because a proof that has been crated to send will be stored in the pending table
|
||||
// in order to avoid accidentally double spending but to allow it to be explicitly reclaimed
|
||||
let pending_states: HashSet<PublicKey> = states
|
||||
.into_iter()
|
||||
.filter(|s| s.state.ne(&State::Spent))
|
||||
.map(|s| s.y)
|
||||
.collect();
|
||||
|
||||
let (pending_proofs, non_pending_proofs): (Vec<ProofInfo>, Vec<ProofInfo>) = proofs
|
||||
.into_iter()
|
||||
.partition(|p| pending_states.contains(&p.y));
|
||||
|
||||
let amount = pending_proofs.iter().map(|p| p.proof.amount).sum();
|
||||
|
||||
self.localstore
|
||||
.remove_proofs(&non_pending_proofs.into_iter().map(|p| p.proof).collect())
|
||||
.await?;
|
||||
|
||||
balance += amount;
|
||||
|
||||
Ok(balance)
|
||||
}
|
||||
|
||||
@@ -946,10 +938,20 @@ impl Wallet {
|
||||
Some(vec![State::Unspent]),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
.ok_or(Error::InsufficientFunds)?;
|
||||
.await?;
|
||||
|
||||
let available_proofs = available_proofs.into_iter().map(|p| p.proof).collect();
|
||||
let (available_proofs, proofs_sum) = available_proofs.into_iter().map(|p| p.proof).fold(
|
||||
(Vec::new(), Amount::ZERO),
|
||||
|(mut acc1, mut acc2), p| {
|
||||
acc2 += p.amount;
|
||||
acc1.push(p);
|
||||
(acc1, acc2)
|
||||
},
|
||||
);
|
||||
|
||||
if proofs_sum < amount {
|
||||
return Err(Error::InsufficientFunds);
|
||||
}
|
||||
|
||||
let proofs = self.select_proofs_to_swap(amount, available_proofs).await?;
|
||||
|
||||
@@ -1015,10 +1017,20 @@ impl Wallet {
|
||||
Some(vec![State::Unspent]),
|
||||
conditions.clone().map(|c| vec![c]),
|
||||
)
|
||||
.await?
|
||||
.unwrap_or_default();
|
||||
.await?;
|
||||
|
||||
let available_proofs = available_proofs.into_iter().map(|p| p.proof).collect();
|
||||
let (available_proofs, proofs_sum) = available_proofs.into_iter().map(|p| p.proof).fold(
|
||||
(Vec::new(), Amount::ZERO),
|
||||
|(mut acc1, mut acc2), p| {
|
||||
acc2 += p.amount;
|
||||
acc1.push(p);
|
||||
(acc1, acc2)
|
||||
},
|
||||
);
|
||||
|
||||
if proofs_sum < amount {
|
||||
return Err(Error::InsufficientFunds);
|
||||
}
|
||||
|
||||
let selected = self
|
||||
.select_proofs_to_send(amount, available_proofs, include_fees)
|
||||
|
||||
Reference in New Issue
Block a user