Skip to content

Commit

Permalink
feat(transfers): spent keys and created for others removed
Browse files Browse the repository at this point in the history
BREAKING_CHANGE: Updates wallet serialisation

This should top out the max size of the wallet files
  • Loading branch information
joshuef committed Dec 18, 2023
1 parent 06b47b7 commit 8fd5683
Show file tree
Hide file tree
Showing 4 changed files with 5 additions and 131 deletions.
66 changes: 0 additions & 66 deletions sn_transfers/src/wallet/local_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,6 @@ impl LocalWallet {
self.store_cash_notes_to_disk(&[cash_note])?;
}

for cash_note in &transfer.created_cash_notes {
self.watchonly_wallet
.insert_cash_note_created_for_others(cash_note.unique_pubkey());
}
// Store created CashNotes in a batch, improving IO performance
self.store_cash_notes_to_disk(&transfer.created_cash_notes)?;

Expand Down Expand Up @@ -513,11 +509,6 @@ mod tests {
.watchonly_wallet
.available_cash_notes()
.is_empty());
assert!(deposit_only
.watchonly_wallet
.cash_notes_created_for_others()
.is_empty());
assert!(deposit_only.watchonly_wallet.spent_cash_notes().is_empty());

Ok(())
}
Expand Down Expand Up @@ -546,11 +537,6 @@ mod tests {
.watchonly_wallet
.available_cash_notes()
.is_empty());
assert!(deposit_only
.watchonly_wallet
.cash_notes_created_for_others()
.is_empty());
assert!(deposit_only.watchonly_wallet.spent_cash_notes().is_empty());

