Skip to content

Commit

Permalink
refactor!: include spend src tx hash
Browse files Browse the repository at this point in the history
- This is the hash of the tx where the dbc to be spent, was created.
In other words: that src tx shall contain this spend as an output.
  • Loading branch information
oetyng committed Apr 12, 2023
1 parent 3523055 commit ed9285c
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 188 deletions.
74 changes: 34 additions & 40 deletions benches/reissue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ fn bench_reissue_1_to_100(c: &mut Criterion) {
generate_dbc_of_value(Token::from_nano(N_OUTPUTS), &mut rng).unwrap();

let dbc_builder = sn_dbc::TransactionBuilder::default()
.add_input_by_secrets(
starting_dbc.derived_key(&starting_main_key).unwrap(),
starting_dbc.revealed_amount(&starting_main_key).unwrap(),
)
.add_input_dbc(&starting_dbc, &starting_main_key)
.unwrap()
.add_outputs((0..N_OUTPUTS).map(|_| {
(
Token::from_nano(1),
Expand All @@ -40,23 +38,19 @@ fn bench_reissue_1_to_100(c: &mut Criterion) {
.build(Hash::default(), &mut rng)
.unwrap();

for (tx, signed_spend) in dbc_builder.signed_spends() {
spentbook_node.log_spent(tx, signed_spend).unwrap();
let dst_tx = &dbc_builder.dst_tx;
for signed_spend in dbc_builder.signed_spends() {
spentbook_node.log_spent(dst_tx, signed_spend).unwrap();
}

let tx = &dbc_builder.tx;
let signed_spends: BTreeSet<_> = dbc_builder
.signed_spends()
.iter()
.map(|(_, spend)| (*spend).clone())
.collect();
let signed_spends: BTreeSet<_> = dbc_builder.signed_spends().into_iter().cloned().collect();

c.bench_function(&format!("reissue split 1 to {N_OUTPUTS}"), |b| {
#[cfg(unix)]
let guard = pprof::ProfilerGuard::new(100).unwrap();

b.iter(|| {
TransactionVerifier::verify(black_box(tx), &signed_spends).unwrap();
TransactionVerifier::verify(black_box(dst_tx), &signed_spends).unwrap();
});

#[cfg(unix)]
Expand Down Expand Up @@ -84,10 +78,8 @@ fn bench_reissue_100_to_1(c: &mut Criterion) {
.collect();

let dbc_builder = sn_dbc::TransactionBuilder::default()
.add_input_by_secrets(
starting_dbc.derived_key(&starting_main_key).unwrap(),
starting_dbc.revealed_amount(&starting_main_key).unwrap(),
)
.add_input_dbc(&starting_dbc, &starting_main_key)
.unwrap()
.add_outputs(
outputs
.iter()
Expand All @@ -104,23 +96,23 @@ fn bench_reissue_100_to_1(c: &mut Criterion) {
.build(Hash::default(), &mut rng)
.unwrap();

for (tx, signed_spend) in dbc_builder.signed_spends() {
spentbook_node.log_spent(tx, signed_spend).unwrap();
let dst_tx = dbc_builder.dst_tx.clone();
for signed_spend in dbc_builder.signed_spends() {
spentbook_node.log_spent(&dst_tx, signed_spend).unwrap();
}
let dbcs = dbc_builder.build().unwrap();

let main_key = MainKey::random_from_rng(&mut rng);
let derivation_index = random_derivation_index(&mut rng);

let merge_dbc_builder = sn_dbc::TransactionBuilder::default()
.add_inputs_by_secrets(
dbcs.into_iter()
.map(|(dbc, revealed_amount)| {
let (main_key, _, _) = outputs.get(&dbc.id()).unwrap();
(dbc.derived_key(main_key).unwrap(), revealed_amount)
})
.collect(),
)
let mut tx_builder = sn_dbc::TransactionBuilder::default();

for (dbc, _) in dbcs.into_iter() {
let (main_key, _, _) = outputs.get(&dbc.id()).unwrap();
tx_builder = tx_builder.add_input_dbc(&dbc, main_key).unwrap();
}

let merge_dbc_builder = tx_builder
.add_output(
Token::from_nano(N_OUTPUTS),
DbcIdSource {
Expand All @@ -131,23 +123,25 @@ fn bench_reissue_100_to_1(c: &mut Criterion) {
.build(Hash::default(), &mut rng)
.unwrap();

for (tx, signed_spend) in merge_dbc_builder.signed_spends() {
spentbook_node.log_spent(tx, signed_spend).unwrap();
let merge_dst_tx = merge_dbc_builder.dst_tx.clone();
for signed_spend in merge_dbc_builder.signed_spends() {
spentbook_node
.log_spent(&merge_dst_tx, signed_spend)
.unwrap();
}

let tx = &merge_dbc_builder.tx;
let signed_spends: BTreeSet<_> = merge_dbc_builder
.signed_spends()
.iter()
.map(|(_, spend)| (*spend).clone())
.into_iter()
.cloned()
.collect();

c.bench_function(&format!("reissue merge {N_OUTPUTS} to 1"), |b| {
#[cfg(unix)]
let guard = pprof::ProfilerGuard::new(100).unwrap();

b.iter(|| {
TransactionVerifier::verify(black_box(tx), &signed_spends).unwrap();
TransactionVerifier::verify(black_box(&merge_dst_tx), &signed_spends).unwrap();
});

#[cfg(unix)]
Expand All @@ -159,6 +153,7 @@ fn bench_reissue_100_to_1(c: &mut Criterion) {
});
}

#[allow(clippy::result_large_err)]
fn generate_dbc_of_value(
amount: Token,
rng: &mut (impl RngCore + CryptoRng),
Expand All @@ -174,10 +169,8 @@ fn generate_dbc_of_value(
let main_key = MainKey::random_from_rng(rng);

let dbc_builder = sn_dbc::TransactionBuilder::default()
.add_input_by_secrets(
genesis_material.derived_key,
genesis_dbc.revealed_amount(&genesis_material.main_key)?,
)
.add_input_dbc(&genesis_dbc, &genesis_material.main_key)
.unwrap()
.add_outputs(output_amounts.into_iter().map(|amount| {
(
amount,
Expand All @@ -189,8 +182,9 @@ fn generate_dbc_of_value(
}))
.build(Hash::default(), rng)?;

for (tx, signed_spend) in dbc_builder.signed_spends() {
spentbook_node.log_spent(tx, signed_spend)?;
let tx = dbc_builder.dst_tx.clone();
for signed_spend in dbc_builder.signed_spends() {
spentbook_node.log_spent(&tx, signed_spend)?;
}

let (starting_dbc, ..) = dbc_builder.build()?.into_iter().next().unwrap();
Expand Down
98 changes: 53 additions & 45 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use std::collections::{BTreeMap, BTreeSet};
use crate::{
dbc_id::DbcIdSource,
transaction::{
DbcTransaction, Output, RevealedAmount, RevealedInput, RevealedOutput, RevealedTx,
DbcTransaction, InputHistory, Output, RevealedAmount, RevealedOutput, RevealedTx,
},
DbcId, DerivedKey, MainKey,
DbcId, MainKey,
};
use crate::{
rand::{CryptoRng, RngCore},
Expand All @@ -37,20 +37,25 @@ pub struct TransactionBuilder {

impl TransactionBuilder {
/// Add an input given a RevealedInput.
pub fn add_input(mut self, input: RevealedInput) -> Self {
pub fn add_input(mut self, input: InputHistory) -> Self {
self.revealed_tx.inputs.push(input);
self
}

/// Add an input given an iterator over RevealedInput.
pub fn add_inputs(mut self, inputs: impl IntoIterator<Item = RevealedInput>) -> Self {
pub fn add_inputs(mut self, inputs: impl IntoIterator<Item = InputHistory>) -> Self {
self.revealed_tx.inputs.extend(inputs);
self
}

/// Add an input given a Dbc and associated MainKey.
pub fn add_input_dbc(mut self, dbc: &Dbc, main_key: &MainKey) -> Result<Self> {
self = self.add_input(dbc.as_revealed_input(main_key)?);
let input = dbc.as_revealed_input(main_key)?;
let input_src_tx = dbc.src_tx.clone();
self = self.add_input(InputHistory {
input,
input_src_tx,
});
Ok(self)
}

Expand All @@ -73,24 +78,24 @@ impl TransactionBuilder {
Ok(self)
}

/// Add an input given a DerivedKey and a RevealedAmount.
pub fn add_input_by_secrets(
mut self,
derived_key: DerivedKey,
revealed_amount: RevealedAmount,
) -> Self {
let revealed_input = RevealedInput::new(derived_key, revealed_amount);
self = self.add_input(revealed_input);
self
}

/// Add an input given a list of (DerivedKey, RevealedAmount).
pub fn add_inputs_by_secrets(mut self, secrets: Vec<(DerivedKey, RevealedAmount)>) -> Self {
for (derived_key, revealed_amount) in secrets.into_iter() {
self = self.add_input_by_secrets(derived_key, revealed_amount);
}
self
}
// /// Add an input given a DerivedKey and a RevealedAmount.
// pub fn add_input_by_secrets(
// mut self,
// derived_key: DerivedKey,
// revealed_amount: RevealedAmount,
// ) -> Self {
// let revealed_input = RevealedInput::new(derived_key, revealed_amount);
// self = self.add_input(revealed_input);
// self
// }

// /// Add an input given a list of (DerivedKey, RevealedAmount).
// pub fn add_inputs_by_secrets(mut self, secrets: Vec<(DerivedKey, RevealedAmount)>) -> Self {
// for (derived_key, revealed_amount) in secrets.into_iter() {
// self = self.add_input_by_secrets(derived_key, revealed_amount);
// }
// self
// }

/// Add an output given amount and the source of the DbcId for the new Dbc.
pub fn add_output(mut self, amount: Token, dbc_id_src: DbcIdSource) -> Self {
Expand All @@ -110,7 +115,11 @@ impl TransactionBuilder {

/// Get a list of input ids.
pub fn input_ids(&self) -> Vec<DbcId> {
self.revealed_tx.inputs.iter().map(|t| t.dbc_id()).collect()
self.revealed_tx
.inputs
.iter()
.map(|t| t.input.dbc_id())
.collect()
}

/// Get sum of input amounts.
Expand All @@ -119,7 +128,7 @@ impl TransactionBuilder {
.revealed_tx
.inputs
.iter()
.map(|t| t.revealed_amount.value)
.map(|t| t.input.revealed_amount.value)
.sum();
Token::from_nano(amount)
}
Expand All @@ -131,7 +140,7 @@ impl TransactionBuilder {
}

/// Get inputs.
pub fn inputs(&self) -> &Vec<RevealedInput> {
pub fn inputs(&self) -> &Vec<InputHistory> {
&self.revealed_tx.inputs
}

Expand All @@ -143,24 +152,25 @@ impl TransactionBuilder {
/// Build the DbcTransaction by signing the inputs,
/// and generating the blinded outputs. Return a DbcBuilder.
pub fn build(self, reason: Hash, rng: impl RngCore + CryptoRng) -> Result<DbcBuilder> {
let (tx, revealed_outputs) = self.revealed_tx.sign(rng)?;
let (dst_tx, revealed_outputs) = self.revealed_tx.sign(rng)?;

let signed_spends: BTreeSet<_> = tx
let signed_spends: BTreeSet<_> = dst_tx
.inputs
.iter()
.flat_map(|input| {
self.revealed_tx
.inputs
.iter()
.find(|i| i.dbc_id() == input.dbc_id())
.find(|i| i.input.dbc_id() == input.dbc_id())
.map(|i| {
let spend = crate::Spend {
dbc_id: input.dbc_id(),
tx: tx.clone(),
dst_tx: dst_tx.clone(),
reason,
blinded_amount: input.blinded_amount,
src_tx_hash: i.input_src_tx.hash(),
};
let derived_key_sig = i.derived_key.sign(&spend.to_bytes());
let derived_key_sig = i.input.derived_key.sign(&spend.to_bytes());
SignedSpend {
spend,
derived_key_sig,
Expand All @@ -170,7 +180,7 @@ impl TransactionBuilder {
.collect();

Ok(DbcBuilder::new(
tx,
dst_tx,
revealed_outputs,
self.output_id_sources,
self.revealed_tx,
Expand All @@ -183,7 +193,7 @@ impl TransactionBuilder {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct DbcBuilder {
pub tx: DbcTransaction,
pub dst_tx: DbcTransaction,
pub revealed_outputs: Vec<RevealedOutput>,
pub output_id_sources: OutputIdSources,
pub revealed_tx: RevealedTx,
Expand All @@ -193,27 +203,25 @@ pub struct DbcBuilder {
impl DbcBuilder {
/// Create a new DbcBuilder.
pub fn new(
tx: DbcTransaction,
dst_tx: DbcTransaction,
revealed_outputs: Vec<RevealedOutput>,
output_id_sources: OutputIdSources,
revealed_tx: RevealedTx,
signed_spends: BTreeSet<SignedSpend>,
) -> Self {
Self {
tx,
dst_tx,
revealed_outputs,
output_id_sources,
revealed_tx,
signed_spends,
}
}

/// Return the signed spends.
pub fn signed_spends(&self) -> Vec<(&DbcTransaction, &SignedSpend)> {
self.signed_spends
.iter()
.map(|spend| (&self.tx, spend))
.collect()
/// Return the signed spends. They each already contain the
/// dst_tx, so the inclusion of it in the result is just for convenience.
pub fn signed_spends(&self) -> Vec<&SignedSpend> {
self.signed_spends.iter().collect()
}

/// Build the output Dbcs, verifying the transaction and SignedSpends.
Expand All @@ -223,7 +231,7 @@ impl DbcBuilder {
pub fn build(self) -> Result<Vec<(Dbc, RevealedAmount)>> {
// Verify the tx, along with signed spends.
// Note that we do this just once for entire tx, not once per output Dbc.
TransactionVerifier::verify(&self.tx, &self.signed_spends)?;
TransactionVerifier::verify(&self.dst_tx, &self.signed_spends)?;

// Build output Dbcs.
self.build_output_dbcs()
Expand All @@ -245,7 +253,7 @@ impl DbcBuilder {
.collect();

let dbc_id_list: Vec<&DbcIdSource> = self
.tx
.dst_tx
.outputs
.iter()
.map(|output| {
Expand All @@ -257,7 +265,7 @@ impl DbcBuilder {

// Form the final output DBCs
let output_dbcs: Vec<(Dbc, RevealedAmount)> = self
.tx
.dst_tx
.outputs
.iter()
.zip(dbc_id_list)
Expand All @@ -276,7 +284,7 @@ impl DbcBuilder {
));
let dbc = Dbc {
id: dbc_id_src.dbc_id(),
tx: self.tx.clone(),
src_tx: self.dst_tx.clone(),
ciphers,
signed_spends: self.signed_spends.clone(),
};
Expand Down
Loading

0 comments on commit ed9285c

Please sign in to comment.