mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-20 06:05:09 +01:00
refactor: use sproof state update
This commit is contained in:
@@ -40,6 +40,7 @@
|
|||||||
- cdk(wallet): Add `fn melt_proofs` that uses specific proofs for `melt` instead of selecting ([thesimplekid]).
|
- cdk(wallet): Add `fn melt_proofs` that uses specific proofs for `melt` instead of selecting ([thesimplekid]).
|
||||||
- cdk-cli(receive): Add support for signing keys to be nostr nsec encoded ([thesimplekid]).
|
- cdk-cli(receive): Add support for signing keys to be nostr nsec encoded ([thesimplekid]).
|
||||||
- cdk-fake-wallet: Add Fake wallet for testing ([thesimplekid]).
|
- cdk-fake-wallet: Add Fake wallet for testing ([thesimplekid]).
|
||||||
|
- cdk(cdk-database/mint): Add `add_proofs`, `get_proofs_by_ys`, `get_proofs_states`, and `update_proofs_states` ([thesimplekid]).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- cdk(mint): `SIG_ALL` is not allowed in `melt` ([thesimplekid]).
|
- cdk(mint): `SIG_ALL` is not allowed in `melt` ([thesimplekid]).
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- cdk(wallet): Remove unused argument `SplitTarget` on `melt` ([thesimplekid]).
|
- cdk(wallet): Remove unused argument `SplitTarget` on `melt` ([thesimplekid]).
|
||||||
|
- cdk(cdk-database/mint): Remove `get_spent_proofs`, `get_spent_proofs_by_ys`,`get_pending_proofs`, `get_pending_proofs_by_ys`, and `remove_pending_proofs` ([thesimplekid]).
|
||||||
|
|
||||||
## [v0.2.0]
|
## [v0.2.0]
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,31 @@
|
|||||||
|
use core::str;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cdk::mint::MintQuote;
|
use cdk::mint::MintQuote;
|
||||||
use cdk::nuts::{CurrencyUnit, MintQuoteState};
|
use cdk::nuts::{CurrencyUnit, MintQuoteState, Proof, State};
|
||||||
use cdk::{Amount, UncheckedUrl};
|
use cdk::{Amount, UncheckedUrl};
|
||||||
use lightning_invoice::Bolt11Invoice;
|
use lightning_invoice::Bolt11Invoice;
|
||||||
use redb::{Database, ReadableTable, TableDefinition};
|
use redb::{Database, ReadableTable, TableDefinition};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::Error;
|
use super::{Error, PROOFS_STATE_TABLE, PROOFS_TABLE};
|
||||||
|
|
||||||
const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
|
const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
|
||||||
|
const PENDING_PROOFS_TABLE: TableDefinition<[u8; 33], &str> =
|
||||||
|
TableDefinition::new("pending_proofs");
|
||||||
|
const SPENT_PROOFS_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("spent_proofs");
|
||||||
|
|
||||||
pub fn migrate_01_to_02(db: Arc<Database>) -> Result<u32, Error> {
|
pub fn migrate_01_to_02(db: Arc<Database>) -> Result<u32, Error> {
|
||||||
migrate_mint_quotes_01_to_02(db)?;
|
migrate_mint_quotes_01_to_02(db)?;
|
||||||
|
|
||||||
Ok(2)
|
Ok(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn migrate_02_to_03(db: Arc<Database>) -> Result<u32, Error> {
|
||||||
|
migrate_mint_proofs_02_to_03(db)?;
|
||||||
|
Ok(3)
|
||||||
|
}
|
||||||
/// Mint Quote Info
|
/// Mint Quote Info
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
struct V1MintQuote {
|
struct V1MintQuote {
|
||||||
@@ -97,3 +105,70 @@ fn migrate_mint_quotes_01_to_02(db: Arc<Database>) -> Result<(), Error> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn migrate_mint_proofs_02_to_03(db: Arc<Database>) -> Result<(), Error> {
|
||||||
|
let pending_proofs: Vec<([u8; 33], Option<Proof>)>;
|
||||||
|
let spent_proofs: Vec<([u8; 33], Option<Proof>)>;
|
||||||
|
|
||||||
|
{
|
||||||
|
let read_txn = db.begin_read().map_err(Error::from)?;
|
||||||
|
let table = read_txn
|
||||||
|
.open_table(PENDING_PROOFS_TABLE)
|
||||||
|
.map_err(Error::from)?;
|
||||||
|
|
||||||
|
pending_proofs = table
|
||||||
|
.iter()
|
||||||
|
.map_err(Error::from)?
|
||||||
|
.flatten()
|
||||||
|
.map(|(quote_id, mint_quote)| {
|
||||||
|
(
|
||||||
|
quote_id.value(),
|
||||||
|
serde_json::from_str(mint_quote.value()).ok(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let read_txn = db.begin_read().map_err(Error::from)?;
|
||||||
|
let table = read_txn
|
||||||
|
.open_table(SPENT_PROOFS_TABLE)
|
||||||
|
.map_err(Error::from)?;
|
||||||
|
|
||||||
|
spent_proofs = table
|
||||||
|
.iter()
|
||||||
|
.map_err(Error::from)?
|
||||||
|
.flatten()
|
||||||
|
.map(|(quote_id, mint_quote)| {
|
||||||
|
(
|
||||||
|
quote_id.value(),
|
||||||
|
serde_json::from_str(mint_quote.value()).ok(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
let write_txn = db.begin_write().map_err(Error::from)?;
|
||||||
|
{
|
||||||
|
let mut proofs_table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
|
||||||
|
let mut state_table = write_txn
|
||||||
|
.open_table(PROOFS_STATE_TABLE)
|
||||||
|
.map_err(Error::from)?;
|
||||||
|
|
||||||
|
for (y, proof) in pending_proofs {
|
||||||
|
if let Some(proof) = proof {
|
||||||
|
proofs_table.insert(y, serde_json::to_string(&proof)?.as_str())?;
|
||||||
|
state_table.insert(y, State::Pending.to_string().as_str())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y, proof) in spent_proofs {
|
||||||
|
if let Some(proof) = proof {
|
||||||
|
proofs_table.insert(y, serde_json::to_string(&proof)?.as_str())?;
|
||||||
|
state_table.insert(y, State::Spent.to_string().as_str())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_txn.commit()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ use cdk::cdk_database::MintDatabase;
|
|||||||
use cdk::dhke::hash_to_curve;
|
use cdk::dhke::hash_to_curve;
|
||||||
use cdk::mint::{MintKeySetInfo, MintQuote};
|
use cdk::mint::{MintKeySetInfo, MintQuote};
|
||||||
use cdk::nuts::{
|
use cdk::nuts::{
|
||||||
BlindSignature, CurrencyUnit, Id, MeltQuoteState, MintQuoteState, Proof, PublicKey,
|
BlindSignature, CurrencyUnit, Id, MeltQuoteState, MintQuoteState, Proof, Proofs, PublicKey,
|
||||||
|
State,
|
||||||
};
|
};
|
||||||
use cdk::secret::Secret;
|
|
||||||
use cdk::{cdk_database, mint};
|
use cdk::{cdk_database, mint};
|
||||||
use migrations::migrate_01_to_02;
|
use migrations::migrate_01_to_02;
|
||||||
use redb::{Database, ReadableTable, TableDefinition};
|
use redb::{Database, ReadableTable, TableDefinition};
|
||||||
@@ -21,6 +21,7 @@ use tokio::sync::Mutex;
|
|||||||
|
|
||||||
use super::error::Error;
|
use super::error::Error;
|
||||||
use crate::migrations::migrate_00_to_01;
|
use crate::migrations::migrate_00_to_01;
|
||||||
|
use crate::mint::migrations::migrate_02_to_03;
|
||||||
|
|
||||||
mod migrations;
|
mod migrations;
|
||||||
|
|
||||||
@@ -28,15 +29,14 @@ const ACTIVE_KEYSETS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("
|
|||||||
const KEYSETS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("keysets");
|
const KEYSETS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("keysets");
|
||||||
const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
|
const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
|
||||||
const MELT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("melt_quotes");
|
const MELT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("melt_quotes");
|
||||||
const PENDING_PROOFS_TABLE: TableDefinition<[u8; 33], &str> =
|
const PROOFS_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("proofs");
|
||||||
TableDefinition::new("pending_proofs");
|
const PROOFS_STATE_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("proofs_state");
|
||||||
const SPENT_PROOFS_TABLE: TableDefinition<[u8; 33], &str> = TableDefinition::new("spent_proofs");
|
|
||||||
const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config");
|
const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config");
|
||||||
// Key is hex blinded_message B_ value is blinded_signature
|
// Key is hex blinded_message B_ value is blinded_signature
|
||||||
const BLINDED_SIGNATURES: TableDefinition<[u8; 33], &str> =
|
const BLINDED_SIGNATURES: TableDefinition<[u8; 33], &str> =
|
||||||
TableDefinition::new("blinded_signatures");
|
TableDefinition::new("blinded_signatures");
|
||||||
|
|
||||||
const DATABASE_VERSION: u32 = 2;
|
const DATABASE_VERSION: u32 = 3;
|
||||||
|
|
||||||
/// Mint Redbdatabase
|
/// Mint Redbdatabase
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -78,6 +78,10 @@ impl MintRedbDatabase {
|
|||||||
current_file_version = migrate_01_to_02(Arc::clone(&db))?;
|
current_file_version = migrate_01_to_02(Arc::clone(&db))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if current_file_version == 2 {
|
||||||
|
current_file_version = migrate_02_to_03(Arc::clone(&db))?;
|
||||||
|
}
|
||||||
|
|
||||||
if current_file_version != DATABASE_VERSION {
|
if current_file_version != DATABASE_VERSION {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"Database upgrade did not complete at {} current is {}",
|
"Database upgrade did not complete at {} current is {}",
|
||||||
@@ -109,8 +113,8 @@ impl MintRedbDatabase {
|
|||||||
let _ = write_txn.open_table(KEYSETS_TABLE)?;
|
let _ = write_txn.open_table(KEYSETS_TABLE)?;
|
||||||
let _ = write_txn.open_table(MINT_QUOTES_TABLE)?;
|
let _ = write_txn.open_table(MINT_QUOTES_TABLE)?;
|
||||||
let _ = write_txn.open_table(MELT_QUOTES_TABLE)?;
|
let _ = write_txn.open_table(MELT_QUOTES_TABLE)?;
|
||||||
let _ = write_txn.open_table(PENDING_PROOFS_TABLE)?;
|
let _ = write_txn.open_table(PROOFS_TABLE)?;
|
||||||
let _ = write_txn.open_table(SPENT_PROOFS_TABLE)?;
|
let _ = write_txn.open_table(PROOFS_STATE_TABLE)?;
|
||||||
let _ = write_txn.open_table(BLINDED_SIGNATURES)?;
|
let _ = write_txn.open_table(BLINDED_SIGNATURES)?;
|
||||||
|
|
||||||
table.insert("db_version", DATABASE_VERSION.to_string().as_str())?;
|
table.insert("db_version", DATABASE_VERSION.to_string().as_str())?;
|
||||||
@@ -494,15 +498,13 @@ impl MintDatabase for MintRedbDatabase {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_spent_proofs(&self, proofs: Vec<Proof>) -> Result<(), Self::Err> {
|
async fn add_proofs(&self, proofs: Proofs) -> 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)?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut table = write_txn
|
let mut table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
|
||||||
.open_table(SPENT_PROOFS_TABLE)
|
|
||||||
.map_err(Error::from)?;
|
|
||||||
for proof in proofs {
|
for proof in proofs {
|
||||||
let y: PublicKey = hash_to_curve(&proof.secret.to_bytes()).map_err(Error::from)?;
|
let y: PublicKey = hash_to_curve(&proof.secret.to_bytes()).map_err(Error::from)?;
|
||||||
table
|
table
|
||||||
@@ -518,15 +520,10 @@ impl MintDatabase for MintRedbDatabase {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_spent_proofs_by_ys(
|
async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result<Vec<Option<Proof>>, Self::Err> {
|
||||||
&self,
|
|
||||||
ys: &[PublicKey],
|
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err> {
|
|
||||||
let db = self.db.lock().await;
|
let db = self.db.lock().await;
|
||||||
let read_txn = db.begin_read().map_err(Error::from)?;
|
let read_txn = db.begin_read().map_err(Error::from)?;
|
||||||
let table = read_txn
|
let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?;
|
||||||
.open_table(SPENT_PROOFS_TABLE)
|
|
||||||
.map_err(Error::from)?;
|
|
||||||
|
|
||||||
let mut proofs = Vec::with_capacity(ys.len());
|
let mut proofs = Vec::with_capacity(ys.len());
|
||||||
|
|
||||||
@@ -542,70 +539,55 @@ impl MintDatabase for MintRedbDatabase {
|
|||||||
Ok(proofs)
|
Ok(proofs)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_pending_proofs(&self, proofs: Vec<Proof>) -> Result<(), Self::Err> {
|
async fn get_proofs_states(&self, ys: &[PublicKey]) -> Result<Vec<Option<State>>, 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(PENDING_PROOFS_TABLE)
|
|
||||||
.map_err(Error::from)?;
|
|
||||||
for proof in proofs {
|
|
||||||
table
|
|
||||||
.insert(
|
|
||||||
hash_to_curve(&proof.secret.to_bytes())?.to_bytes(),
|
|
||||||
serde_json::to_string(&proof).map_err(Error::from)?.as_str(),
|
|
||||||
)
|
|
||||||
.map_err(Error::from)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write_txn.commit().map_err(Error::from)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_pending_proofs_by_ys(
|
|
||||||
&self,
|
|
||||||
ys: &[PublicKey],
|
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err> {
|
|
||||||
let db = self.db.lock().await;
|
let db = self.db.lock().await;
|
||||||
let read_txn = db.begin_read().map_err(Error::from)?;
|
let read_txn = db.begin_read().map_err(Error::from)?;
|
||||||
let table = read_txn
|
let table = read_txn
|
||||||
.open_table(PENDING_PROOFS_TABLE)
|
.open_table(PROOFS_STATE_TABLE)
|
||||||
.map_err(Error::from)?;
|
.map_err(Error::from)?;
|
||||||
|
|
||||||
let mut proofs = Vec::with_capacity(ys.len());
|
let mut states = Vec::with_capacity(ys.len());
|
||||||
|
|
||||||
for y in ys {
|
for y in ys {
|
||||||
match table.get(y.to_bytes()).map_err(Error::from)? {
|
match table.get(y.to_bytes()).map_err(Error::from)? {
|
||||||
Some(proof) => proofs.push(Some(
|
Some(state) => states.push(Some(
|
||||||
serde_json::from_str(proof.value()).map_err(Error::from)?,
|
serde_json::from_str(state.value()).map_err(Error::from)?,
|
||||||
)),
|
)),
|
||||||
None => proofs.push(None),
|
None => states.push(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(proofs)
|
Ok(states)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn remove_pending_proofs(&self, secrets: Vec<&Secret>) -> Result<(), Self::Err> {
|
async fn update_proofs_states(
|
||||||
|
&self,
|
||||||
|
ys: &[PublicKey],
|
||||||
|
proofs_state: State,
|
||||||
|
) -> Result<Vec<Option<State>>, 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)?;
|
||||||
|
let mut table = write_txn
|
||||||
|
.open_table(PROOFS_STATE_TABLE)
|
||||||
|
.map_err(Error::from)?;
|
||||||
|
|
||||||
{
|
let mut states = Vec::with_capacity(ys.len());
|
||||||
let mut table = write_txn
|
|
||||||
.open_table(PENDING_PROOFS_TABLE)
|
let state_str = serde_json::to_string(&proofs_state).map_err(Error::from)?;
|
||||||
.map_err(Error::from)?;
|
|
||||||
for secret in secrets {
|
for y in ys {
|
||||||
let secret_hash = hash_to_curve(&secret.to_bytes()).map_err(Error::from)?;
|
match table
|
||||||
table.remove(secret_hash.to_bytes()).map_err(Error::from)?;
|
.insert(y.to_bytes(), state_str.as_str())
|
||||||
|
.map_err(Error::from)?
|
||||||
|
{
|
||||||
|
Some(state) => states.push(Some(
|
||||||
|
serde_json::from_str(state.value()).map_err(Error::from)?,
|
||||||
|
)),
|
||||||
|
None => states.push(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_txn.commit().map_err(Error::from)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(states)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_blind_signatures(
|
async fn add_blind_signatures(
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ pub enum Error {
|
|||||||
/// NUT05 Error
|
/// NUT05 Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
CDKNUT05(#[from] cdk::nuts::nut05::Error),
|
CDKNUT05(#[from] cdk::nuts::nut05::Error),
|
||||||
|
/// NUT07 Error
|
||||||
|
#[error(transparent)]
|
||||||
|
CDKNUT07(#[from] cdk::nuts::nut07::Error),
|
||||||
/// Secret Error
|
/// Secret Error
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
CDKSECRET(#[from] cdk::secret::Error),
|
CDKSECRET(#[from] cdk::secret::Error),
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-- Create a new table with the updated CHECK constraint
|
||||||
|
CREATE TABLE proof_new (
|
||||||
|
y BLOB PRIMARY KEY,
|
||||||
|
amount INTEGER NOT NULL,
|
||||||
|
keyset_id TEXT NOT NULL,
|
||||||
|
secret TEXT NOT NULL,
|
||||||
|
c BLOB NOT NULL,
|
||||||
|
witness TEXT,
|
||||||
|
state TEXT CHECK (state IN ('SPENT', 'PENDING', 'UNSPENT')) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Copy the data from the old table to the new table
|
||||||
|
INSERT INTO proof_new (y, amount, keyset_id, secret, c, witness, state)
|
||||||
|
SELECT y, amount, keyset_id, secret, c, witness, state
|
||||||
|
FROM proof;
|
||||||
|
|
||||||
|
-- Drop the old table
|
||||||
|
DROP TABLE proof;
|
||||||
|
|
||||||
|
-- Rename the new table to the original table name
|
||||||
|
ALTER TABLE proof_new RENAME TO proof;
|
||||||
@@ -11,6 +11,7 @@ use cdk::mint::{MintKeySetInfo, MintQuote};
|
|||||||
use cdk::nuts::nut05::QuoteState;
|
use cdk::nuts::nut05::QuoteState;
|
||||||
use cdk::nuts::{
|
use cdk::nuts::{
|
||||||
BlindSignature, CurrencyUnit, Id, MeltQuoteState, MintQuoteState, Proof, Proofs, PublicKey,
|
BlindSignature, CurrencyUnit, Id, MeltQuoteState, MintQuoteState, Proof, Proofs, PublicKey,
|
||||||
|
State,
|
||||||
};
|
};
|
||||||
use cdk::secret::Secret;
|
use cdk::secret::Secret;
|
||||||
use cdk::{mint, Amount};
|
use cdk::{mint, Amount};
|
||||||
@@ -480,13 +481,12 @@ FROM keyset;
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_spent_proofs(&self, proofs: Proofs) -> Result<(), Self::Err> {
|
async fn add_proofs(&self, proofs: Proofs) -> Result<(), Self::Err> {
|
||||||
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
||||||
|
|
||||||
for proof in proofs {
|
for proof in proofs {
|
||||||
sqlx::query(
|
if let Err(err) = sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
INSERT OR REPLACE INTO proof
|
INSERT INTO proof
|
||||||
(y, amount, keyset_id, secret, c, witness, state)
|
(y, amount, keyset_id, secret, c, witness, state)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?);
|
VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||||
"#,
|
"#,
|
||||||
@@ -497,79 +497,19 @@ VALUES (?, ?, ?, ?, ?, ?, ?);
|
|||||||
.bind(proof.secret.to_string())
|
.bind(proof.secret.to_string())
|
||||||
.bind(proof.c.to_bytes().to_vec())
|
.bind(proof.c.to_bytes().to_vec())
|
||||||
.bind(proof.witness.map(|w| serde_json::to_string(&w).unwrap()))
|
.bind(proof.witness.map(|w| serde_json::to_string(&w).unwrap()))
|
||||||
.bind("SPENT")
|
.bind("UNSPENT")
|
||||||
.execute(&mut transaction)
|
.execute(&mut transaction)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::from)?;
|
.map_err(Error::from)
|
||||||
}
|
{
|
||||||
transaction.commit().await.map_err(Error::from)?;
|
tracing::debug!("Attempting to add known proof. Skipping.... {:?}", err);
|
||||||
Ok(())
|
}
|
||||||
}
|
|
||||||
async fn get_spent_proofs_by_ys(
|
|
||||||
&self,
|
|
||||||
ys: &[PublicKey],
|
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err> {
|
|
||||||
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
|
||||||
|
|
||||||
let mut proofs = Vec::with_capacity(ys.len());
|
|
||||||
for y in ys {
|
|
||||||
let rec = sqlx::query(
|
|
||||||
r#"
|
|
||||||
SELECT *
|
|
||||||
FROM proof
|
|
||||||
WHERE y=?
|
|
||||||
AND state="SPENT";
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.bind(y.to_bytes().to_vec())
|
|
||||||
.fetch_one(&mut transaction)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match rec {
|
|
||||||
Ok(rec) => {
|
|
||||||
proofs.push(Some(sqlite_row_to_proof(rec)?));
|
|
||||||
}
|
|
||||||
Err(err) => match err {
|
|
||||||
sqlx::Error::RowNotFound => proofs.push(None),
|
|
||||||
_ => return Err(Error::SQLX(err).into()),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction.commit().await.map_err(Error::from)?;
|
|
||||||
|
|
||||||
Ok(proofs)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_pending_proofs(&self, proofs: Proofs) -> Result<(), Self::Err> {
|
|
||||||
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
|
||||||
for proof in proofs {
|
|
||||||
sqlx::query(
|
|
||||||
r#"
|
|
||||||
INSERT OR REPLACE INTO proof
|
|
||||||
(y, amount, keyset_id, secret, c, witness, state)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?);
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.bind(proof.y()?.to_bytes().to_vec())
|
|
||||||
.bind(u64::from(proof.amount) as i64)
|
|
||||||
.bind(proof.keyset_id.to_string())
|
|
||||||
.bind(proof.secret.to_string())
|
|
||||||
.bind(proof.c.to_bytes().to_vec())
|
|
||||||
.bind(proof.witness.map(|w| serde_json::to_string(&w).unwrap()))
|
|
||||||
.bind("PENDING")
|
|
||||||
.execute(&mut transaction)
|
|
||||||
.await
|
|
||||||
.map_err(Error::from)?;
|
|
||||||
}
|
}
|
||||||
transaction.commit().await.map_err(Error::from)?;
|
transaction.commit().await.map_err(Error::from)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn get_pending_proofs_by_ys(
|
async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result<Vec<Option<Proof>>, Self::Err> {
|
||||||
&self,
|
|
||||||
ys: &[PublicKey],
|
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err> {
|
|
||||||
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
||||||
|
|
||||||
let mut proofs = Vec::with_capacity(ys.len());
|
let mut proofs = Vec::with_capacity(ys.len());
|
||||||
@@ -579,8 +519,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?);
|
|||||||
r#"
|
r#"
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM proof
|
FROM proof
|
||||||
WHERE y=?
|
WHERE y=?;
|
||||||
AND state="PENDING";
|
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(y.to_bytes().to_vec())
|
.bind(y.to_bytes().to_vec())
|
||||||
@@ -600,26 +539,91 @@ AND state="PENDING";
|
|||||||
|
|
||||||
Ok(proofs)
|
Ok(proofs)
|
||||||
}
|
}
|
||||||
async fn remove_pending_proofs(&self, secrets: Vec<&Secret>) -> Result<(), Self::Err> {
|
|
||||||
|
async fn get_proofs_states(&self, ys: &[PublicKey]) -> Result<Vec<Option<State>>, Self::Err> {
|
||||||
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
||||||
for secret in secrets {
|
|
||||||
sqlx::query(
|
let mut states = Vec::with_capacity(ys.len());
|
||||||
|
|
||||||
|
for y in ys {
|
||||||
|
let rec = sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
DELETE FROM proof
|
SELECT state
|
||||||
WHERE secret=?
|
FROM proof
|
||||||
AND state="PENDING";
|
WHERE y=?;
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(secret.to_string())
|
.bind(y.to_bytes().to_vec())
|
||||||
|
.fetch_one(&mut transaction)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match rec {
|
||||||
|
Ok(rec) => {
|
||||||
|
let state: String = rec.get("state");
|
||||||
|
let state = State::from_str(&state).map_err(Error::from)?;
|
||||||
|
states.push(Some(state));
|
||||||
|
}
|
||||||
|
Err(err) => match err {
|
||||||
|
sqlx::Error::RowNotFound => states.push(None),
|
||||||
|
_ => return Err(Error::SQLX(err).into()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(states)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_proofs_states(
|
||||||
|
&self,
|
||||||
|
ys: &[PublicKey],
|
||||||
|
proofs_state: State,
|
||||||
|
) -> Result<Vec<Option<State>>, Self::Err> {
|
||||||
|
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
||||||
|
|
||||||
|
let mut states = Vec::with_capacity(ys.len());
|
||||||
|
|
||||||
|
let proofs_state = proofs_state.to_string();
|
||||||
|
for y in ys {
|
||||||
|
let y = y.to_bytes().to_vec();
|
||||||
|
let rec = sqlx::query(
|
||||||
|
r#"
|
||||||
|
SELECT state
|
||||||
|
FROM proof
|
||||||
|
WHERE y=?;
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(&y)
|
||||||
|
.fetch_one(&mut transaction)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match rec {
|
||||||
|
Ok(rec) => {
|
||||||
|
let state: String = rec.get("state");
|
||||||
|
let state = State::from_str(&state).map_err(Error::from)?;
|
||||||
|
states.push(Some(state));
|
||||||
|
}
|
||||||
|
Err(err) => match err {
|
||||||
|
sqlx::Error::RowNotFound => states.push(None),
|
||||||
|
_ => return Err(Error::SQLX(err).into()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
UPDATE proof SET state = ? WHERE y = ?
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(&proofs_state)
|
||||||
|
.bind(y)
|
||||||
.execute(&mut transaction)
|
.execute(&mut transaction)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::from)?;
|
.map_err(Error::from)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.commit().await.map_err(Error::from)?;
|
transaction.commit().await.map_err(Error::from)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(states)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_blind_signatures(
|
async fn add_blind_signatures(
|
||||||
&self,
|
&self,
|
||||||
blinded_messages: &[PublicKey],
|
blinded_messages: &[PublicKey],
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
|
||||||
use super::{Error, MintDatabase};
|
use super::{Error, MintDatabase};
|
||||||
use crate::dhke::hash_to_curve;
|
use crate::dhke::hash_to_curve;
|
||||||
use crate::mint::{self, MintKeySetInfo, MintQuote};
|
use crate::mint::{self, MintKeySetInfo, MintQuote};
|
||||||
|
use crate::nuts::nut07::State;
|
||||||
use crate::nuts::{
|
use crate::nuts::{
|
||||||
BlindSignature, CurrencyUnit, Id, MeltQuoteState, MintQuoteState, Proof, Proofs, PublicKey,
|
nut07, BlindSignature, CurrencyUnit, Id, MeltQuoteState, MintQuoteState, Proof, Proofs,
|
||||||
|
PublicKey,
|
||||||
};
|
};
|
||||||
use crate::secret::Secret;
|
|
||||||
|
|
||||||
/// Mint Memory Database
|
/// Mint Memory Database
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -21,8 +22,8 @@ pub struct MintMemoryDatabase {
|
|||||||
keysets: Arc<RwLock<HashMap<Id, MintKeySetInfo>>>,
|
keysets: Arc<RwLock<HashMap<Id, MintKeySetInfo>>>,
|
||||||
mint_quotes: Arc<RwLock<HashMap<String, MintQuote>>>,
|
mint_quotes: Arc<RwLock<HashMap<String, MintQuote>>>,
|
||||||
melt_quotes: Arc<RwLock<HashMap<String, mint::MeltQuote>>>,
|
melt_quotes: Arc<RwLock<HashMap<String, mint::MeltQuote>>>,
|
||||||
pending_proofs: Arc<RwLock<HashMap<[u8; 33], Proof>>>,
|
proofs: Arc<RwLock<HashMap<[u8; 33], Proof>>>,
|
||||||
spent_proofs: Arc<RwLock<HashMap<[u8; 33], Proof>>>,
|
proof_state: Arc<Mutex<HashMap<[u8; 33], nut07::State>>>,
|
||||||
blinded_signatures: Arc<RwLock<HashMap<[u8; 33], BlindSignature>>>,
|
blinded_signatures: Arc<RwLock<HashMap<[u8; 33], BlindSignature>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +39,21 @@ impl MintMemoryDatabase {
|
|||||||
spent_proofs: Proofs,
|
spent_proofs: Proofs,
|
||||||
blinded_signatures: HashMap<[u8; 33], BlindSignature>,
|
blinded_signatures: HashMap<[u8; 33], BlindSignature>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
|
let mut proofs = HashMap::new();
|
||||||
|
let mut proof_states = HashMap::new();
|
||||||
|
|
||||||
|
for proof in pending_proofs {
|
||||||
|
let y = hash_to_curve(&proof.secret.to_bytes())?.to_bytes();
|
||||||
|
proofs.insert(y, proof);
|
||||||
|
proof_states.insert(y, State::Pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
for proof in spent_proofs {
|
||||||
|
let y = hash_to_curve(&proof.secret.to_bytes())?.to_bytes();
|
||||||
|
proofs.insert(y, proof);
|
||||||
|
proof_states.insert(y, State::Spent);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
active_keysets: Arc::new(RwLock::new(active_keysets)),
|
active_keysets: Arc::new(RwLock::new(active_keysets)),
|
||||||
keysets: Arc::new(RwLock::new(
|
keysets: Arc::new(RwLock::new(
|
||||||
@@ -49,18 +65,8 @@ impl MintMemoryDatabase {
|
|||||||
melt_quotes: Arc::new(RwLock::new(
|
melt_quotes: Arc::new(RwLock::new(
|
||||||
melt_quotes.into_iter().map(|q| (q.id.clone(), q)).collect(),
|
melt_quotes.into_iter().map(|q| (q.id.clone(), q)).collect(),
|
||||||
)),
|
)),
|
||||||
pending_proofs: Arc::new(RwLock::new(
|
proofs: Arc::new(RwLock::new(proofs)),
|
||||||
pending_proofs
|
proof_state: Arc::new(Mutex::new(proof_states)),
|
||||||
.into_iter()
|
|
||||||
.map(|p| (hash_to_curve(&p.secret.to_bytes()).unwrap().to_bytes(), p))
|
|
||||||
.collect(),
|
|
||||||
)),
|
|
||||||
spent_proofs: Arc::new(RwLock::new(
|
|
||||||
spent_proofs
|
|
||||||
.into_iter()
|
|
||||||
.map(|p| (hash_to_curve(&p.secret.to_bytes()).unwrap().to_bytes(), p))
|
|
||||||
.collect(),
|
|
||||||
)),
|
|
||||||
blinded_signatures: Arc::new(RwLock::new(blinded_signatures)),
|
blinded_signatures: Arc::new(RwLock::new(blinded_signatures)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -213,21 +219,18 @@ impl MintDatabase for MintMemoryDatabase {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_spent_proofs(&self, spent_proofs: Proofs) -> Result<(), Self::Err> {
|
async fn add_proofs(&self, proofs: Proofs) -> Result<(), Self::Err> {
|
||||||
let mut proofs = self.spent_proofs.write().await;
|
let mut db_proofs = self.proofs.write().await;
|
||||||
|
|
||||||
for proof in spent_proofs {
|
for proof in proofs {
|
||||||
let secret_point = hash_to_curve(&proof.secret.to_bytes())?;
|
let secret_point = hash_to_curve(&proof.secret.to_bytes())?;
|
||||||
proofs.insert(secret_point.to_bytes(), proof);
|
db_proofs.insert(secret_point.to_bytes(), proof);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_spent_proofs_by_ys(
|
async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result<Vec<Option<Proof>>, Self::Err> {
|
||||||
&self,
|
let spent_proofs = self.proofs.read().await;
|
||||||
ys: &[PublicKey],
|
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err> {
|
|
||||||
let spent_proofs = self.spent_proofs.read().await;
|
|
||||||
|
|
||||||
let mut proofs = Vec::with_capacity(ys.len());
|
let mut proofs = Vec::with_capacity(ys.len());
|
||||||
|
|
||||||
@@ -240,41 +243,34 @@ impl MintDatabase for MintMemoryDatabase {
|
|||||||
Ok(proofs)
|
Ok(proofs)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_pending_proofs(&self, pending_proofs: Proofs) -> Result<(), Self::Err> {
|
async fn update_proofs_states(
|
||||||
let mut proofs = self.pending_proofs.write().await;
|
|
||||||
|
|
||||||
for proof in pending_proofs {
|
|
||||||
proofs.insert(hash_to_curve(&proof.secret.to_bytes())?.to_bytes(), proof);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_pending_proofs_by_ys(
|
|
||||||
&self,
|
&self,
|
||||||
ys: &[PublicKey],
|
ys: &[PublicKey],
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err> {
|
proof_state: State,
|
||||||
let spent_proofs = self.pending_proofs.read().await;
|
) -> Result<Vec<Option<State>>, Self::Err> {
|
||||||
|
let mut proofs_states = self.proof_state.lock().await;
|
||||||
|
|
||||||
let mut proofs = Vec::with_capacity(ys.len());
|
let mut states = Vec::new();
|
||||||
|
|
||||||
for y in ys {
|
for y in ys {
|
||||||
let proof = spent_proofs.get(&y.to_bytes()).cloned();
|
let state = proofs_states.insert(y.to_bytes(), proof_state);
|
||||||
|
states.push(state);
|
||||||
proofs.push(proof);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(proofs)
|
Ok(states)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn remove_pending_proofs(&self, secrets: Vec<&Secret>) -> Result<(), Self::Err> {
|
async fn get_proofs_states(&self, ys: &[PublicKey]) -> Result<Vec<Option<State>>, Self::Err> {
|
||||||
let mut proofs = self.pending_proofs.write().await;
|
let proofs_states = self.proof_state.lock().await;
|
||||||
|
|
||||||
for secret in secrets {
|
let mut states = Vec::new();
|
||||||
let secret_point = hash_to_curve(&secret.to_bytes())?;
|
|
||||||
proofs.remove(&secret_point.to_bytes());
|
for y in ys {
|
||||||
|
let state = proofs_states.get(&y.to_bytes()).cloned();
|
||||||
|
states.push(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(states)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_blind_signatures(
|
async fn add_blind_signatures(
|
||||||
|
|||||||
@@ -14,16 +14,12 @@ use crate::mint;
|
|||||||
use crate::mint::MintKeySetInfo;
|
use crate::mint::MintKeySetInfo;
|
||||||
#[cfg(feature = "mint")]
|
#[cfg(feature = "mint")]
|
||||||
use crate::mint::MintQuote as MintMintQuote;
|
use crate::mint::MintQuote as MintMintQuote;
|
||||||
#[cfg(feature = "wallet")]
|
|
||||||
use crate::nuts::State;
|
|
||||||
#[cfg(feature = "mint")]
|
#[cfg(feature = "mint")]
|
||||||
use crate::nuts::{BlindSignature, MeltQuoteState, MintQuoteState, Proof};
|
use crate::nuts::{BlindSignature, MeltQuoteState, MintQuoteState, Proof};
|
||||||
#[cfg(any(feature = "wallet", feature = "mint"))]
|
#[cfg(any(feature = "wallet", feature = "mint"))]
|
||||||
use crate::nuts::{CurrencyUnit, Id, Proofs, PublicKey};
|
use crate::nuts::{CurrencyUnit, Id, Proofs, PublicKey, State};
|
||||||
#[cfg(feature = "wallet")]
|
#[cfg(feature = "wallet")]
|
||||||
use crate::nuts::{KeySetInfo, Keys, MintInfo, SpendingConditions};
|
use crate::nuts::{KeySetInfo, Keys, MintInfo, SpendingConditions};
|
||||||
#[cfg(feature = "mint")]
|
|
||||||
use crate::secret::Secret;
|
|
||||||
#[cfg(feature = "wallet")]
|
#[cfg(feature = "wallet")]
|
||||||
use crate::types::ProofInfo;
|
use crate::types::ProofInfo;
|
||||||
#[cfg(feature = "wallet")]
|
#[cfg(feature = "wallet")]
|
||||||
@@ -218,22 +214,17 @@ pub trait MintDatabase {
|
|||||||
async fn get_keyset_infos(&self) -> Result<Vec<MintKeySetInfo>, Self::Err>;
|
async fn get_keyset_infos(&self) -> Result<Vec<MintKeySetInfo>, Self::Err>;
|
||||||
|
|
||||||
/// Add spent [`Proofs`]
|
/// Add spent [`Proofs`]
|
||||||
async fn add_spent_proofs(&self, proof: Proofs) -> Result<(), Self::Err>;
|
async fn add_proofs(&self, proof: Proofs) -> Result<(), Self::Err>;
|
||||||
/// Get spent [`Proofs`] by ys
|
/// Get [`Proofs`] by ys
|
||||||
async fn get_spent_proofs_by_ys(
|
async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result<Vec<Option<Proof>>, Self::Err>;
|
||||||
&self,
|
/// Get [`Proofs`] state
|
||||||
y: &[PublicKey],
|
async fn get_proofs_states(&self, ys: &[PublicKey]) -> Result<Vec<Option<State>>, Self::Err>;
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err>;
|
/// Get [`Proofs`] state
|
||||||
|
async fn update_proofs_states(
|
||||||
/// Add pending [`Proofs`]
|
|
||||||
async fn add_pending_proofs(&self, proof: Proofs) -> Result<(), Self::Err>;
|
|
||||||
/// Get pending [`Proofs`] by ys
|
|
||||||
async fn get_pending_proofs_by_ys(
|
|
||||||
&self,
|
&self,
|
||||||
ys: &[PublicKey],
|
ys: &[PublicKey],
|
||||||
) -> Result<Vec<Option<Proof>>, Self::Err>;
|
proofs_state: State,
|
||||||
/// Remove pending [`Proofs`]
|
) -> Result<Vec<Option<State>>, Self::Err>;
|
||||||
async fn remove_pending_proofs(&self, secret: Vec<&Secret>) -> Result<(), Self::Err>;
|
|
||||||
|
|
||||||
/// Add [`BlindSignature`]
|
/// Add [`BlindSignature`]
|
||||||
async fn add_blind_signatures(
|
async fn add_blind_signatures(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#![warn(rustdoc::bare_urls)]
|
#![warn(rustdoc::bare_urls)]
|
||||||
|
|
||||||
pub mod amount;
|
pub mod amount;
|
||||||
|
#[cfg(any(feature = "wallet", feature = "mint"))]
|
||||||
pub mod cdk_database;
|
pub mod cdk_database;
|
||||||
#[cfg(feature = "mint")]
|
#[cfg(feature = "mint")]
|
||||||
pub mod cdk_lightning;
|
pub mod cdk_lightning;
|
||||||
|
|||||||
@@ -614,16 +614,19 @@ impl Mint {
|
|||||||
|
|
||||||
let proof_count = swap_request.inputs.len();
|
let proof_count = swap_request.inputs.len();
|
||||||
|
|
||||||
let ys: Vec<PublicKey> = swap_request
|
let input_ys: Vec<PublicKey> = swap_request
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|p| hash_to_curve(&p.secret.to_bytes()))
|
.flat_map(|p| hash_to_curve(&p.secret.to_bytes()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.check_ys_unspent(&ys).await?;
|
self.localstore
|
||||||
|
.add_proofs(swap_request.inputs.clone())
|
||||||
|
.await?;
|
||||||
|
self.check_ys_spendable(&input_ys, State::Pending).await?;
|
||||||
|
|
||||||
// Check that there are no duplicate proofs in request
|
// Check that there are no duplicate proofs in request
|
||||||
if ys
|
if input_ys
|
||||||
.iter()
|
.iter()
|
||||||
.collect::<HashSet<&PublicKey>>()
|
.collect::<HashSet<&PublicKey>>()
|
||||||
.len()
|
.len()
|
||||||
@@ -684,10 +687,6 @@ impl Mint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.localstore
|
|
||||||
.add_spent_proofs(swap_request.inputs)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut promises = Vec::with_capacity(swap_request.outputs.len());
|
let mut promises = Vec::with_capacity(swap_request.outputs.len());
|
||||||
|
|
||||||
for blinded_message in swap_request.outputs.iter() {
|
for blinded_message in swap_request.outputs.iter() {
|
||||||
@@ -695,6 +694,10 @@ impl Mint {
|
|||||||
promises.push(blinded_signature);
|
promises.push(blinded_signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.localstore
|
||||||
|
.update_proofs_states(&input_ys, State::Spent)
|
||||||
|
.await?;
|
||||||
|
|
||||||
self.localstore
|
self.localstore
|
||||||
.add_blind_signatures(
|
.add_blind_signatures(
|
||||||
&swap_request
|
&swap_request
|
||||||
@@ -749,31 +752,17 @@ impl Mint {
|
|||||||
&self,
|
&self,
|
||||||
check_state: &CheckStateRequest,
|
check_state: &CheckStateRequest,
|
||||||
) -> Result<CheckStateResponse, Error> {
|
) -> Result<CheckStateResponse, Error> {
|
||||||
let spent_proofs = self
|
let states = self.localstore.get_proofs_states(&check_state.ys).await?;
|
||||||
.localstore
|
|
||||||
.get_spent_proofs_by_ys(&check_state.ys)
|
|
||||||
.await?;
|
|
||||||
let pending_proofs = self
|
|
||||||
.localstore
|
|
||||||
.get_pending_proofs_by_ys(&check_state.ys)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let states = spent_proofs
|
let states = states
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&pending_proofs)
|
|
||||||
.zip(&check_state.ys)
|
.zip(&check_state.ys)
|
||||||
.map(|((spent, pending), y)| {
|
.map(|(state, y)| {
|
||||||
let state = match (spent, pending) {
|
let state = match state {
|
||||||
(None, None) => State::Unspent,
|
Some(state) => *state,
|
||||||
(Some(_), None) => State::Spent,
|
None => State::Unspent,
|
||||||
(None, Some(_)) => State::Pending,
|
|
||||||
(Some(_), Some(_)) => {
|
|
||||||
tracing::error!(
|
|
||||||
"Proof should not be both pending and spent. Assuming Spent"
|
|
||||||
);
|
|
||||||
State::Spent
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ProofState {
|
ProofState {
|
||||||
y: *y,
|
y: *y,
|
||||||
state,
|
state,
|
||||||
@@ -787,28 +776,23 @@ impl Mint {
|
|||||||
|
|
||||||
/// Check Tokens are not spent or pending
|
/// Check Tokens are not spent or pending
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub async fn check_ys_unspent(&self, ys: &[PublicKey]) -> Result<(), Error> {
|
pub async fn check_ys_spendable(
|
||||||
let pending_proofs: Proofs = self
|
&self,
|
||||||
|
ys: &[PublicKey],
|
||||||
|
proof_state: State,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let proofs_state = self
|
||||||
.localstore
|
.localstore
|
||||||
.get_pending_proofs_by_ys(ys)
|
.update_proofs_states(ys, proof_state)
|
||||||
.await?
|
.await?;
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if !pending_proofs.is_empty() {
|
let proofs_state = proofs_state.iter().flatten().collect::<HashSet<&State>>();
|
||||||
|
|
||||||
|
if proofs_state.contains(&State::Pending) {
|
||||||
return Err(Error::TokenPending);
|
return Err(Error::TokenPending);
|
||||||
}
|
}
|
||||||
|
|
||||||
let spent_proofs: Proofs = self
|
if proofs_state.contains(&State::Spent) {
|
||||||
.localstore
|
|
||||||
.get_spent_proofs_by_ys(ys)
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if !spent_proofs.is_empty() {
|
|
||||||
return Err(Error::TokenAlreadySpent);
|
return Err(Error::TokenAlreadySpent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +816,10 @@ impl Mint {
|
|||||||
return Err(Error::DuplicateProofs);
|
return Err(Error::DuplicateProofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_ys_unspent(&ys).await?;
|
self.localstore
|
||||||
|
.add_proofs(melt_request.inputs.clone())
|
||||||
|
.await?;
|
||||||
|
self.check_ys_spendable(&ys, State::Pending).await?;
|
||||||
|
|
||||||
for proof in &melt_request.inputs {
|
for proof in &melt_request.inputs {
|
||||||
self.verify_proof(proof).await?;
|
self.verify_proof(proof).await?;
|
||||||
@@ -929,11 +916,6 @@ impl Mint {
|
|||||||
return Err(Error::MultipleUnits);
|
return Err(Error::MultipleUnits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add proofs to pending
|
|
||||||
self.localstore
|
|
||||||
.add_pending_proofs(melt_request.inputs.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
tracing::debug!("Verified melt quote: {}", melt_request.quote);
|
tracing::debug!("Verified melt quote: {}", melt_request.quote);
|
||||||
Ok(quote)
|
Ok(quote)
|
||||||
}
|
}
|
||||||
@@ -943,8 +925,14 @@ impl Mint {
|
|||||||
/// The [`Proofs`] should be returned to an unspent state and the quote should be unpaid
|
/// The [`Proofs`] should be returned to an unspent state and the quote should be unpaid
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub async fn process_unpaid_melt(&self, melt_request: &MeltBolt11Request) -> Result<(), Error> {
|
pub async fn process_unpaid_melt(&self, melt_request: &MeltBolt11Request) -> Result<(), Error> {
|
||||||
|
let input_ys: Vec<PublicKey> = melt_request
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.flat_map(|p| hash_to_curve(&p.secret.to_bytes()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
self.localstore
|
self.localstore
|
||||||
.remove_pending_proofs(melt_request.inputs.iter().map(|p| &p.secret).collect())
|
.update_proofs_states(&input_ys, State::Unspent)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.localstore
|
self.localstore
|
||||||
@@ -987,10 +975,6 @@ impl Mint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.localstore
|
|
||||||
.add_spent_proofs(melt_request.inputs.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut change = None;
|
let mut change = None;
|
||||||
|
|
||||||
if let Some(outputs) = melt_request.outputs.clone() {
|
if let Some(outputs) = melt_request.outputs.clone() {
|
||||||
@@ -1038,8 +1022,14 @@ impl Mint {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let input_ys: Vec<PublicKey> = melt_request
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.flat_map(|p| hash_to_curve(&p.secret.to_bytes()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
self.localstore
|
self.localstore
|
||||||
.remove_pending_proofs(melt_request.inputs.iter().map(|p| &p.secret).collect())
|
.update_proofs_states(&input_ys, State::Spent)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.localstore
|
self.localstore
|
||||||
|
|||||||
Reference in New Issue
Block a user