Skip to content

Commit

Permalink
chore: update docs for CashNote and spends
Browse files Browse the repository at this point in the history
  • Loading branch information
grumbach committed Jul 24, 2024
1 parent 3f64f6d commit c28a5da
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 19 deletions.
22 changes: 11 additions & 11 deletions sn_transfers/src/cashnotes/cashnote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ use tiny_keccak::{Hasher, Sha3};

/// Represents a CashNote (CashNote).
///
/// A CashNote is like a check. Only the recipient can spend it.
/// A CashNote is like a piece of money on an account. Only the owner can spend it.
///
/// A CashNote has a MainPubkey representing the recipient of the CashNote.
/// A CashNote has a MainPubkey representing the owner of the CashNote.
///
/// An MainPubkey consists of a PublicKey.
/// The user who receives payments to this MainPubkey, will be holding
/// An MainPubkey is a PublicKey.
/// The user who receives payments (`Transfer`) to this MainPubkey, will be holding
/// a MainSecretKey - a secret key, which corresponds to the MainPubkey.
///
/// The MainPubkey can be given out to multiple parties and
/// multiple CashNotes can share the same MainPubkey.
///
/// The spentbook nodes never sees the MainPubkey. Instead, when a
/// The Network nodes never sees the MainPubkey. Instead, when a
/// transaction output cashnote is created for a given MainPubkey, a random
/// derivation index is generated and used to derive a UniquePubkey, which will be
/// used for this new cashnote.
/// used to create the `Spend` for this new cashnote.
///
/// The UniquePubkey is a unique identifier of a CashNote.
/// The UniquePubkey is a unique identifier of a CashNote and its associated Spend (once the CashNote is spent).
/// So there can only ever be one CashNote with that id, previously, now and forever.
/// The UniquePubkey consists of a PublicKey. To unlock the tokens of the CashNote,
/// the corresponding DerivedSecretKey (consists of a SecretKey) must be used.
Expand All @@ -47,19 +47,19 @@ use tiny_keccak::{Hasher, Sha3};
/// The MainSecretKey and MainPubkey is a unique pair of a user, where the MainSecretKey
/// is held secret, and the MainPubkey is given to all and anyone who wishes to send tokens to you.
/// A sender of tokens will derive the UniquePubkey from the MainPubkey, which will identify the CashNote that
/// holds the tokens going to the recipient. The sender does this using a derivation index.
/// The recipient of the tokens, will use the same derivation index, to derive the DerivedSecretKey
/// holds the tokens going to the owner. The sender does this using a derivation index.
/// The owner of the tokens, will use the same derivation index, to derive the DerivedSecretKey
/// from the MainSecretKey. The DerivedSecretKey and UniquePubkey pair is the second important pair.
/// For an outsider, there is no way to associate either the DerivedSecretKey or the UniquePubkey to the MainPubkey
/// (or for that matter to the MainSecretKey, if they were ever to see it, which they shouldn't of course).
/// Only by having the derivation index, which is only known to sender and recipient, can such a connection be made.
/// Only by having the derivation index, which is only known to sender and owner, can such a connection be made.
///
/// To spend or work with a CashNote, wallet software must obtain the corresponding
/// MainSecretKey from the user, and then call an API function that accepts a MainSecretKey,
/// eg: `cashnote.derivation_index(&main_key)`
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub struct CashNote {
/// The transaction's input's SignedSpends
/// The parent spends of this CashNote. These are assumed to fetched from the Network.
pub parent_spends: BTreeSet<SignedSpend>,
/// This is the MainPubkey of the owner of this CashNote
pub main_pubkey: MainPubkey,
Expand Down
23 changes: 15 additions & 8 deletions sn_transfers/src/cashnotes/signed_spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ use std::{
collections::{BTreeMap, BTreeSet},
};

/// SignedSpend's are constructed when a CashNote is logged to the spentbook.
/// `SignedSpend`s are the core of the Network's transaction system.
/// They are the data type on the Network used to commit to a transfer of value. Analogous to a transaction in Bitcoin.
/// They are signed piece of data proving the owner's commitment to transfer value.
/// `Spend`s refer to their ancestors and descendants, forming a directed acyclic graph that starts from Genesis.
#[derive(Debug, Clone, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SignedSpend {
/// The Spend, which together with signature over it, constitutes the SignedSpend.
/// The Spend, together with the owner's signature over it, constitutes the SignedSpend.
pub spend: Spend,
/// The DerivedSecretKey's signature over (the hash of) Spend, confirming that the CashNote was intended to be spent.
/// The DerivedSecretKey's signature over the Spend, proving the owner's commitment to the Spend.
#[debug(skip)]
pub derived_key_sig: Signature,
}
Expand Down Expand Up @@ -159,18 +162,22 @@ impl std::hash::Hash for SignedSpend {
}
}

