use std::collections::HashSet;
use tracing::instrument;
use super::{CheckStateRequest, CheckStateResponse, Mint, ProofState, PublicKey, State};
use crate::{cdk_database, Error};
impl Mint {
#[instrument(skip_all)]
pub async fn check_state(
&self,
check_state: &CheckStateRequest,
) -> Result<CheckStateResponse, Error> {
let states = self.localstore.get_proofs_states(&check_state.ys).await?;
let states = states
.iter()
.zip(&check_state.ys)
.map(|(state, y)| {
let state = match state {
Some(state) => *state,
None => State::Unspent,
};
ProofState {
y: *y,
state,
witness: None,
}
})
.collect();
Ok(CheckStateResponse { states })
}
#[instrument(skip_all)]
pub async fn check_ys_spendable(
&self,
ys: &[PublicKey],
proof_state: State,
) -> Result<(), Error> {
let original_proofs_state =
match self.localstore.update_proofs_states(ys, proof_state).await {
Ok(states) => states,
Err(cdk_database::Error::AttemptUpdateSpentProof)
| Err(cdk_database::Error::AttemptRemoveSpentProof) => {
return Err(Error::TokenAlreadySpent)
}
Err(err) => return Err(err.into()),
};
let proofs_state = original_proofs_state
.iter()
.flatten()
.collect::<HashSet<&State>>();
if proofs_state.contains(&State::Pending) {
for (y, state) in ys.iter().zip(original_proofs_state.iter()) {
if let Some(original_state) = state {
self.localstore
.update_proofs_states(&[*y], *original_state)
.await?;
}
}
return Err(Error::TokenPending);
}
if proofs_state.contains(&State::Spent) {
for (y, state) in ys.iter().zip(original_proofs_state.iter()) {
if let Some(original_state) = state {
self.localstore
.update_proofs_states(&[*y], *original_state)
.await?;
}
}
return Err(Error::TokenAlreadySpent);
}
for public_key in ys {
tracing::debug!("proof: {} set to {}", public_key.to_hex(), proof_state);
self.pubsub_manager.proof_state((*public_key, proof_state));
}
Ok(())
}
}