refactor: store keyset by id

This commit is contained in:
thesimplekid
2024-06-02 19:26:15 +01:00
parent 1ab1f47885
commit efd9b39722
5 changed files with 180 additions and 44 deletions

View File

@@ -17,12 +17,15 @@ use tracing::instrument;
use super::error::Error;
const MINTS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mints_table");
const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &str> =
// <Mint_Url, Keyset_id>
const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &[u8]> =
MultimapTableDefinition::new("mint_keysets");
// <Keyset_id, KeysetInfo>
const KEYSETS_TABLE: TableDefinition<&[u8], &str> = TableDefinition::new("keysets");
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");
// <Y, (Proof, Status, Mint url)>
// <Y, Proof Info>
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");
@@ -62,6 +65,7 @@ impl RedbWalletDatabase {
// Open all tables to init a new db
let _ = write_txn.open_table(MINTS_TABLE)?;
let _ = write_txn.open_multimap_table(MINT_KEYSETS_TABLE)?;
let _ = write_txn.open_table(KEYSETS_TABLE)?;
let _ = write_txn.open_table(MINT_QUOTES_TABLE)?;
let _ = write_txn.open_table(MELT_QUOTES_TABLE)?;
let _ = write_txn.open_table(MINT_KEYS_TABLE)?;
@@ -166,9 +170,7 @@ impl WalletDatabase for RedbWalletDatabase {
table
.insert(
mint_url.to_string().as_str(),
serde_json::to_string(&keyset)
.map_err(Error::from)?
.as_str(),
keyset.id.to_bytes().as_slice(),
)
.map_err(Error::from)?;
}
@@ -189,14 +191,52 @@ impl WalletDatabase for RedbWalletDatabase {
.open_multimap_table(MINT_KEYSETS_TABLE)
.map_err(Error::from)?;
let keysets = table
let keyset_ids: Vec<Id> = table
.get(mint_url.to_string().as_str())
.map_err(Error::from)?
.flatten()
.flat_map(|k| serde_json::from_str(k.value()))
.flat_map(|k| Id::from_bytes(k.value()))
.collect();
Ok(keysets)
let mut keysets = vec![];
let keysets_t = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
for keyset_id in keyset_ids {
if let Some(keyset) = keysets_t
.get(keyset_id.to_bytes().as_slice())
.map_err(Error::from)?
{
let keyset = serde_json::from_str(keyset.value()).map_err(Error::from)?;
keysets.push(keyset);
}
}
match keysets.is_empty() {
true => Ok(None),
false => Ok(Some(keysets)),
}
}
#[instrument(skip(self))]
async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Self::Err> {
let db = self.db.lock().await;
let read_txn = db.begin_read().map_err(Into::<Error>::into)?;
let table = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
match table
.get(keyset_id.to_bytes().as_slice())
.map_err(Error::from)?
{
Some(keyset) => {
let keyset: KeySetInfo =
serde_json::from_str(keyset.value()).map_err(Error::from)?;
Ok(Some(keyset))
}
None => Ok(None),
}
}
#[instrument(skip_all)]

View File

@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::result::Result;
@@ -15,7 +15,8 @@ use tokio::sync::Mutex;
// Tables
const MINTS: &str = "mints";
const MINT_KEYSETS: &str = "mint_keysets";
const MINT_KEYSETS: &str = "keysets_by_mint";
const KEYSETS: &str = "keysets";
const MINT_KEYS: &str = "mint_keys";
const MINT_QUOTES: &str = "mint_quotes";
const MELT_QUOTES: &str = "melt_quotes";
@@ -23,7 +24,7 @@ const PROOFS: &str = "proofs";
const CONFIG: &str = "config";
const KEYSET_COUNTER: &str = "keyset_counter";
const DATABASE_VERSION: u32 = 1;
const DATABASE_VERSION: u32 = 2;
#[derive(Debug, Error)]
pub enum Error {
@@ -61,15 +62,20 @@ unsafe impl Sync for RexieWalletDatabase {}
impl RexieWalletDatabase {
pub async fn new() -> Result<Self, Error> {
let rexie = Rexie::builder("cdk")
// Set the version of the database to 1.0
.version(DATABASE_VERSION)
// Add an object store named `employees`
.add_object_store(ObjectStore::new(PROOFS).add_index(Index::new("y", "y").unique(true)))
.add_object_store(
ObjectStore::new(PROOFS)
.add_index(Index::new("y", "y").unique(true))
.add_index(Index::new("mint_url", "mint_url"))
.add_index(Index::new("state", "state"))
.add_index(Index::new("unit", "unit")),
)
.add_object_store(
ObjectStore::new(MINTS).add_index(Index::new("mint_url", "mint_url").unique(true)),
)
.add_object_store(ObjectStore::new(MINT_KEYSETS))
.add_object_store(
ObjectStore::new(MINT_KEYSETS)
ObjectStore::new(KEYSETS)
.add_index(Index::new("keyset_id", "keyset_id").unique(true)),
)
.add_object_store(
@@ -175,19 +181,46 @@ impl WalletDatabase for RexieWalletDatabase {
let rexie = self.db.lock().await;
let transaction = rexie
.transaction(&[MINT_KEYSETS], TransactionMode::ReadWrite)
.transaction(&[MINT_KEYSETS, KEYSETS], TransactionMode::ReadWrite)
.map_err(Error::from)?;
let keysets_store = transaction.store(MINT_KEYSETS).map_err(Error::from)?;
let mint_keysets_store = transaction.store(MINT_KEYSETS).map_err(Error::from)?;
let keysets_store = transaction.store(KEYSETS).map_err(Error::from)?;
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
let keysets = serde_wasm_bindgen::to_value(&keysets).map_err(Error::from)?;
keysets_store
.put(&keysets, Some(&mint_url))
let mint_keysets = mint_keysets_store
.get(&mint_url)
.await
.map_err(Error::from)?;
let mut mint_keysets: Option<HashSet<Id>> =
serde_wasm_bindgen::from_value(mint_keysets).map_err(Error::from)?;
let new_keyset_ids: Vec<Id> = keysets.iter().map(|k| k.id).collect();
mint_keysets
.as_mut()
.unwrap_or(&mut HashSet::new())
.extend(new_keyset_ids);
let mint_keysets = serde_wasm_bindgen::to_value(&mint_keysets).map_err(Error::from)?;
mint_keysets_store
.put(&mint_keysets, Some(&mint_url))
.await
.map_err(Error::from)?;
for keyset in keysets {
let id = serde_wasm_bindgen::to_value(&keyset.id).map_err(Error::from)?;
let keyset = serde_wasm_bindgen::to_value(&keyset).map_err(Error::from)?;
keysets_store
.put(&keyset, Some(&id))
.await
.map_err(Error::from)?;
}
transaction.done().await.map_err(Error::from)?;
Ok(())
@@ -200,20 +233,58 @@ impl WalletDatabase for RexieWalletDatabase {
let rexie = self.db.lock().await;
let transaction = rexie
.transaction(&[MINT_KEYSETS], TransactionMode::ReadOnly)
.transaction(&[MINT_KEYSETS, KEYSETS], TransactionMode::ReadOnly)
.map_err(Error::from)?;
let mints_store = transaction.store(MINT_KEYSETS).map_err(Error::from)?;
let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
let keysets = mints_store.get(&mint_url).await.map_err(Error::from)?;
let mint_keysets = mints_store.get(&mint_url).await.map_err(Error::from)?;
let keysets: Option<Vec<KeySetInfo>> =
serde_wasm_bindgen::from_value(keysets).map_err(Error::from)?;
let mint_keysets: Option<HashSet<Id>> =
serde_wasm_bindgen::from_value(mint_keysets).map_err(Error::from)?;
let keysets_store = transaction.store(KEYSETS).map_err(Error::from)?;
let keysets = match mint_keysets {
Some(mint_keysets) => {
let mut keysets = vec![];
for mint_keyset in mint_keysets {
let id = serde_wasm_bindgen::to_value(&mint_keyset).map_err(Error::from)?;
let keyset = keysets_store.get(&id).await.map_err(Error::from)?;
let keyset = serde_wasm_bindgen::from_value(keyset).map_err(Error::from)?;
keysets.push(keyset);
}
Some(keysets)
}
None => None,
};
transaction.done().await.map_err(Error::from)?;
Ok(keysets)
}
async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Self::Err> {
let rexie = self.db.lock().await;
let transaction = rexie
.transaction(&[KEYSETS], TransactionMode::ReadOnly)
.map_err(Error::from)?;
let keysets_store = transaction.store(KEYSETS).map_err(Error::from)?;
let keyset_id = serde_wasm_bindgen::to_value(keyset_id).map_err(Error::from)?;
let keyset = keysets_store.get(&keyset_id).await.map_err(Error::from)?;
Ok(serde_wasm_bindgen::from_value(keyset).map_err(Error::from)?)
}
async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err> {
let rexie = self.db.lock().await;

View File

@@ -64,6 +64,8 @@ pub trait WalletDatabase {
&self,
mint_url: UncheckedUrl,
) -> Result<Option<Vec<KeySetInfo>>, Self::Err>;
async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Self::Err>;
async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err>;
async fn get_mint_quote(&self, quote_id: &str) -> Result<Option<MintQuote>, Self::Err>;
async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err>;

View File

@@ -18,7 +18,8 @@ use crate::url::UncheckedUrl;
#[derive(Default, Debug, Clone)]
pub struct WalletMemoryDatabase {
mints: Arc<RwLock<HashMap<UncheckedUrl, Option<MintInfo>>>>,
mint_keysets: Arc<RwLock<HashMap<UncheckedUrl, HashSet<KeySetInfo>>>>,
mint_keysets: Arc<RwLock<HashMap<UncheckedUrl, HashSet<Id>>>>,
keysets: Arc<RwLock<HashMap<Id, KeySetInfo>>>,
mint_quotes: Arc<RwLock<HashMap<String, MintQuote>>>,
melt_quotes: Arc<RwLock<HashMap<String, MeltQuote>>>,
mint_keys: Arc<RwLock<HashMap<Id, Keys>>>,
@@ -39,6 +40,7 @@ impl WalletMemoryDatabase {
Self {
mints: Arc::new(RwLock::new(HashMap::new())),
mint_keysets: Arc::new(RwLock::new(HashMap::new())),
keysets: Arc::new(RwLock::new(HashMap::new())),
mint_quotes: Arc::new(RwLock::new(
mint_quotes.into_iter().map(|q| (q.id.clone(), q)).collect(),
)),
@@ -83,10 +85,19 @@ impl WalletDatabase for WalletMemoryDatabase {
mint_url: UncheckedUrl,
keysets: Vec<KeySetInfo>,
) -> Result<(), Error> {
let mut current_keysets = self.mint_keysets.write().await;
let mut current_mint_keysets = self.mint_keysets.write().await;
let mut current_keysets = self.keysets.write().await;
let mint_keysets = current_keysets.entry(mint_url).or_insert(HashSet::new());
mint_keysets.extend(keysets);
for keyset in keysets {
current_mint_keysets
.entry(mint_url.clone())
.and_modify(|ks| {
ks.insert(keyset.id);
})
.or_insert(HashSet::from_iter(vec![keyset.id]));
current_keysets.insert(keyset.id, keyset);
}
Ok(())
}
@@ -95,12 +106,26 @@ impl WalletDatabase for WalletMemoryDatabase {
&self,
mint_url: UncheckedUrl,
) -> Result<Option<Vec<KeySetInfo>>, Error> {
Ok(self
.mint_keysets
.read()
.await
.get(&mint_url)
.map(|ks| ks.iter().cloned().collect()))
match self.mint_keysets.read().await.get(&mint_url) {
Some(keyset_ids) => {
let mut keysets = vec![];
let db_keysets = self.keysets.read().await;
for id in keyset_ids {
if let Some(keyset) = db_keysets.get(id) {
keysets.push(keyset.clone());
}
}
Ok(Some(keysets))
}
None => Ok(None),
}
}
async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Error> {
Ok(self.keysets.read().await.get(keyset_id).cloned())
}
async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Error> {

View File

@@ -694,14 +694,13 @@ impl Wallet {
.post_swap(mint_url.clone().try_into()?, pre_swap.swap_request)
.await?;
let active_keys = self.active_keys(mint_url, unit).await?.unwrap();
let mut post_swap_proofs = construct_proofs(
swap_response.signatures,
pre_swap.pre_mint_secrets.rs(),
pre_swap.pre_mint_secrets.secrets(),
&self
.active_keys(mint_url, unit)
.await?
.ok_or(Error::UnknownKey)?,
&active_keys,
)?;
let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?;
@@ -793,7 +792,7 @@ impl Wallet {
proofs: Proofs,
spending_conditions: Option<SpendingConditions>,
) -> Result<PreSwap, Error> {
let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?;
let active_keyset_id = self.active_mint_keyset(mint_url, unit).await.unwrap();
// Desired amount is either amount passwed or value of all proof
let proofs_total = proofs.iter().map(|p| p.amount).sum();
@@ -1047,11 +1046,10 @@ impl Wallet {
.collect();
}
let mint_keysets = self
.localstore
.get_mint_keysets(mint_url.clone())
.await?
.ok_or(Error::UnknownKey)?;
let mint_keysets = match self.localstore.get_mint_keysets(mint_url.clone()).await? {
Some(keysets) => keysets,
None => self.get_mint_keysets(&mint_url).await?,
};
let (active, inactive): (HashSet<KeySetInfo>, HashSet<KeySetInfo>) = mint_keysets
.into_iter()