Ok(())
}
Expand Down Expand Up @@ -641,27 +627,11 @@ mod tests {
assert_eq!(GENESIS_CASHNOTE_AMOUNT, deserialized.balance().as_nano());

assert_eq!(1, depositor.watchonly_wallet.available_cash_notes().len());
assert_eq!(
0,
depositor
.watchonly_wallet
.cash_notes_created_for_others()
.len()
);
assert_eq!(0, depositor.watchonly_wallet.spent_cash_notes().len());

assert_eq!(
1,
deserialized.watchonly_wallet.available_cash_notes().len()
);
assert_eq!(
0,
deserialized
.watchonly_wallet
.cash_notes_created_for_others()
.len()
);
assert_eq!(0, deserialized.watchonly_wallet.spent_cash_notes().len());

let a_available = depositor
.watchonly_wallet
Expand Down Expand Up @@ -746,27 +716,11 @@ mod tests {
);

assert_eq!(1, sender.watchonly_wallet.available_cash_notes().len());
assert_eq!(
1,
sender
.watchonly_wallet
.cash_notes_created_for_others()
.len()
);
assert_eq!(1, sender.watchonly_wallet.spent_cash_notes().len());

assert_eq!(
1,
deserialized.watchonly_wallet.available_cash_notes().len()
);
assert_eq!(
1,
deserialized
.watchonly_wallet
.cash_notes_created_for_others()
.len()
);
assert_eq!(1, deserialized.watchonly_wallet.spent_cash_notes().len());

let a_available = sender
.watchonly_wallet
Expand All @@ -782,26 +736,6 @@ mod tests {
.expect("There to be an available CashNote.");
assert_eq!(a_available, b_available);

let a_created_for_others = sender.watchonly_wallet.cash_notes_created_for_others();
let b_created_for_others = deserialized
.watchonly_wallet
.cash_notes_created_for_others();
assert_eq!(a_created_for_others, b_created_for_others);

let a_spent = sender
.watchonly_wallet
.spent_cash_notes()
.iter()
.last()
.expect("There to be a spent CashNote.");
let b_spent = deserialized
.watchonly_wallet
.spent_cash_notes()
.iter()
.last()
.expect("There to be a spent CashNote.");
assert_eq!(a_spent, b_spent);

Ok(())
}

Expand Down
19 changes: 3 additions & 16 deletions sn_transfers/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ mod wallet_file;
mod watch_only;

use data_payments::ContentPaymentsMap;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

pub use self::{
data_payments::{Payment, PaymentQuote},
Expand All @@ -71,34 +73,19 @@ pub use self::{
pub(crate) use keys::store_new_keypair;

use crate::{NanoTokens, UniquePubkey};
use std::collections::{BTreeMap, BTreeSet};

#[derive(Default, serde::Serialize, serde::Deserialize)]
/// This assumes the CashNotes are stored on disk
#[derive(Default, Serialize, Deserialize)]
pub(super) struct KeyLessWallet {
/// These are the UniquePubkeys of cash_notes we've owned, that have been
/// spent when sending tokens to other addresses.
spent_cash_notes: BTreeSet<UniquePubkey>,
/// These are the UniquePubkeys of cash_notes we own that are not yet spent.
available_cash_notes: BTreeMap<UniquePubkey, NanoTokens>,
/// These are the UniquePubkeys of cash_notes we've created by
/// sending tokens to other addresses.
/// They are not owned by us, but we
/// keep them here so we can track our
/// transfer history.
cash_notes_created_for_others: BTreeSet<UniquePubkey>,
/// Cached proofs of storage transactions made to be used for uploading the paid content.
payment_transactions: ContentPaymentsMap,
}

impl KeyLessWallet {
pub fn balance(&self) -> NanoTokens {
// loop through avaiable cash notes and get total token count
let mut balance = 0;
for (_unique_pubkey, value) in self.available_cash_notes.iter() {
balance += value.as_nano();
}

NanoTokens::from(balance)
}
}
2 changes: 1 addition & 1 deletion sn_transfers/src/wallet/wallet_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ where
// The create cash_notes dir within the wallet dir.
let created_cash_notes_path = wallet_dir.join(CASHNOTES_DIR_NAME);
for cash_note_key in cash_notes {
let unique_pubkey_name = *SpendAddress::from_unique_pubkey(&cash_note_key).xorname();
let unique_pubkey_name = *SpendAddress::from_unique_pubkey(cash_note_key).xorname();
let unique_pubkey_file_name = format!("{}.cash_note", hex::encode(unique_pubkey_name));

debug!("Removing cash note from: {:?}", created_cash_notes_path);
Expand Down
49 changes: 1 addition & 48 deletions sn_transfers/src/wallet/watch_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use super::{
use crate::{CashNote, MainPubkey, NanoTokens, UniquePubkey};
use fs2::FileExt;
use std::{
collections::{BTreeMap, BTreeSet},
collections::BTreeMap,
fs::OpenOptions,
path::{Path, PathBuf},
};
Expand Down Expand Up @@ -106,11 +106,6 @@ impl WatchOnlyWallet {
for cash_note in received_cash_notes {
let id = cash_note.unique_pubkey();

if self.keyless_wallet.spent_cash_notes.contains(&id) {
debug!("skipping: cash_note is spent");
continue;
}

if cash_note.derived_pubkey(&self.main_pubkey).is_err() {
debug!("skipping: cash_note is not our key");
continue;
Expand Down Expand Up @@ -141,11 +136,6 @@ impl WatchOnlyWallet {
for cash_note in received_cash_notes {
let id = cash_note.unique_pubkey();

if self.keyless_wallet.spent_cash_notes.contains(&id) {
debug!("skipping: cash_note is spent");
continue;
}

if cash_note.derived_pubkey(&self.main_pubkey).is_err() {
debug!("skipping: cash_note is not our key");
continue;
Expand Down Expand Up @@ -187,38 +177,9 @@ impl WatchOnlyWallet {
{
for k in unique_pubkeys {
self.keyless_wallet.available_cash_notes.remove(k);
self.keyless_wallet.spent_cash_notes.insert(*k);
}
}

/// Return the set of UnniquePubjkey's of spent cash notes.
pub fn spent_cash_notes(&self) -> &BTreeSet<UniquePubkey> {
&self.keyless_wallet.spent_cash_notes
}

/// Insert provided UniquePubkey's into the set of spent cash notes.
pub fn insert_spent_cash_notes<'a, T>(&mut self, spent_cash_notes: T)
where
T: IntoIterator<Item = &'a UniquePubkey>,
{
for pk in spent_cash_notes {
let _ = self.keyless_wallet.spent_cash_notes.insert(*pk);
}
}

/// Return cash notes created for others
pub fn cash_notes_created_for_others(&self) -> &BTreeSet<UniquePubkey> {
&self.keyless_wallet.cash_notes_created_for_others
}

/// Record pubkey as a cash note created for others
pub fn insert_cash_note_created_for_others(&mut self, unique_pubkey: UniquePubkey) {
let _ = self
.keyless_wallet
.cash_notes_created_for_others
.insert(unique_pubkey);
}

/// Return a payment transaction detail
pub fn get_payment_transaction(&self, name: &XorName) -> Option<&PaymentDetails> {
self.keyless_wallet.payment_transactions.get(name)
Expand Down Expand Up @@ -277,8 +238,6 @@ mod tests {
assert_eq!(wallet_dir.path(), wallet.wallet_dir());
assert_eq!(main_pubkey, wallet.address());
assert_eq!(NanoTokens::zero(), wallet.balance());
assert!(wallet.cash_notes_created_for_others().is_empty());
assert!(wallet.spent_cash_notes().is_empty());
assert!(wallet.available_cash_notes().is_empty());

Ok(())
Expand All @@ -302,12 +261,6 @@ mod tests {
assert_eq!(GENESIS_CASHNOTE_AMOUNT, wallet.balance().as_nano());
assert_eq!(GENESIS_CASHNOTE_AMOUNT, deserialised.balance().as_nano());

assert!(wallet.cash_notes_created_for_others().is_empty());
assert!(deserialised.cash_notes_created_for_others().is_empty());

assert!(wallet.spent_cash_notes().is_empty());
assert!(deserialised.spent_cash_notes().is_empty());

assert_eq!(1, wallet.available_cash_notes().len());
assert_eq!(1, deserialised.available_cash_notes().len());
assert_eq!(
Expand Down

0 comments on commit 8fd5683

Please sign in to comment.