Skip to content

Commit

Permalink
feat: rename utxo by CashNoteRedemption
Browse files Browse the repository at this point in the history
  • Loading branch information
grumbach committed Sep 20, 2023
1 parent 7410682 commit 95a0de6
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 64 deletions.
2 changes: 1 addition & 1 deletion sn_networking/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type PendingGetRecord = HashMap<QueryId, (oneshot::Sender<Result<Record>>, GetRe

/// What is the largest packet to send over the network.
/// Records larger than this will be rejected.
// TODO: revisit once utxo is in
// TODO: revisit once cashnote_redemption is in

Check notice

Code scanning / devskim

A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note

Suspicious comment
const MAX_PACKET_SIZE: usize = 1024 * 1024 * 5; // the chunk size is 1mb, so should be higher than that to prevent failures, 5mb here to allow for CashNote storage

// Timeout for requests sent/received through the request_response behaviour.
Expand Down
13 changes: 8 additions & 5 deletions sn_networking/src/transfers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,19 @@ impl Network {
transfer: Transfer,
wallet: &LocalWallet,
) -> Result<Vec<CashNote>> {
// get UTXOs from encrypted Transfer
// get CashNoteRedemptions from encrypted Transfer
trace!("Decyphering Transfer");
let utxos = wallet
let cashnote_redemptions = wallet
.unwrap_transfer(transfer)
.map_err(|_| Error::FailedToDecypherTransfer)?;
let main_pubkey = wallet.address();

// get the parent transactions
trace!("Getting parent Tx for validation");
let parent_addrs: BTreeSet<SpendAddress> = utxos.iter().map(|u| u.parent_spend).collect();
let parent_addrs: BTreeSet<SpendAddress> = cashnote_redemptions
.iter()
.map(|u| u.parent_spend)
.collect();
let mut tasks = JoinSet::new();
for addr in parent_addrs.clone() {
let self_clone = self.clone();
Expand Down Expand Up @@ -121,7 +124,7 @@ impl Network {
}

// get our outputs from Tx
let our_output_unique_pubkeys: Vec<(UniquePubkey, DerivationIndex)> = utxos
let our_output_unique_pubkeys: Vec<(UniquePubkey, DerivationIndex)> = cashnote_redemptions
.iter()
.map(|u| (wallet.derive_key(&u.derivation_index), u.derivation_index))
.map(|(k, d)| (k.unique_pubkey(), d))
Expand All @@ -132,7 +135,7 @@ impl Network {
.iter()
.find(|tx| tx.outputs.iter().any(|o| o.unique_pubkey() == &id))
.ok_or(Error::InvalidTransfer(
"None of the UTXOs are refered to in upstream Txs".to_string(),
"None of the CashNoteRedemptions are refered to in upstream Txs".to_string(),
))?
.clone();
let signed_spends: BTreeSet<SignedSpend> = parent_spends
Expand Down
12 changes: 6 additions & 6 deletions sn_transfers/src/wallet/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ pub enum Error {
#[error("Could not serialize main key to hex: {0}")]
FailedToHexEncodeKey(String),

#[error("UTXO serialisation failed")]
UtxoSerialisationFailed,
#[error("UTXO decryption failed")]
UtxoDecryptionFailed,
#[error("UTXO encryption failed")]
UtxoEncryptionFailed,
#[error("CashNoteRedemption serialisation failed")]
CashNoteRedemptionSerialisationFailed,
#[error("CashNoteRedemption decryption failed")]
CashNoteRedemptionDecryptionFailed,
#[error("CashNoteRedemption encryption failed")]
CashNoteRedemptionEncryptionFailed,
#[error("We are not a recipient of this Transfer")]
NotRecipient,
#[error("Transfer serialisation failed")]
Expand Down
6 changes: 3 additions & 3 deletions sn_transfers/src/wallet/local_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::{
create_received_cash_notes_dir, get_unconfirmed_txs, get_wallet, load_cash_note,
load_received_cash_notes, store_created_cash_notes, store_unconfirmed_txs, store_wallet,
},
KeyLessWallet, Result, Transfer, Utxo,
CashNoteRedemption, KeyLessWallet, Result, Transfer,
};

use crate::client_transfers::{
Expand Down Expand Up @@ -363,8 +363,8 @@ impl LocalWallet {
Ok(())
}

pub fn unwrap_transfer(&self, transfer: Transfer) -> Result<Vec<Utxo>> {
transfer.utxos(self.key.secret_key())
pub fn unwrap_transfer(&self, transfer: Transfer) -> Result<Vec<CashNoteRedemption>> {
transfer.cashnote_redemptions(self.key.secret_key())
}

pub fn derive_key(&self, derivation_index: &DerivationIndex) -> DerivedSecretKey {
Expand Down
4 changes: 2 additions & 2 deletions sn_transfers/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
mod error;
mod keys;
mod local_store;
mod utxo;
mod transfer;
mod wallet_file;

use crate::client_transfers::ContentPaymentsIdMap;
Expand All @@ -65,7 +65,7 @@ pub use self::{
keys::{bls_secret_from_hex, parse_main_pubkey},
local_store::LocalWallet,
};
pub use utxo::{Transfer, Utxo};
pub use transfer::{CashNoteRedemption, Transfer};

use crate::{MainPubkey, Nano, UniquePubkey};
use std::collections::{BTreeMap, BTreeSet};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use super::error::{Error, Result};
/// Transfer sent to a recipient
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, custom_debug::Debug)]
pub struct Transfer {
/// List of encrypted UTXOs from which a recipient can verify and get money
/// Only the recipient can decrypt these UTXOs
encrypted_utxos: Vec<Ciphertext>,
/// List of encrypted CashNoteRedemptions from which a recipient can verify and get money
/// Only the recipient can decrypt these CashNoteRedemptions
encrypted_cashnote_redemptions: Vec<Ciphertext>,
}

impl Transfer {
Expand All @@ -29,7 +29,8 @@ impl Transfer {
/// This Transfer can be sent safely to the recipients as all data in it is encrypted
/// The recipients can then decrypt the data and use it to verify and reconstruct the CashNotes
pub fn transfers_from_cash_notes(cash_notes: Vec<CashNote>) -> Result<Vec<Transfer>> {
let mut utxos_map: BTreeMap<MainPubkey, Vec<Utxo>> = BTreeMap::new();
let mut cashnote_redemptions_map: BTreeMap<MainPubkey, Vec<CashNoteRedemption>> =
BTreeMap::new();
for cash_note in cash_notes {
let recipient = cash_note.main_pubkey;
let derivation_index = cash_note.derivation_index();
Expand All @@ -43,40 +44,48 @@ impl Transfer {
}
};

let u = Utxo::new(derivation_index, parent_spend_addr);
utxos_map.entry(recipient).or_insert_with(Vec::new).push(u);
let u = CashNoteRedemption::new(derivation_index, parent_spend_addr);
cashnote_redemptions_map
.entry(recipient)
.or_insert_with(Vec::new)
.push(u);
}

let mut transfers = Vec::new();
for (recipient, utxos) in utxos_map {
let t =
Transfer::create(utxos, recipient.0).map_err(|_| Error::UtxoEncryptionFailed)?;
for (recipient, cashnote_redemptions) in cashnote_redemptions_map {
let t = Transfer::create(cashnote_redemptions, recipient.0)
.map_err(|_| Error::CashNoteRedemptionEncryptionFailed)?;
transfers.push(t)
}
Ok(transfers)
}

/// Create a new transfer
/// utxos: List of UTXOs to be used for payment
/// cashnote_redemptions: List of CashNoteRedemptions to be used for payment
/// recipient: main Public key (donation key) of the recipient,
/// not to be confused with the derived keys
pub fn create(utxos: Vec<Utxo>, recipient: PublicKey) -> Result<Self> {
let encrypted_utxos = utxos
pub fn create(
cashnote_redemptions: Vec<CashNoteRedemption>,
recipient: PublicKey,
) -> Result<Self> {
let encrypted_cashnote_redemptions = cashnote_redemptions
.into_iter()
.map(|utxo| utxo.encrypt(recipient))
.map(|cashnote_redemption| cashnote_redemption.encrypt(recipient))
.collect::<Result<Vec<Ciphertext>>>()?;
Ok(Transfer { encrypted_utxos })
Ok(Transfer {
encrypted_cashnote_redemptions,
})
}

/// Get the UTXOs from the Payment
/// This is used by the recipient of a payment to decrypt the utxos in a payment
pub fn utxos(&self, sk: &SecretKey) -> Result<Vec<Utxo>> {
let mut utxos = Vec::new();
for cypher in &self.encrypted_utxos {
let utxo = Utxo::decrypt(cypher, sk)?;
utxos.push(utxo);
/// Get the CashNoteRedemptions from the Payment
/// This is used by the recipient of a payment to decrypt the cashnote_redemptions in a payment
pub fn cashnote_redemptions(&self, sk: &SecretKey) -> Result<Vec<CashNoteRedemption>> {
let mut cashnote_redemptions = Vec::new();
for cypher in &self.encrypted_cashnote_redemptions {
let cashnote_redemption = CashNoteRedemption::decrypt(cypher, sk)?;
cashnote_redemptions.push(cashnote_redemption);
}
Ok(utxos)
Ok(cashnote_redemptions)
}

/// Deserializes a `Transfer` represented as a hex string to a `Transfer`.
Expand Down Expand Up @@ -104,44 +113,46 @@ impl Transfer {
/// This struct contains sensitive information that should be kept secret
/// so it should be encrypted to the recipient's public key (public address)
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, custom_debug::Debug)]
pub struct Utxo {
/// derivation index of the UTXO
pub struct CashNoteRedemption {
/// derivation index of the CashNoteRedemption
/// with this derivation index the owner can derive
/// the secret key from their main key needed to spend this UTXO
/// the secret key from their main key needed to spend this CashNoteRedemption
pub derivation_index: DerivationIndex,
/// spentbook entry of one of one of the inputs (parent spends)
/// using data found at this address the owner can check that the output is valid money
pub parent_spend: SpendAddress,
}

impl Utxo {
/// Create a new Utxo
impl CashNoteRedemption {
/// Create a new CashNoteRedemption
pub fn new(derivation_index: DerivationIndex, parent_spend: SpendAddress) -> Self {
Self {
derivation_index,
parent_spend,
}
}

/// Serialize the Utxo to bytes
/// Serialize the CashNoteRedemption to bytes
pub fn to_bytes(&self) -> Result<Vec<u8>> {
rmp_serde::to_vec(self).map_err(|_| Error::UtxoSerialisationFailed)
rmp_serde::to_vec(self).map_err(|_| Error::CashNoteRedemptionSerialisationFailed)
}

/// Deserialize the Utxo from bytes
/// Deserialize the CashNoteRedemption from bytes
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
rmp_serde::from_slice(bytes).map_err(|_| Error::UtxoSerialisationFailed)
rmp_serde::from_slice(bytes).map_err(|_| Error::CashNoteRedemptionSerialisationFailed)
}

/// Encrypt the Utxo to a public key
/// Encrypt the CashNoteRedemption to a public key
pub fn encrypt(&self, pk: PublicKey) -> Result<Ciphertext> {
let bytes = self.to_bytes()?;
Ok(pk.encrypt(bytes))
}

/// Decrypt the Utxo with a secret key
/// Decrypt the CashNoteRedemption with a secret key
pub fn decrypt(cypher: &Ciphertext, sk: &SecretKey) -> Result<Self> {
let bytes = sk.decrypt(cypher).ok_or(Error::UtxoDecryptionFailed)?;
let bytes = sk
.decrypt(cypher)
.ok_or(Error::CashNoteRedemptionDecryptionFailed)?;
Self::from_bytes(&bytes)
}
}
Expand All @@ -153,32 +164,34 @@ mod tests {
use super::*;

#[test]
fn test_utxo_conversions() {
fn test_cashnote_redemption_conversions() {
let rng = &mut bls::rand::thread_rng();
let utxo = Utxo::new([42; 32], SpendAddress::new(XorName::random(rng)));
let cashnote_redemption =
CashNoteRedemption::new([42; 32], SpendAddress::new(XorName::random(rng)));
let sk = SecretKey::random();
let pk = sk.public_key();

let bytes = utxo.to_bytes().unwrap();
let cipher = utxo.encrypt(pk).unwrap();
let bytes = cashnote_redemption.to_bytes().unwrap();
let cipher = cashnote_redemption.encrypt(pk).unwrap();

let utxo2 = Utxo::from_bytes(&bytes).unwrap();
let utxo3 = Utxo::decrypt(&cipher, &sk).unwrap();
let cashnote_redemption2 = CashNoteRedemption::from_bytes(&bytes).unwrap();
let cashnote_redemption3 = CashNoteRedemption::decrypt(&cipher, &sk).unwrap();

assert_eq!(utxo, utxo2);
assert_eq!(utxo, utxo3);
assert_eq!(cashnote_redemption, cashnote_redemption2);
assert_eq!(cashnote_redemption, cashnote_redemption3);
}

#[test]
fn test_utxo_transfer() {
fn test_cashnote_redemption_transfer() {
let rng = &mut bls::rand::thread_rng();
let utxo = Utxo::new([42; 32], SpendAddress::new(XorName::random(rng)));
let cashnote_redemption =
CashNoteRedemption::new([42; 32], SpendAddress::new(XorName::random(rng)));
let sk = SecretKey::random();
let pk = sk.public_key();

let payment = Transfer::create(vec![utxo.clone()], pk).unwrap();
let utxos = payment.utxos(&sk).unwrap();
let payment = Transfer::create(vec![cashnote_redemption.clone()], pk).unwrap();
let cashnote_redemptions = payment.cashnote_redemptions(&sk).unwrap();

assert_eq!(utxos, vec![utxo]);
assert_eq!(cashnote_redemptions, vec![cashnote_redemption]);
}
}

0 comments on commit 95a0de6

Please sign in to comment.