/// Represents the data to be signed by the DerivedSecretKey of the CashNote being spent.
/// The claimed `spend.unique_pubkey` must appears in the `ancestor` spends, and the total sum of amount
/// must be equal to the total sum of amount of all outputs (descendants)
/// Represents a spent UniquePubkey on the Network.
/// When a CashNote is spent, a Spend is created with the UniquePubkey of the CashNote.
/// It is then sent to the Network along with the signature of the owner using the DerivedSecretKey matching its UniquePubkey.
/// A Spend can have multiple ancestors (other spends) which will refer to it as a descendant.
/// A Spend's value is equal to the total value given by its ancestors, which one can fetch on the Network to check.
/// A Spend can have multiple descendants (other spends) which will refer to it as an ancestor.
/// A Spend's value is equal to the total value of given to its descendants.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Spend {
/// UniquePubkey of input CashNote that this SignedSpend is proving to be spent.
pub unique_pubkey: UniquePubkey,
/// Reason why this CashNote was spent.
pub reason: SpendReason,
/// Inputs (parent spends) of this spend
/// parent spends of this spend
pub ancestors: BTreeSet<UniquePubkey>,
/// Outputs of this spend
/// spends we are parents of along with the amount we commited to give them
pub descendants: BTreeMap<UniquePubkey, (NanoTokens, OutputPurpose)>,
}

Expand Down
3 changes: 3 additions & 0 deletions sn_transfers/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ pub enum TransferError {
CashNoteRedemptionDecryptionFailed,
#[error("CashNoteRedemption encryption failed")]
CashNoteRedemptionEncryptionFailed,

#[error("Transaction serialization error: {0}")]
TransactionSerialization(String),
#[error("Unsigned transaction is invalid: {0}")]
InvalidUnsignedTransaction(String),

#[error("Transfer serialisation failed")]
TransferSerializationFailed,
Expand Down
19 changes: 19 additions & 0 deletions sn_transfers/src/transfers/unsigned_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ impl Debug for UnsignedTransaction {

impl UnsignedTransaction {
/// Create a new `UnsignedTransaction` with the given inputs and outputs
/// This function will perform a distribution of the input value to the outputs
/// In the figure below, inputs and outputs represent `CashNote`s,
/// which are spent thus creating spends that commit to a transfer of value to the outputs.
/// The value of the outputs is the sum of the values given to them by the inputs.
///
/// ```text
///
/// inputA(7) inputB(5)
/// | |
/// | |
/// spend1 spend2
/// / \ / \ \__________
/// 5 2 2 1 2
/// / \ / \ \
/// outputA(5) outputB(4) outputC(1) change(2)
///
/// ```
///
/// Once created, the `UnsignedTransaction` can be signed with the owner's `MainSecretKey` using the `sign` method
pub fn new(
available_cash_notes: Vec<CashNote>,
recipients: Vec<(NanoTokens, MainPubkey, DerivationIndex, OutputPurpose)>,
Expand Down

0 comments on commit c28a5da

Please sign in to comment.