1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::collections::{BTreeSet, HashMap, HashSet};
use std::iter::FromIterator;
use curve25519_dalek_ng::scalar::Scalar;
use crate::{Amount, AmountSecrets, Dbc, DbcContent, Hash, ReissueTransaction, Result};
pub struct Output {
pub amount: Amount,
pub owner: blsttc::PublicKey,
}
#[derive(Default)]
pub struct TransactionBuilder {
pub inputs: HashMap<Dbc, AmountSecrets>,
pub outputs: Vec<Output>,
}
impl TransactionBuilder {
pub fn add_input(mut self, dbc: Dbc, amount_secrets: AmountSecrets) -> Self {
self.inputs.insert(dbc, amount_secrets);
self
}
pub fn add_inputs(mut self, inputs: impl IntoIterator<Item = (Dbc, AmountSecrets)>) -> Self {
self.inputs.extend(inputs);
self
}
pub fn add_output(mut self, output: Output) -> Self {
self.outputs.push(output);
self
}
pub fn add_outputs(mut self, outputs: impl IntoIterator<Item = Output>) -> Self {
self.outputs.extend(outputs);
self
}
pub fn inputs_hashes(&self) -> BTreeSet<Hash> {
self.inputs
.iter()
.map(|(dbc, _)| dbc.name())
.collect::<BTreeSet<_>>()
}
pub fn inputs_amount_sum(&self) -> Amount {
self.inputs.iter().map(|(_, s)| s.amount).sum()
}
pub fn outputs_amount_sum(&self) -> Amount {
self.outputs.iter().map(|o| o.amount).sum()
}
pub fn build(self) -> Result<(ReissueTransaction, HashMap<crate::Hash, blsttc::PublicKey>)> {
let parents = BTreeSet::from_iter(self.inputs.keys().map(Dbc::name));
let inputs_bf_sum = self
.inputs
.values()
.map(|amount_secrets| amount_secrets.blinding_factor)
.sum();
let mut outputs_bf_sum: Scalar = Default::default();
let outputs_and_owners = self
.outputs
.iter()
.enumerate()
.map(|(out_idx, output)| {
let blinding_factor = DbcContent::calc_blinding_factor(
out_idx == self.outputs.len() - 1,
inputs_bf_sum,
outputs_bf_sum,
);
outputs_bf_sum += blinding_factor;
let dbc_content = DbcContent::new(
parents.clone(),
output.amount,
output.owner,
blinding_factor,
)?;
Ok((dbc_content, output.owner))
})
.collect::<Result<Vec<_>>>()?;
let inputs = HashSet::from_iter(self.inputs.into_keys());
let output_owners = HashMap::from_iter(
outputs_and_owners
.iter()
.map(|(dbc_content, owner)| (dbc_content.hash(), *owner)),
);
let outputs = HashSet::from_iter(outputs_and_owners.into_iter().map(|(o, _)| o));
Ok((ReissueTransaction { inputs, outputs }, output_owners))
}
}