mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-07 14:15:56 +01:00
refactor: database use one proofs table
This commit is contained in:
@@ -8,6 +8,7 @@ pub enum JsState {
|
||||
Spent,
|
||||
Unspent,
|
||||
Pending,
|
||||
Reserved,
|
||||
}
|
||||
|
||||
impl From<State> for JsState {
|
||||
@@ -16,6 +17,7 @@ impl From<State> for JsState {
|
||||
State::Spent => JsState::Spent,
|
||||
State::Unspent => JsState::Unspent,
|
||||
State::Pending => JsState::Pending,
|
||||
State::Reserved => JsState::Reserved,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +28,7 @@ impl From<JsState> for State {
|
||||
JsState::Spent => State::Spent,
|
||||
JsState::Unspent => State::Unspent,
|
||||
JsState::Pending => State::Pending,
|
||||
JsState::Reserved => State::Reserved,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ nostr = ["cdk/nostr"]
|
||||
[dependencies]
|
||||
async-trait.workspace = true
|
||||
cdk = { workspace = true, default-features = false }
|
||||
redb = "2.0.0"
|
||||
redb = "2.1.0"
|
||||
tokio.workspace = true
|
||||
thiserror.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
@@ -43,6 +43,9 @@ pub enum Error {
|
||||
/// Unknown Mint Info
|
||||
#[error("Unknown Mint Info")]
|
||||
UnknownMintInfo,
|
||||
/// Unknown Proof Y
|
||||
#[error("Unknown Proof Y")]
|
||||
UnknownY,
|
||||
}
|
||||
|
||||
impl From<Error> for cdk::cdk_database::Error {
|
||||
|
||||
@@ -5,10 +5,8 @@ use std::sync::Arc;
|
||||
use async_trait::async_trait;
|
||||
use cdk::cdk_database;
|
||||
use cdk::cdk_database::WalletDatabase;
|
||||
#[cfg(feature = "nostr")]
|
||||
use cdk::nuts::PublicKey;
|
||||
use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs};
|
||||
use cdk::types::{MeltQuote, MintQuote};
|
||||
use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, State};
|
||||
use cdk::types::{MeltQuote, MintQuote, ProofInfo};
|
||||
use cdk::url::UncheckedUrl;
|
||||
use redb::{Database, MultimapTableDefinition, ReadableTable, TableDefinition};
|
||||
use tokio::sync::Mutex;
|
||||
@@ -22,9 +20,8 @@ const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &str> =
|
||||
const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
|
||||
const MELT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("melt_quotes");
|
||||
const MINT_KEYS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_keys");
|
||||
const PROOFS_TABLE: MultimapTableDefinition<&str, &str> = MultimapTableDefinition::new("proofs");
|
||||
const PENDING_PROOFS_TABLE: MultimapTableDefinition<&str, &str> =
|
||||
MultimapTableDefinition::new("pending_proofs");
|
||||
// <Y, (Proof, Status, Mint url)>
|
||||
const PROOFS_TABLE: TableDefinition<&[u8], &str> = TableDefinition::new("proofs");
|
||||
const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config");
|
||||
const KEYSET_COUNTER: TableDefinition<&str, u32> = TableDefinition::new("keyset_counter");
|
||||
#[cfg(feature = "nostr")]
|
||||
@@ -66,7 +63,7 @@ impl RedbWalletDatabase {
|
||||
let _ = write_txn.open_table(MINT_QUOTES_TABLE)?;
|
||||
let _ = write_txn.open_table(MELT_QUOTES_TABLE)?;
|
||||
let _ = write_txn.open_table(MINT_KEYS_TABLE)?;
|
||||
let _ = write_txn.open_multimap_table(PROOFS_TABLE)?;
|
||||
let _ = write_txn.open_table(PROOFS_TABLE)?;
|
||||
let _ = write_txn.open_table(KEYSET_COUNTER)?;
|
||||
#[cfg(feature = "nostr")]
|
||||
let _ = write_txn.open_table(NOSTR_LAST_CHECKED)?;
|
||||
@@ -373,22 +370,22 @@ impl WalletDatabase for RedbWalletDatabase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self, proofs))]
|
||||
async fn add_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Self::Err> {
|
||||
#[instrument(skip(self, proofs_info))]
|
||||
async fn add_proofs(&self, proofs_info: Vec<ProofInfo>) -> 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_multimap_table(PROOFS_TABLE)
|
||||
.map_err(Error::from)?;
|
||||
let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
|
||||
|
||||
for proof in proofs {
|
||||
for proof_info in proofs_info.iter() {
|
||||
table
|
||||
.insert(
|
||||
mint_url.to_string().as_str(),
|
||||
serde_json::to_string(&proof).map_err(Error::from)?.as_str(),
|
||||
proof_info.y.to_bytes().as_slice(),
|
||||
serde_json::to_string(&proof_info)
|
||||
.map_err(Error::from)?
|
||||
.as_str(),
|
||||
)
|
||||
.map_err(Error::from)?;
|
||||
}
|
||||
@@ -399,124 +396,69 @@ impl WalletDatabase for RedbWalletDatabase {
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Self::Err> {
|
||||
let db = self.db.lock().await;
|
||||
let read_txn = db.begin_read().map_err(Error::from)?;
|
||||
let table = read_txn
|
||||
.open_multimap_table(PROOFS_TABLE)
|
||||
.map_err(Error::from)?;
|
||||
|
||||
let proofs = table
|
||||
.get(mint_url.to_string().as_str())
|
||||
.map_err(Error::from)?
|
||||
.flatten()
|
||||
.flat_map(|k| serde_json::from_str(k.value()))
|
||||
.collect();
|
||||
|
||||
Ok(proofs)
|
||||
}
|
||||
|
||||
#[instrument(skip(self, proofs))]
|
||||
async fn remove_proofs(
|
||||
async fn get_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
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_multimap_table(PROOFS_TABLE)
|
||||
.map_err(Error::from)?;
|
||||
|
||||
for proof in proofs {
|
||||
table
|
||||
.remove(
|
||||
mint_url.to_string().as_str(),
|
||||
serde_json::to_string(&proof).map_err(Error::from)?.as_str(),
|
||||
)
|
||||
.map_err(Error::from)?;
|
||||
}
|
||||
}
|
||||
write_txn.commit().map_err(Error::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self, proofs))]
|
||||
async fn add_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
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_multimap_table(PENDING_PROOFS_TABLE)
|
||||
.map_err(Error::from)?;
|
||||
|
||||
for proof in proofs {
|
||||
table
|
||||
.insert(
|
||||
mint_url.to_string().as_str(),
|
||||
serde_json::to_string(&proof).map_err(Error::from)?.as_str(),
|
||||
)
|
||||
.map_err(Error::from)?;
|
||||
}
|
||||
}
|
||||
write_txn.commit().map_err(Error::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn get_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
mint_url: Option<UncheckedUrl>,
|
||||
state: Option<Vec<State>>,
|
||||
) -> Result<Option<Proofs>, Self::Err> {
|
||||
let db = self.db.lock().await;
|
||||
let read_txn = db.begin_read().map_err(Error::from)?;
|
||||
let table = read_txn
|
||||
.open_multimap_table(PENDING_PROOFS_TABLE)
|
||||
.map_err(Error::from)?;
|
||||
|
||||
let proofs = table
|
||||
.get(mint_url.to_string().as_str())
|
||||
let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
|
||||
|
||||
let proofs: Proofs = table
|
||||
.iter()
|
||||
.map_err(Error::from)?
|
||||
.flatten()
|
||||
.flat_map(|k| serde_json::from_str(k.value()))
|
||||
.filter_map(|(_k, v)| {
|
||||
let mut proof = None;
|
||||
|
||||
if let Ok(proof_info) = serde_json::from_str::<ProofInfo>(v.value()) {
|
||||
match (&mint_url, &state) {
|
||||
(Some(mint_url), Some(state)) => {
|
||||
if state.contains(&proof_info.state)
|
||||
&& mint_url.eq(&proof_info.mint_url)
|
||||
{
|
||||
proof = Some(proof_info.proof);
|
||||
}
|
||||
}
|
||||
(Some(mint_url), None) => {
|
||||
if mint_url.eq(&proof_info.mint_url) {
|
||||
proof = Some(proof_info.proof);
|
||||
}
|
||||
}
|
||||
(None, Some(state)) => {
|
||||
if state.contains(&proof_info.state) {
|
||||
proof = Some(proof_info.proof);
|
||||
}
|
||||
}
|
||||
(None, None) => proof = Some(proof_info.proof),
|
||||
}
|
||||
}
|
||||
|
||||
proof
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(proofs)
|
||||
if proofs.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(proofs))
|
||||
}
|
||||
|
||||
#[instrument(skip(self, proofs))]
|
||||
async fn remove_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: &Proofs,
|
||||
) -> Result<(), Self::Err> {
|
||||
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_multimap_table(PENDING_PROOFS_TABLE)
|
||||
.map_err(Error::from)?;
|
||||
let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
|
||||
|
||||
for proof in proofs {
|
||||
table
|
||||
.remove(
|
||||
mint_url.to_string().as_str(),
|
||||
serde_json::to_string(&proof).map_err(Error::from)?.as_str(),
|
||||
)
|
||||
.map_err(Error::from)?;
|
||||
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)?;
|
||||
@@ -524,6 +466,41 @@ impl WalletDatabase for RedbWalletDatabase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
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)?;
|
||||
|
||||
let write_txn = db.begin_write().map_err(Error::from)?;
|
||||
|
||||
if let Some(proof) = proof {
|
||||
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)?;
|
||||
|
||||
Err(Error::UnknownY.into())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err> {
|
||||
let db = self.db.lock().await;
|
||||
|
||||
@@ -4,8 +4,8 @@ use std::result::Result;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cdk::cdk_database::WalletDatabase;
|
||||
use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs};
|
||||
use cdk::types::{MeltQuote, MintQuote};
|
||||
use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, State};
|
||||
use cdk::types::{MeltQuote, MintQuote, ProofInfo};
|
||||
use cdk::url::UncheckedUrl;
|
||||
use rexie::*;
|
||||
use thiserror::Error;
|
||||
@@ -18,7 +18,6 @@ const MINT_KEYS: &str = "mint_keys";
|
||||
const MINT_QUOTES: &str = "mint_quotes";
|
||||
const MELT_QUOTES: &str = "melt_quotes";
|
||||
const PROOFS: &str = "proofs";
|
||||
const PENDING_PROOFS: &str = "pending_proofs";
|
||||
const CONFIG: &str = "config";
|
||||
const KEYSET_COUNTER: &str = "keyset_counter";
|
||||
|
||||
@@ -35,6 +34,8 @@ pub enum Error {
|
||||
/// Serde Wasm Error
|
||||
#[error(transparent)]
|
||||
SerdeBindgen(#[from] serde_wasm_bindgen::Error),
|
||||
#[error(transparent)]
|
||||
NUT00(cdk::nuts::nut00::Error),
|
||||
}
|
||||
impl From<Error> for cdk::cdk_database::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
@@ -87,10 +88,6 @@ impl RexieWalletDatabase {
|
||||
ObjectStore::new(MELT_QUOTES)
|
||||
.add_index(Index::new("keyset_id", "keyset_id").unique(true)),
|
||||
)
|
||||
.add_object_store(
|
||||
ObjectStore::new(PENDING_PROOFS)
|
||||
.add_index(Index::new("keyset_id", "keyset_id").unique(true)),
|
||||
)
|
||||
.add_object_store(
|
||||
ObjectStore::new(CONFIG)
|
||||
.add_index(Index::new("keyset_id", "keyset_id").unique(true)),
|
||||
@@ -423,7 +420,7 @@ impl WalletDatabase for RexieWalletDatabase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Self::Err> {
|
||||
async fn add_proofs(&self, proofs: Vec<ProofInfo>) -> Result<(), Self::Err> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
let transaction = rexie
|
||||
@@ -432,33 +429,27 @@ impl WalletDatabase for RexieWalletDatabase {
|
||||
|
||||
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
|
||||
|
||||
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
|
||||
for proof in proofs {
|
||||
let y = proof.y;
|
||||
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 current_proofs = proofs_store.get(&mint_url).await.map_err(Error::from)?;
|
||||
|
||||
let current_proofs: Proofs =
|
||||
serde_wasm_bindgen::from_value(current_proofs).unwrap_or_default();
|
||||
|
||||
let all_proofs: Proofs = current_proofs
|
||||
.into_iter()
|
||||
.chain(proofs.into_iter())
|
||||
.collect();
|
||||
|
||||
let all_proofs = serde_wasm_bindgen::to_value(&all_proofs).map_err(Error::from)?;
|
||||
|
||||
web_sys::console::log_1(&all_proofs);
|
||||
|
||||
proofs_store
|
||||
.put(&all_proofs, Some(&mint_url))
|
||||
.await
|
||||
.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 get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Self::Err> {
|
||||
async fn get_proofs(
|
||||
&self,
|
||||
mint_url: Option<UncheckedUrl>,
|
||||
state: Option<Vec<State>>,
|
||||
) -> Result<Option<Proofs>, Self::Err> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
let transaction = rexie
|
||||
@@ -467,21 +458,53 @@ impl WalletDatabase for RexieWalletDatabase {
|
||||
|
||||
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
|
||||
|
||||
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
|
||||
let proofs = proofs_store.get(&mint_url).await.map_err(Error::from)?;
|
||||
let proofs = proofs_store
|
||||
.get_all(None, None, None, None)
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
|
||||
let proofs: Proofs = proofs
|
||||
.into_iter()
|
||||
.filter_map(|(_k, v)| {
|
||||
let mut proof = None;
|
||||
|
||||
if let Ok(proof_info) = serde_wasm_bindgen::from_value::<ProofInfo>(v) {
|
||||
match (&mint_url, &state) {
|
||||
(Some(mint_url), Some(state)) => {
|
||||
if state.contains(&proof_info.state)
|
||||
&& mint_url.eq(&proof_info.mint_url)
|
||||
{
|
||||
proof = Some(proof_info.proof);
|
||||
}
|
||||
}
|
||||
(Some(mint_url), None) => {
|
||||
if mint_url.eq(&proof_info.mint_url) {
|
||||
proof = Some(proof_info.proof);
|
||||
}
|
||||
}
|
||||
(None, Some(state)) => {
|
||||
if state.contains(&proof_info.state) {
|
||||
proof = Some(proof_info.proof);
|
||||
}
|
||||
}
|
||||
(None, None) => proof = Some(proof_info.proof),
|
||||
}
|
||||
}
|
||||
|
||||
proof
|
||||
})
|
||||
.collect();
|
||||
|
||||
transaction.done().await.map_err(Error::from)?;
|
||||
|
||||
let proofs: Option<Proofs> = serde_wasm_bindgen::from_value(proofs).map_err(Error::from)?;
|
||||
if proofs.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(proofs)
|
||||
Ok(Some(proofs))
|
||||
}
|
||||
|
||||
async fn remove_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: &Proofs,
|
||||
) -> Result<(), Self::Err> {
|
||||
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
let transaction = rexie
|
||||
@@ -490,24 +513,10 @@ impl WalletDatabase for RexieWalletDatabase {
|
||||
|
||||
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
|
||||
|
||||
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
|
||||
let current_proofs = proofs_store.get(&mint_url).await.map_err(Error::from)?;
|
||||
for proof in proofs {
|
||||
let y = serde_wasm_bindgen::to_value(&proof.y()?).map_err(Error::from)?;
|
||||
|
||||
let current_proofs: Option<Proofs> =
|
||||
serde_wasm_bindgen::from_value(current_proofs).map_err(Error::from)?;
|
||||
|
||||
if let Some(current_proofs) = current_proofs {
|
||||
let proofs: Proofs = current_proofs
|
||||
.into_iter()
|
||||
.filter(|p| !proofs.contains(p))
|
||||
.collect();
|
||||
|
||||
let proofs = serde_wasm_bindgen::to_value(&proofs).map_err(Error::from)?;
|
||||
|
||||
proofs_store
|
||||
.put(&proofs, Some(&mint_url))
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
proofs_store.delete(&y).await.map_err(Error::from)?;
|
||||
}
|
||||
|
||||
transaction.done().await.map_err(Error::from)?;
|
||||
@@ -515,35 +524,26 @@ impl WalletDatabase for RexieWalletDatabase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: Proofs,
|
||||
) -> Result<(), Self::Err> {
|
||||
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
let transaction = rexie
|
||||
.transaction(&[PENDING_PROOFS], TransactionMode::ReadWrite)
|
||||
.transaction(&[PROOFS], TransactionMode::ReadWrite)
|
||||
.map_err(Error::from)?;
|
||||
|
||||
let proofs_store = transaction.store(PENDING_PROOFS).map_err(Error::from)?;
|
||||
let proofs_store = transaction.store(PROOFS).map_err(Error::from)?;
|
||||
|
||||
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
|
||||
let y = serde_wasm_bindgen::to_value(&y).map_err(Error::from)?;
|
||||
|
||||
let current_proofs = proofs_store.get(&mint_url).await.map_err(Error::from)?;
|
||||
let proof = proofs_store.get(&y).await.map_err(Error::from)?;
|
||||
let mut proof: ProofInfo = serde_wasm_bindgen::from_value(proof).map_err(Error::from)?;
|
||||
|
||||
let current_proofs: Proofs =
|
||||
serde_wasm_bindgen::from_value(current_proofs).unwrap_or_default();
|
||||
proof.state = state;
|
||||
|
||||
let all_proofs: Proofs = current_proofs
|
||||
.into_iter()
|
||||
.chain(proofs.into_iter())
|
||||
.collect();
|
||||
|
||||
let all_proofs = serde_wasm_bindgen::to_value(&all_proofs).map_err(Error::from)?;
|
||||
let proof = serde_wasm_bindgen::to_value(&proof).map_err(Error::from)?;
|
||||
|
||||
proofs_store
|
||||
.put(&all_proofs, Some(&mint_url))
|
||||
.put(&proof, Some(&y))
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
|
||||
@@ -552,66 +552,6 @@ impl WalletDatabase for RexieWalletDatabase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
) -> Result<Option<Proofs>, Self::Err> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
let transaction = rexie
|
||||
.transaction(&[PENDING_PROOFS], TransactionMode::ReadOnly)
|
||||
.map_err(Error::from)?;
|
||||
|
||||
let proofs_store = transaction.store(PENDING_PROOFS).map_err(Error::from)?;
|
||||
|
||||
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
|
||||
let proofs = proofs_store.get(&mint_url).await.map_err(Error::from)?;
|
||||
|
||||
transaction.done().await.map_err(Error::from)?;
|
||||
|
||||
let proofs: Option<Proofs> = serde_wasm_bindgen::from_value(proofs).unwrap_or(None);
|
||||
|
||||
Ok(proofs)
|
||||
}
|
||||
|
||||
async fn remove_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: &Proofs,
|
||||
) -> Result<(), Self::Err> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
let transaction = rexie
|
||||
.transaction(&[PENDING_PROOFS], TransactionMode::ReadWrite)
|
||||
.map_err(Error::from)?;
|
||||
|
||||
let proofs_store = transaction.store(PENDING_PROOFS).map_err(Error::from)?;
|
||||
|
||||
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
|
||||
let current_proofs = proofs_store.get(&mint_url).await.map_err(Error::from)?;
|
||||
|
||||
let current_proofs: Option<Proofs> =
|
||||
serde_wasm_bindgen::from_value(current_proofs).map_err(Error::from)?;
|
||||
|
||||
if let Some(current_proofs) = current_proofs {
|
||||
let proofs: Proofs = current_proofs
|
||||
.into_iter()
|
||||
.filter(|p| !proofs.contains(p))
|
||||
.collect();
|
||||
|
||||
let proofs = serde_wasm_bindgen::to_value(&proofs).map_err(Error::from)?;
|
||||
|
||||
proofs_store
|
||||
.add(&proofs, Some(&mint_url))
|
||||
.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> {
|
||||
let rexie = self.db.lock().await;
|
||||
|
||||
|
||||
@@ -9,16 +9,18 @@ use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::mint::MintKeySetInfo;
|
||||
#[cfg(any(feature = "nostr", feature = "mint"))]
|
||||
use crate::nuts::PublicKey;
|
||||
#[cfg(feature = "wallet")]
|
||||
use crate::nuts::State;
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::nuts::{BlindSignature, CurrencyUnit, Proof};
|
||||
#[cfg(any(feature = "wallet", feature = "mint"))]
|
||||
use crate::nuts::{Id, MintInfo};
|
||||
use crate::nuts::{Id, MintInfo, PublicKey};
|
||||
#[cfg(feature = "wallet")]
|
||||
use crate::nuts::{KeySetInfo, Keys, Proofs};
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::secret::Secret;
|
||||
#[cfg(feature = "wallet")]
|
||||
use crate::types::ProofInfo;
|
||||
#[cfg(any(feature = "wallet", feature = "mint"))]
|
||||
use crate::types::{MeltQuote, MintQuote};
|
||||
#[cfg(feature = "wallet")]
|
||||
@@ -35,6 +37,8 @@ pub enum Error {
|
||||
Database(Box<dyn std::error::Error + Send + Sync>),
|
||||
#[error(transparent)]
|
||||
Cdk(#[from] crate::error::Error),
|
||||
#[error(transparent)]
|
||||
NUT01(#[from] crate::nuts::nut00::Error),
|
||||
}
|
||||
|
||||
#[cfg(feature = "wallet")]
|
||||
@@ -73,23 +77,15 @@ pub trait WalletDatabase {
|
||||
async fn get_keys(&self, id: &Id) -> Result<Option<Keys>, Self::Err>;
|
||||
async fn remove_keys(&self, id: &Id) -> Result<(), Self::Err>;
|
||||
|
||||
async fn add_proofs(&self, mint_url: UncheckedUrl, proof: Proofs) -> Result<(), Self::Err>;
|
||||
async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Self::Err>;
|
||||
async fn remove_proofs(&self, mint_url: UncheckedUrl, proofs: &Proofs)
|
||||
-> Result<(), Self::Err>;
|
||||
async fn add_proofs(&self, proof_info: Vec<ProofInfo>) -> Result<(), Self::Err>;
|
||||
async fn get_proofs(
|
||||
&self,
|
||||
mint_url: Option<UncheckedUrl>,
|
||||
state: Option<Vec<State>>,
|
||||
) -> Result<Option<Proofs>, Self::Err>;
|
||||
async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err>;
|
||||
|
||||
async fn add_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proof: Proofs,
|
||||
) -> Result<(), Self::Err>;
|
||||
async fn get_pending_proofs(&self, mint_url: UncheckedUrl)
|
||||
-> Result<Option<Proofs>, Self::Err>;
|
||||
async fn remove_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: &Proofs,
|
||||
) -> Result<(), Self::Err>;
|
||||
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err>;
|
||||
|
||||
async fn increment_keyset_counter(&self, keyset_id: &Id, count: u32) -> Result<(), Self::Err>;
|
||||
async fn get_keyset_counter(&self, keyset_id: &Id) -> Result<Option<u32>, Self::Err>;
|
||||
|
||||
@@ -8,10 +8,8 @@ use tokio::sync::RwLock;
|
||||
|
||||
use super::WalletDatabase;
|
||||
use crate::cdk_database::Error;
|
||||
#[cfg(feature = "nostr")]
|
||||
use crate::nuts::PublicKey;
|
||||
use crate::nuts::{Id, KeySetInfo, Keys, MintInfo, Proof, Proofs};
|
||||
use crate::types::{MeltQuote, MintQuote};
|
||||
use crate::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, State};
|
||||
use crate::types::{MeltQuote, MintQuote, ProofInfo};
|
||||
use crate::url::UncheckedUrl;
|
||||
|
||||
// TODO: Change these all to RwLocks
|
||||
@@ -22,8 +20,7 @@ pub struct WalletMemoryDatabase {
|
||||
mint_quotes: Arc<RwLock<HashMap<String, MintQuote>>>,
|
||||
melt_quotes: Arc<RwLock<HashMap<String, MeltQuote>>>,
|
||||
mint_keys: Arc<RwLock<HashMap<Id, Keys>>>,
|
||||
proofs: Arc<RwLock<HashMap<UncheckedUrl, HashSet<Proof>>>>,
|
||||
pending_proofs: Arc<RwLock<HashMap<UncheckedUrl, HashSet<Proof>>>>,
|
||||
proofs: Arc<RwLock<HashMap<PublicKey, ProofInfo>>>,
|
||||
keyset_counter: Arc<RwLock<HashMap<Id, u32>>>,
|
||||
#[cfg(feature = "nostr")]
|
||||
nostr_last_checked: Arc<RwLock<HashMap<PublicKey, u32>>>,
|
||||
@@ -50,7 +47,6 @@ impl WalletMemoryDatabase {
|
||||
mint_keys.into_iter().map(|k| (Id::from(&k), k)).collect(),
|
||||
)),
|
||||
proofs: Arc::new(RwLock::new(HashMap::new())),
|
||||
pending_proofs: Arc::new(RwLock::new(HashMap::new())),
|
||||
keyset_counter: Arc::new(RwLock::new(keyset_counter)),
|
||||
#[cfg(feature = "nostr")]
|
||||
nostr_last_checked: Arc::new(RwLock::new(nostr_last_checked)),
|
||||
@@ -160,69 +156,81 @@ impl WalletDatabase for WalletMemoryDatabase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Error> {
|
||||
async fn add_proofs(&self, proofs_info: Vec<ProofInfo>) -> Result<(), Error> {
|
||||
let mut all_proofs = self.proofs.write().await;
|
||||
|
||||
let mint_proofs = all_proofs.entry(mint_url).or_insert(HashSet::new());
|
||||
mint_proofs.extend(proofs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Error> {
|
||||
Ok(self
|
||||
.proofs
|
||||
.read()
|
||||
.await
|
||||
.get(&mint_url)
|
||||
.map(|p| p.iter().cloned().collect()))
|
||||
}
|
||||
|
||||
async fn remove_proofs(&self, mint_url: UncheckedUrl, proofs: &Proofs) -> Result<(), Error> {
|
||||
let mut mint_proofs = self.proofs.write().await;
|
||||
|
||||
if let Some(mint_proofs) = mint_proofs.get_mut(&mint_url) {
|
||||
for proof in proofs {
|
||||
mint_proofs.remove(proof);
|
||||
}
|
||||
for proof_info in proofs_info.into_iter() {
|
||||
all_proofs.insert(proof_info.y, proof_info);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_pending_proofs(
|
||||
async fn get_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: Proofs,
|
||||
) -> Result<(), Error> {
|
||||
let mut all_proofs = self.pending_proofs.write().await;
|
||||
mint_url: Option<UncheckedUrl>,
|
||||
state: Option<Vec<State>>,
|
||||
) -> Result<Option<Proofs>, Error> {
|
||||
let proofs = self.proofs.read().await;
|
||||
|
||||
let mint_proofs = all_proofs.entry(mint_url).or_insert(HashSet::new());
|
||||
mint_proofs.extend(proofs);
|
||||
let proofs: Proofs = proofs
|
||||
.clone()
|
||||
.into_values()
|
||||
.filter_map(|proof_info| match (mint_url.clone(), state.clone()) {
|
||||
(Some(mint_url), Some(state)) => {
|
||||
if state.contains(&proof_info.state) && mint_url.eq(&proof_info.mint_url) {
|
||||
Some(proof_info.proof)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(Some(mint_url), None) => {
|
||||
if proof_info.mint_url.eq(&mint_url) {
|
||||
Some(proof_info.proof)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(None, Some(state)) => {
|
||||
if state.contains(&proof_info.state) {
|
||||
Some(proof_info.proof)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(None, None) => Some(proof_info.proof),
|
||||
})
|
||||
.collect();
|
||||
|
||||
if proofs.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(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 get_pending_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Error> {
|
||||
Ok(self
|
||||
.pending_proofs
|
||||
.read()
|
||||
.await
|
||||
.get(&mint_url)
|
||||
.map(|p| p.iter().cloned().collect()))
|
||||
}
|
||||
async fn set_proof_state(&self, y: PublicKey, state: State) -> Result<(), Self::Err> {
|
||||
let mint_proofs = self.proofs.read().await;
|
||||
|
||||
async fn remove_pending_proofs(
|
||||
&self,
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: &Proofs,
|
||||
) -> Result<(), Error> {
|
||||
let mut mint_proofs = self.pending_proofs.write().await;
|
||||
let mint_proof = mint_proofs.get(&y);
|
||||
|
||||
if let Some(mint_proofs) = mint_proofs.get_mut(&mint_url) {
|
||||
for proof in proofs {
|
||||
mint_proofs.remove(proof);
|
||||
}
|
||||
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(())
|
||||
|
||||
@@ -2,16 +2,56 @@
|
||||
//!
|
||||
//! <https://github.com/cashubtc/nuts/blob/main/07.md>
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::nut01::PublicKey;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
/// NUT07 Error
|
||||
#[derive(Debug, Error, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
/// Unknown State error
|
||||
#[error("Unknown State")]
|
||||
UnknownState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum State {
|
||||
Spent,
|
||||
Unspent,
|
||||
Pending,
|
||||
Reserved,
|
||||
}
|
||||
|
||||
impl fmt::Display for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let s = match self {
|
||||
State::Spent => "SPENT",
|
||||
State::Unspent => "UNSPENT",
|
||||
State::Pending => "PENDING",
|
||||
State::Reserved => "RESERVED",
|
||||
};
|
||||
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for State {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(state: &str) -> Result<Self, Self::Err> {
|
||||
match state {
|
||||
"SPENT" => Ok(Self::Spent),
|
||||
"UNSPENT" => Ok(Self::Unspent),
|
||||
"PENDING" => Ok(Self::Pending),
|
||||
"RESERVED" => Ok(Self::Reserved),
|
||||
_ => Err(Error::UnknownState),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check spendabale request [NUT-07]
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::nuts::{CurrencyUnit, Proofs};
|
||||
use crate::error::Error;
|
||||
use crate::nuts::{CurrencyUnit, Proof, Proofs, PublicKey, State};
|
||||
use crate::url::UncheckedUrl;
|
||||
use crate::Amount;
|
||||
|
||||
/// Melt response with proofs
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
pub struct Melted {
|
||||
pub paid: bool,
|
||||
pub preimage: Option<String>,
|
||||
@@ -16,7 +17,7 @@ pub struct Melted {
|
||||
}
|
||||
|
||||
/// Possible states of an invoice
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum InvoiceStatus {
|
||||
Unpaid,
|
||||
Paid,
|
||||
@@ -25,7 +26,7 @@ pub enum InvoiceStatus {
|
||||
}
|
||||
|
||||
/// Mint Quote Info
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MintQuote {
|
||||
pub id: String,
|
||||
pub mint_url: UncheckedUrl,
|
||||
@@ -59,7 +60,7 @@ impl MintQuote {
|
||||
}
|
||||
|
||||
/// Melt Quote Info
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MeltQuote {
|
||||
pub id: String,
|
||||
pub unit: CurrencyUnit,
|
||||
@@ -91,3 +92,26 @@ impl MeltQuote {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ProofInfo {
|
||||
pub proof: Proof,
|
||||
pub y: PublicKey,
|
||||
pub mint_url: UncheckedUrl,
|
||||
pub state: State,
|
||||
}
|
||||
|
||||
impl ProofInfo {
|
||||
pub fn new(proof: Proof, mint_url: UncheckedUrl, state: State) -> Result<Self, Error> {
|
||||
let y = proof
|
||||
.y()
|
||||
.map_err(|_| Error::CustomError("Could not find y".to_string()))?;
|
||||
|
||||
Ok(Self {
|
||||
proof,
|
||||
y,
|
||||
mint_url,
|
||||
state,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use crate::nuts::{
|
||||
ProofState, Proofs, PublicKey, RestoreRequest, SecretKey, SigFlag, SpendingConditions, State,
|
||||
SwapRequest, Token,
|
||||
};
|
||||
use crate::types::{MeltQuote, Melted, MintQuote};
|
||||
use crate::types::{MeltQuote, Melted, MintQuote, ProofInfo};
|
||||
use crate::url::UncheckedUrl;
|
||||
use crate::util::{hex, unix_time};
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
@@ -139,15 +139,16 @@ impl Wallet {
|
||||
/// Total Balance of wallet
|
||||
#[instrument(skip(self))]
|
||||
pub async fn total_balance(&self) -> Result<Amount, Error> {
|
||||
let mints = self.localstore.get_mints().await?;
|
||||
let mut balance = Amount::ZERO;
|
||||
|
||||
for (mint, _) in mints {
|
||||
if let Some(proofs) = self.localstore.get_proofs(mint.clone()).await? {
|
||||
let amount = proofs.iter().map(|p| p.amount).sum();
|
||||
if let Some(proofs) = self
|
||||
.localstore
|
||||
.get_proofs(None, Some(vec![State::Unspent]))
|
||||
.await?
|
||||
{
|
||||
let amount = proofs.iter().map(|p| p.amount).sum();
|
||||
|
||||
balance += amount;
|
||||
}
|
||||
balance += amount;
|
||||
}
|
||||
|
||||
Ok(balance)
|
||||
@@ -156,15 +157,16 @@ impl Wallet {
|
||||
/// Total Balance of wallet
|
||||
#[instrument(skip(self))]
|
||||
pub async fn total_pending_balance(&self) -> Result<Amount, Error> {
|
||||
let mints = self.localstore.get_mints().await?;
|
||||
let mut balance = Amount::ZERO;
|
||||
|
||||
for (mint, _) in mints {
|
||||
if let Some(proofs) = self.localstore.get_pending_proofs(mint.clone()).await? {
|
||||
let amount = proofs.iter().map(|p| p.amount).sum();
|
||||
if let Some(proofs) = self
|
||||
.localstore
|
||||
.get_proofs(None, Some(vec![State::Pending]))
|
||||
.await?
|
||||
{
|
||||
let amount = proofs.iter().map(|p| p.amount).sum();
|
||||
|
||||
balance += amount;
|
||||
}
|
||||
balance += amount;
|
||||
}
|
||||
|
||||
Ok(balance)
|
||||
@@ -177,7 +179,7 @@ impl Wallet {
|
||||
let mut balances = HashMap::new();
|
||||
|
||||
for (mint, _) in mints {
|
||||
if let Some(proofs) = self.localstore.get_proofs(mint.clone()).await? {
|
||||
if let Some(proofs) = self.localstore.get_proofs(Some(mint.clone()), None).await? {
|
||||
let amount = proofs.iter().map(|p| p.amount).sum();
|
||||
|
||||
balances.insert(mint, amount);
|
||||
@@ -191,7 +193,10 @@ impl Wallet {
|
||||
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Error> {
|
||||
Ok(self.localstore.get_proofs(mint_url).await?)
|
||||
Ok(self
|
||||
.localstore
|
||||
.get_proofs(Some(mint_url), Some(vec![State::Unspent]))
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
@@ -347,7 +352,14 @@ impl Wallet {
|
||||
let mut balance = Amount::ZERO;
|
||||
|
||||
for (mint, _) in mints {
|
||||
if let Some(proofs) = self.localstore.get_pending_proofs(mint.clone()).await? {
|
||||
if let Some(proofs) = self
|
||||
.localstore
|
||||
.get_proofs(
|
||||
Some(mint.clone()),
|
||||
Some(vec![State::Unspent, State::Pending]),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
let states = self
|
||||
.check_proofs_spent(mint.clone(), proofs.clone())
|
||||
.await?;
|
||||
@@ -367,9 +379,7 @@ impl Wallet {
|
||||
|
||||
let amount = pending_proofs.iter().map(|p| p.amount).sum();
|
||||
|
||||
self.localstore
|
||||
.remove_pending_proofs(mint, &non_pending_proofs)
|
||||
.await?;
|
||||
self.localstore.remove_proofs(&non_pending_proofs).await?;
|
||||
|
||||
balance += amount;
|
||||
}
|
||||
@@ -594,8 +604,13 @@ impl Wallet {
|
||||
.increment_keyset_counter(&active_keyset_id, proofs.len() as u32)
|
||||
.await?;
|
||||
|
||||
let proofs = proofs
|
||||
.into_iter()
|
||||
.flat_map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent))
|
||||
.collect();
|
||||
|
||||
// Add new proofs to store
|
||||
self.localstore.add_proofs(mint_url, proofs).await?;
|
||||
self.localstore.add_proofs(proofs).await?;
|
||||
|
||||
Ok(minted_amount)
|
||||
}
|
||||
@@ -680,9 +695,13 @@ impl Wallet {
|
||||
);
|
||||
}
|
||||
|
||||
self.localstore
|
||||
.add_pending_proofs(mint_url.clone(), send_proofs.clone())
|
||||
.await?;
|
||||
let send_proofs_info = send_proofs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.flat_map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Reserved))
|
||||
.collect();
|
||||
|
||||
self.localstore.add_proofs(send_proofs_info).await?;
|
||||
|
||||
proofs_to_send = Some(send_proofs);
|
||||
}
|
||||
@@ -692,17 +711,20 @@ impl Wallet {
|
||||
}
|
||||
}
|
||||
|
||||
self.localstore
|
||||
.remove_proofs(mint_url.clone(), &input_proofs)
|
||||
.await?;
|
||||
self.localstore.remove_proofs(&input_proofs).await?;
|
||||
|
||||
self.localstore
|
||||
.add_pending_proofs(mint_url.clone(), input_proofs)
|
||||
.await?;
|
||||
for proof in input_proofs {
|
||||
self.localstore
|
||||
.set_proof_state(proof.y()?, State::Reserved)
|
||||
.await?;
|
||||
}
|
||||
|
||||
self.localstore
|
||||
.add_proofs(mint_url.clone(), keep_proofs)
|
||||
.await?;
|
||||
let keep_proofs = keep_proofs
|
||||
.into_iter()
|
||||
.flat_map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent))
|
||||
.collect();
|
||||
|
||||
self.localstore.add_proofs(keep_proofs).await?;
|
||||
|
||||
Ok(proofs_to_send)
|
||||
}
|
||||
@@ -913,7 +935,7 @@ impl Wallet {
|
||||
) -> Result<Proofs, Error> {
|
||||
let mint_proofs = self
|
||||
.localstore
|
||||
.get_proofs(mint_url.clone())
|
||||
.get_proofs(Some(mint_url.clone()), Some(vec![State::Unspent]))
|
||||
.await?
|
||||
.ok_or(Error::InsufficientFunds)?;
|
||||
|
||||
@@ -1048,16 +1070,17 @@ impl Wallet {
|
||||
.increment_keyset_counter(&active_keyset_id, change_proofs.len() as u32)
|
||||
.await?;
|
||||
|
||||
self.localstore
|
||||
.add_proofs(mint_url.clone(), change_proofs)
|
||||
.await?;
|
||||
let change_proofs_info = change_proofs
|
||||
.into_iter()
|
||||
.flat_map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent))
|
||||
.collect();
|
||||
|
||||
self.localstore.add_proofs(change_proofs_info).await?;
|
||||
}
|
||||
|
||||
self.localstore.remove_melt_quote("e_info.id).await?;
|
||||
|
||||
self.localstore
|
||||
.remove_proofs(mint_url.clone(), &proofs)
|
||||
.await?;
|
||||
self.localstore.remove_proofs(&proofs).await?;
|
||||
|
||||
Ok(melted)
|
||||
}
|
||||
@@ -1209,7 +1232,11 @@ impl Wallet {
|
||||
let mut total_amount = Amount::ZERO;
|
||||
for (mint, proofs) in received_proofs {
|
||||
total_amount += proofs.iter().map(|p| p.amount).sum();
|
||||
self.localstore.add_proofs(mint, proofs).await?;
|
||||
let proofs = proofs
|
||||
.into_iter()
|
||||
.flat_map(|proof| ProofInfo::new(proof, mint.clone(), State::Unspent))
|
||||
.collect();
|
||||
self.localstore.add_proofs(proofs).await?;
|
||||
}
|
||||
|
||||
Ok(total_amount)
|
||||
@@ -1402,9 +1429,12 @@ impl Wallet {
|
||||
|
||||
restored_value += unspent_proofs.iter().map(|p| p.amount).sum();
|
||||
|
||||
self.localstore
|
||||
.add_proofs(mint_url.clone(), unspent_proofs)
|
||||
.await?;
|
||||
let unspent_proofs = unspent_proofs
|
||||
.into_iter()
|
||||
.flat_map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent))
|
||||
.collect();
|
||||
|
||||
self.localstore.add_proofs(unspent_proofs).await?;
|
||||
|
||||
empty_batch = 0;
|
||||
start_counter += 100;
|
||||
|
||||
Reference in New Issue
Block a user