use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use async_trait::async_trait;
use cashu::quote_id::QuoteId;
use cashu::Amount;
use super::{DbTransactionFinalizer, Error};
use crate::mint::{
self, MeltQuote, MintKeySetInfo, MintQuote as MintMintQuote, Operation, ProofsWithState,
};
use crate::nuts::{
BlindSignature, BlindedMessage, CurrencyUnit, Id, MeltQuoteState, Proof, Proofs, PublicKey,
State,
};
use crate::payment::PaymentIdentifier;
mod auth;
#[cfg(feature = "test")]
pub mod test;
pub use auth::{DynMintAuthDatabase, MintAuthDatabase, MintAuthTransaction};
pub use super::kvstore::{
validate_kvstore_params, validate_kvstore_string, KVStore, KVStoreDatabase, KVStoreTransaction,
KVSTORE_NAMESPACE_KEY_ALPHABET, KVSTORE_NAMESPACE_KEY_MAX_LEN,
};
#[derive(Debug)]
pub struct Acquired<T> {
inner: T,
}
impl<T> From<T> for Acquired<T> {
fn from(value: T) -> Self {
Acquired { inner: value }
}
}
impl<T> Acquired<T> {
pub fn inner(self) -> T {
self.inner
}
}
impl<T> Deref for Acquired<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for Acquired<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MeltRequestInfo {
pub inputs_amount: Amount<CurrencyUnit>,
pub inputs_fee: Amount<CurrencyUnit>,
pub change_outputs: Vec<BlindedMessage>,
}
#[derive(Debug)]
pub struct LockedMeltQuotes {
pub target: Option<Acquired<MeltQuote>>,
pub all_related: Vec<Acquired<MeltQuote>>,
}
#[async_trait]
pub trait KeysDatabaseTransaction<'a, Error>: DbTransactionFinalizer<Err = Error> {
async fn set_active_keyset(&mut self, unit: CurrencyUnit, id: Id) -> Result<(), Error>;
async fn add_keyset_info(&mut self, keyset: MintKeySetInfo) -> Result<(), Error>;
}
#[async_trait]
pub trait KeysDatabase {
type Err: Into<Error> + From<Error>;
async fn begin_transaction<'a>(
&'a self,
) -> Result<Box<dyn KeysDatabaseTransaction<'a, Self::Err> + Send + Sync + 'a>, Error>;
async fn get_active_keyset_id(&self, unit: &CurrencyUnit) -> Result<Option<Id>, Self::Err>;
async fn get_active_keysets(&self) -> Result<HashMap<CurrencyUnit, Id>, Self::Err>;
async fn get_keyset_info(&self, id: &Id) -> Result<Option<MintKeySetInfo>, Self::Err>;
async fn get_keyset_infos(&self) -> Result<Vec<MintKeySetInfo>, Self::Err>;
}
#[async_trait]
pub trait QuotesTransaction {
type Err: Into<Error> + From<Error>;
async fn add_melt_request(
&mut self,
quote_id: &QuoteId,
inputs_amount: Amount<CurrencyUnit>,
inputs_fee: Amount<CurrencyUnit>,
) -> Result<(), Self::Err>;
async fn add_blinded_messages(
&mut self,
quote_id: Option<&QuoteId>,
blinded_messages: &[BlindedMessage],
operation: &Operation,
) -> Result<(), Self::Err>;
async fn delete_blinded_messages(
&mut self,
blinded_secrets: &[PublicKey],
) -> Result<(), Self::Err>;
async fn get_melt_request_and_blinded_messages(
&mut self,
quote_id: &QuoteId,
) -> Result<Option<MeltRequestInfo>, Self::Err>;
async fn delete_melt_request(&mut self, quote_id: &QuoteId) -> Result<(), Self::Err>;
async fn get_mint_quote(
&mut self,
quote_id: &QuoteId,
) -> Result<Option<Acquired<MintMintQuote>>, Self::Err>;
async fn get_mint_quotes_by_ids(
&mut self,
quote_ids: &[QuoteId],
) -> Result<Vec<Option<Acquired<MintMintQuote>>>, Self::Err>;
async fn add_mint_quote(
&mut self,
quote: MintMintQuote,
) -> Result<Acquired<MintMintQuote>, Self::Err>;
async fn update_mint_quote(
&mut self,
quote: &mut Acquired<mint::MintQuote>,
) -> Result<(), Self::Err>;
async fn get_melt_quote(
&mut self,
quote_id: &QuoteId,
) -> Result<Option<Acquired<mint::MeltQuote>>, Self::Err>;
async fn add_melt_quote(&mut self, quote: mint::MeltQuote) -> Result<(), Self::Err>;
async fn get_melt_quotes_by_request_lookup_id(
&mut self,
request_lookup_id: &PaymentIdentifier,
) -> Result<Vec<Acquired<MeltQuote>>, Self::Err>;
async fn lock_melt_quote_and_related(
&mut self,
quote_id: &QuoteId,
) -> Result<LockedMeltQuotes, Self::Err>;
async fn update_melt_quote_request_lookup_id(
&mut self,
quote: &mut Acquired<mint::MeltQuote>,
new_request_lookup_id: &PaymentIdentifier,
) -> Result<(), Self::Err>;
async fn update_melt_quote_state(
&mut self,
quote: &mut Acquired<mint::MeltQuote>,
new_state: MeltQuoteState,
payment_proof: Option<String>,
) -> Result<MeltQuoteState, Self::Err>;
async fn get_mint_quote_by_request(
&mut self,
request: &str,
) -> Result<Option<Acquired<MintMintQuote>>, Self::Err>;
async fn get_mint_quote_by_request_lookup_id(
&mut self,
request_lookup_id: &PaymentIdentifier,
) -> Result<Option<Acquired<MintMintQuote>>, Self::Err>;
}
#[async_trait]
pub trait QuotesDatabase {
type Err: Into<Error> + From<Error>;
async fn get_mint_quote(&self, quote_id: &QuoteId) -> Result<Option<MintMintQuote>, Self::Err>;
async fn get_mint_quotes_by_ids(
&self,
quote_ids: &[QuoteId],
) -> Result<Vec<Option<MintMintQuote>>, Self::Err>;
async fn get_mint_quote_by_request(
&self,
request: &str,
) -> Result<Option<MintMintQuote>, Self::Err>;
async fn get_mint_quote_by_request_lookup_id(
&self,
request_lookup_id: &PaymentIdentifier,
) -> Result<Option<MintMintQuote>, Self::Err>;
async fn get_mint_quotes(&self) -> Result<Vec<MintMintQuote>, Self::Err>;
async fn get_melt_quote(
&self,
quote_id: &QuoteId,
) -> Result<Option<mint::MeltQuote>, Self::Err>;
async fn get_melt_quotes(&self) -> Result<Vec<mint::MeltQuote>, Self::Err>;
}
#[async_trait]
pub trait ProofsTransaction {
type Err: Into<Error> + From<Error>;
async fn add_proofs(
&mut self,
proof: Proofs,
quote_id: Option<QuoteId>,
operation: &Operation,
) -> Result<Acquired<ProofsWithState>, Self::Err>;
async fn update_proofs_state(
&mut self,
proofs: &mut Acquired<ProofsWithState>,
new_state: State,
) -> Result<(), Self::Err>;
async fn get_proofs(
&mut self,
ys: &[PublicKey],
) -> Result<Acquired<ProofsWithState>, Self::Err>;
async fn remove_proofs(
&mut self,
ys: &[PublicKey],
quote_id: Option<QuoteId>,
) -> Result<(), Self::Err>;
async fn get_proof_ys_by_quote_id(
&mut self,
quote_id: &QuoteId,
) -> Result<Vec<PublicKey>, Self::Err>;
async fn get_proof_ys_by_operation_id(
&mut self,
operation_id: &uuid::Uuid,
) -> Result<Vec<PublicKey>, Self::Err>;
}
#[async_trait]
pub trait ProofsDatabase {
type Err: Into<Error> + From<Error>;
async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result<Vec<Option<Proof>>, Self::Err>;
async fn get_proof_ys_by_quote_id(
&self,
quote_id: &QuoteId,
) -> Result<Vec<PublicKey>, Self::Err>;
async fn get_proofs_states(&self, ys: &[PublicKey]) -> Result<Vec<Option<State>>, Self::Err>;
async fn get_proofs_by_keyset_id(
&self,
keyset_id: &Id,
) -> Result<(Proofs, Vec<Option<State>>), Self::Err>;
async fn get_total_redeemed(&self) -> Result<HashMap<Id, Amount>, Self::Err>;
async fn get_proof_ys_by_operation_id(
&self,
operation_id: &uuid::Uuid,
) -> Result<Vec<PublicKey>, Self::Err>;
}
#[async_trait]
pub trait SignaturesTransaction {
type Err: Into<Error> + From<Error>;
async fn add_blind_signatures(
&mut self,
blinded_messages: &[PublicKey],
blind_signatures: &[BlindSignature],
quote_id: Option<QuoteId>,
) -> Result<(), Self::Err>;
async fn get_blind_signatures(
&mut self,
blinded_messages: &[PublicKey],
) -> Result<Vec<Option<BlindSignature>>, Self::Err>;
}
#[async_trait]
pub trait SignaturesDatabase {
type Err: Into<Error> + From<Error>;
async fn get_blind_signatures(
&self,
blinded_messages: &[PublicKey],
) -> Result<Vec<Option<BlindSignature>>, Self::Err>;
async fn get_blind_signatures_for_keyset(
&self,
keyset_id: &Id,
) -> Result<Vec<BlindSignature>, Self::Err>;
async fn get_blind_signatures_for_quote(
&self,
quote_id: &QuoteId,
) -> Result<Vec<BlindSignature>, Self::Err>;
async fn get_total_issued(&self) -> Result<HashMap<Id, Amount>, Self::Err>;
async fn get_blinded_secrets_by_operation_id(
&self,
operation_id: &uuid::Uuid,
) -> Result<Vec<PublicKey>, Self::Err>;
}
#[async_trait]
pub trait SagaTransaction {
type Err: Into<Error> + From<Error>;
async fn get_saga(
&mut self,
operation_id: &uuid::Uuid,
) -> Result<Option<mint::Saga>, Self::Err>;
async fn add_saga(&mut self, saga: &mint::Saga) -> Result<(), Self::Err>;
async fn update_saga(
&mut self,
operation_id: &uuid::Uuid,
new_state: mint::SagaStateEnum,
) -> Result<(), Self::Err>;
async fn delete_saga(&mut self, operation_id: &uuid::Uuid) -> Result<(), Self::Err>;
}
#[async_trait]
pub trait SagaDatabase {
type Err: Into<Error> + From<Error>;
async fn get_incomplete_sagas(
&self,
operation_kind: mint::OperationKind,
) -> Result<Vec<mint::Saga>, Self::Err>;
}
#[async_trait]
pub trait CompletedOperationsTransaction {
type Err: Into<Error> + From<Error>;
async fn add_completed_operation(
&mut self,
operation: &mint::Operation,
fee_by_keyset: &std::collections::HashMap<crate::nuts::Id, crate::Amount>,
) -> Result<(), Self::Err>;
}
#[async_trait]
pub trait CompletedOperationsDatabase {
type Err: Into<Error> + From<Error>;
async fn get_completed_operation(
&self,
operation_id: &uuid::Uuid,
) -> Result<Option<mint::Operation>, Self::Err>;
async fn get_completed_operations_by_kind(
&self,
operation_kind: mint::OperationKind,
) -> Result<Vec<mint::Operation>, Self::Err>;
async fn get_completed_operations(&self) -> Result<Vec<mint::Operation>, Self::Err>;
}
pub trait Transaction<Error>:
DbTransactionFinalizer<Err = Error>
+ QuotesTransaction<Err = Error>
+ SignaturesTransaction<Err = Error>
+ ProofsTransaction<Err = Error>
+ KVStoreTransaction<Error>
+ SagaTransaction<Err = Error>
+ CompletedOperationsTransaction<Err = Error>
{
}
#[async_trait]
pub trait Database<Error>:
KVStoreDatabase<Err = Error>
+ QuotesDatabase<Err = Error>
+ ProofsDatabase<Err = Error>
+ SignaturesDatabase<Err = Error>
+ SagaDatabase<Err = Error>
+ CompletedOperationsDatabase<Err = Error>
{
async fn begin_transaction(&self) -> Result<Box<dyn Transaction<Error> + Send + Sync>, Error>;
}
pub type DynMintDatabase = std::sync::Arc<dyn Database<Error> + Send + Sync>;
pub type DynMintTransaction = Box<dyn Transaction<Error> + Send + Sync>;