Skip to content

Commit

Permalink
feat(mint): issued and redeamed by keyset
Browse files Browse the repository at this point in the history
  • Loading branch information
thesimplekid committed Jul 25, 2024
1 parent 53c75a4 commit ba19663
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 12 deletions.
28 changes: 26 additions & 2 deletions crates/cdk-redb/src/mint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,30 @@ impl MintDatabase for MintRedbDatabase {
Ok(states)
}

async fn get_proofs_by_keyset_id(
&self,
keyset_id: &Id,
) -> Result<(Proofs, Vec<Option<State>>), 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 proofs_for_id: Proofs = table
.iter()
.map_err(Error::from)?
.flatten()
.flat_map(|(_, p)| serde_json::from_str::<Proof>(p.value()))
.filter(|p| &p.keyset_id == keyset_id)
.collect();

let proof_ys: Vec<PublicKey> = proofs_for_id.iter().flat_map(|p| p.y()).collect();
assert_eq!(proofs_for_id.len(), proof_ys.len());

let states = self.get_proofs_states(&proof_ys).await?;

Ok((proofs_for_id, states))
}

async fn update_proofs_states(
&self,
ys: &[PublicKey],
Expand Down Expand Up @@ -647,7 +671,7 @@ impl MintDatabase for MintRedbDatabase {
Ok(())
}

async fn get_blinded_signatures(
async fn get_blind_signatures(
&self,
blinded_messages: &[PublicKey],
) -> Result<Vec<Option<BlindSignature>>, Self::Err> {
Expand All @@ -671,7 +695,7 @@ impl MintDatabase for MintRedbDatabase {
Ok(signatures)
}

async fn get_blinded_signatures_for_keyset(
async fn get_blind_signatures_for_keyset(
&self,
keyset_id: &Id,
) -> Result<Vec<BlindSignature>, Self::Err> {
Expand Down
57 changes: 55 additions & 2 deletions crates/cdk-sqlite/src/mint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,35 @@ WHERE y=?;
Ok(states)
}

async fn get_proofs_by_keyset_id(
&self,
keyset_id: &Id,
) -> Result<(Proofs, Vec<Option<State>>), Self::Err> {
let rec = sqlx::query(
r#"
SELECT *
FROM proof
WHERE keyset_id=?;
"#,
)
.bind(keyset_id.to_string())
.fetch_all(&self.pool)
.await
.map_err(Error::from)?;

let mut proofs_for_id = vec![];
let mut states = vec![];

for row in rec {
let (proof, state) = sqlite_row_to_proof_with_state(row)?;

proofs_for_id.push(proof);
states.push(state);
}

Ok((proofs_for_id, states))
}

async fn update_proofs_states(
&self,
ys: &[PublicKey],
Expand Down Expand Up @@ -657,7 +686,7 @@ VALUES (?, ?, ?, ?);

Ok(())
}
async fn get_blinded_signatures(
async fn get_blind_signatures(
&self,
blinded_messages: &[PublicKey],
) -> Result<Vec<Option<BlindSignature>>, Self::Err> {
Expand Down Expand Up @@ -686,7 +715,7 @@ WHERE y=?;
Ok(signatures)
}

async fn get_blinded_signatures_for_keyset(
async fn get_blind_signatures_for_keyset(
&self,
keyset_id: &Id,
) -> Result<Vec<BlindSignature>, Self::Err> {
Expand Down Expand Up @@ -811,6 +840,30 @@ fn sqlite_row_to_proof(row: SqliteRow) -> Result<Proof, Error> {
})
}

fn sqlite_row_to_proof_with_state(row: SqliteRow) -> Result<(Proof, Option<State>), Error> {
let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
let keyset_id: String = row.try_get("keyset_id").map_err(Error::from)?;
let row_secret: String = row.try_get("secret").map_err(Error::from)?;
let row_c: Vec<u8> = row.try_get("c").map_err(Error::from)?;
let row_witness: Option<String> = row.try_get("witness").map_err(Error::from)?;

let row_state: Option<String> = row.try_get("state").map_err(Error::from)?;

let state = row_state.and_then(|s| State::from_str(&s).ok());

Ok((
Proof {
amount: Amount::from(row_amount as u64),
keyset_id: Id::from_str(&keyset_id)?,
secret: Secret::from_str(&row_secret)?,
c: PublicKey::from_slice(&row_c)?,
witness: row_witness.and_then(|w| serde_json::from_str(&w).ok()),
dleq: None,
},
state,
))
}

fn sqlite_row_to_blind_signature(row: SqliteRow) -> Result<BlindSignature, Error> {
let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
let keyset_id: String = row.try_get("keyset_id").map_err(Error::from)?;
Expand Down
27 changes: 25 additions & 2 deletions crates/cdk/src/cdk_database/mint_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,29 @@ impl MintDatabase for MintMemoryDatabase {
Ok(states)
}

async fn get_proofs_by_keyset_id(
&self,
keyset_id: &Id,
) -> Result<(Proofs, Vec<Option<State>>), Self::Err> {
let proofs = self.proofs.read().await;

let proofs_for_id: Proofs = proofs
.iter()
.filter_map(|(_, p)| match &p.keyset_id == keyset_id {
true => Some(p),
false => None,
})
.cloned()
.collect();

let proof_ys: Vec<PublicKey> = proofs_for_id.iter().flat_map(|p| p.y()).collect();
assert_eq!(proofs_for_id.len(), proof_ys.len());

let states = self.get_proofs_states(&proof_ys).await?;

Ok((proofs_for_id, states))
}

async fn add_blind_signatures(
&self,
blinded_message: &[PublicKey],
Expand All @@ -287,7 +310,7 @@ impl MintDatabase for MintMemoryDatabase {
Ok(())
}

async fn get_blinded_signatures(
async fn get_blind_signatures(
&self,
blinded_messages: &[PublicKey],
) -> Result<Vec<Option<BlindSignature>>, Self::Err> {
Expand All @@ -304,7 +327,7 @@ impl MintDatabase for MintMemoryDatabase {
Ok(signatures)
}

async fn get_blinded_signatures_for_keyset(
async fn get_blind_signatures_for_keyset(
&self,
keyset_id: &Id,
) -> Result<Vec<BlindSignature>, Self::Err> {
Expand Down
9 changes: 7 additions & 2 deletions crates/cdk/src/cdk_database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ pub trait MintDatabase {
ys: &[PublicKey],
proofs_state: State,
) -> Result<Vec<Option<State>>, Self::Err>;
/// Get [`Proofs`] by state
async fn get_proofs_by_keyset_id(
&self,
keyset_id: &Id,
) -> Result<(Proofs, Vec<Option<State>>), Self::Err>;

/// Add [`BlindSignature`]
async fn add_blind_signatures(
Expand All @@ -233,12 +238,12 @@ pub trait MintDatabase {
blind_signatures: &[BlindSignature],
) -> Result<(), Self::Err>;
/// Get [`BlindSignature`]s
async fn get_blinded_signatures(
async fn get_blind_signatures(
&self,
blinded_messages: &[PublicKey],
) -> Result<Vec<Option<BlindSignature>>, Self::Err>;
/// Get [`BlindSignature`]s for keyset_id
async fn get_blinded_signatures_for_keyset(
async fn get_blind_signatures_for_keyset(
&self,
keyset_id: &Id,
) -> Result<Vec<BlindSignature>, Self::Err>;
Expand Down
54 changes: 50 additions & 4 deletions crates/cdk/src/mint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ impl Mint {

if self
.localstore
.get_blinded_signatures(&blinded_messages)
.get_blind_signatures(&blinded_messages)
.await?
.iter()
.flatten()
Expand Down Expand Up @@ -600,7 +600,7 @@ impl Mint {

if self
.localstore
.get_blinded_signatures(&blinded_messages)
.get_blind_signatures(&blinded_messages)
.await?
.iter()
.flatten()
Expand Down Expand Up @@ -984,7 +984,7 @@ impl Mint {

if self
.localstore
.get_blinded_signatures(&blinded_messages)
.get_blind_signatures(&blinded_messages)
.await?
.iter()
.flatten()
Expand Down Expand Up @@ -1083,7 +1083,7 @@ impl Mint {

let blinded_signatures = self
.localstore
.get_blinded_signatures(&blinded_message)
.get_blind_signatures(&blinded_message)
.await?;

assert_eq!(blinded_signatures.len(), output_len);
Expand Down Expand Up @@ -1128,6 +1128,52 @@ impl Mint {
pub fn generate_keyset(&self, keyset_info: MintKeySetInfo) -> MintKeySet {
MintKeySet::generate_from_xpriv(&self.secp_ctx, self.xpriv, keyset_info)
}

/// Get the total amount issed by keyset
#[instrument(skip_all)]
pub async fn total_issued(&self) -> Result<HashMap<Id, Amount>, Error> {
let keysets = self.localstore.get_keyset_infos().await?;

let mut total_issued = HashMap::new();

for keyset in keysets {
let blinded = self
.localstore
.get_blind_signatures_for_keyset(&keyset.id)
.await?;

let total = blinded.iter().map(|b| b.amount).sum();

total_issued.insert(keyset.id, total);
}

Ok(total_issued)
}

/// Total redeamed for keyset
#[instrument(skip_all)]
pub async fn total_redeamed(&self) -> Result<HashMap<Id, Amount>, Error> {
let keysets = self.localstore.get_keyset_infos().await?;

let mut total_redeamed = HashMap::new();

for keyset in keysets {
let (proofs, state) = self.localstore.get_proofs_by_keyset_id(&keyset.id).await?;

let total_spent = proofs
.iter()
.zip(state)
.filter_map(|(p, s)| match s == Some(State::Spent) {
true => Some(p.amount),
false => None,
})
.sum();

total_redeamed.insert(keyset.id, total_spent);
}

Ok(total_redeamed)
}
}

/// Mint Fee Reserve
Expand Down

0 comments on commit ba19663

Please sign in to comment.