mirror of https://github.com/zcash/orchard.git
Rename `Builder::add_recipient` to `add_output`.
The term `recipient` is commonly used to refer to the address to which a note is sent; however, a bundle may include multiple outputs to the same recipient. This change is intended to clarify this usage. Co-authored-by: Daira Emma Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
003619bad4
commit
06cb76168e
|
@ -7,6 +7,11 @@ and this project adheres to Rust's notion of
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- `orchard::builder::Builder::add_recipient` has been renamed to `add_output`
|
||||||
|
in order to clarify than more than one output of a given transaction may be
|
||||||
|
sent to the same recipient.
|
||||||
|
|
||||||
## [0.6.0] - 2023-09-08
|
## [0.6.0] - 2023-09-08
|
||||||
### Changed
|
### Changed
|
||||||
- MSRV is now 1.65.0.
|
- MSRV is now 1.65.0.
|
||||||
|
|
|
@ -32,7 +32,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||||
);
|
);
|
||||||
for _ in 0..num_recipients {
|
for _ in 0..num_recipients {
|
||||||
builder
|
builder
|
||||||
.add_recipient(None, recipient, NoteValue::from_raw(10), None)
|
.add_output(None, recipient, NoteValue::from_raw(10), None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
|
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
|
||||||
|
|
|
@ -52,10 +52,10 @@ fn bench_note_decryption(c: &mut Criterion) {
|
||||||
// The builder pads to two actions, and shuffles their order. Add two recipients
|
// The builder pads to two actions, and shuffles their order. Add two recipients
|
||||||
// so the first action is always decryptable.
|
// so the first action is always decryptable.
|
||||||
builder
|
builder
|
||||||
.add_recipient(None, recipient, NoteValue::from_raw(10), None)
|
.add_output(None, recipient, NoteValue::from_raw(10), None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
builder
|
builder
|
||||||
.add_recipient(None, recipient, NoteValue::from_raw(10), None)
|
.add_output(None, recipient, NoteValue::from_raw(10), None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
|
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
|
||||||
bundle
|
bundle
|
||||||
|
|
|
@ -157,16 +157,16 @@ impl SpendInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a specific recipient to receive funds in an [`Action`].
|
/// Information about a specific output to receive funds in an [`Action`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct RecipientInfo {
|
struct OutputInfo {
|
||||||
ovk: Option<OutgoingViewingKey>,
|
ovk: Option<OutgoingViewingKey>,
|
||||||
recipient: Address,
|
recipient: Address,
|
||||||
value: NoteValue,
|
value: NoteValue,
|
||||||
memo: Option<[u8; 512]>,
|
memo: Option<[u8; 512]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecipientInfo {
|
impl OutputInfo {
|
||||||
/// Defined in [Zcash Protocol Spec § 4.8.3: Dummy Notes (Orchard)][orcharddummynotes].
|
/// Defined in [Zcash Protocol Spec § 4.8.3: Dummy Notes (Orchard)][orcharddummynotes].
|
||||||
///
|
///
|
||||||
/// [orcharddummynotes]: https://zips.z.cash/protocol/nu5.pdf#orcharddummynotes
|
/// [orcharddummynotes]: https://zips.z.cash/protocol/nu5.pdf#orcharddummynotes
|
||||||
|
@ -174,7 +174,7 @@ impl RecipientInfo {
|
||||||
let fvk: FullViewingKey = (&SpendingKey::random(rng)).into();
|
let fvk: FullViewingKey = (&SpendingKey::random(rng)).into();
|
||||||
let recipient = fvk.address_at(0u32, Scope::External);
|
let recipient = fvk.address_at(0u32, Scope::External);
|
||||||
|
|
||||||
RecipientInfo {
|
OutputInfo {
|
||||||
ovk: None,
|
ovk: None,
|
||||||
recipient,
|
recipient,
|
||||||
value: NoteValue::zero(),
|
value: NoteValue::zero(),
|
||||||
|
@ -187,12 +187,12 @@ impl RecipientInfo {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ActionInfo {
|
struct ActionInfo {
|
||||||
spend: SpendInfo,
|
spend: SpendInfo,
|
||||||
output: RecipientInfo,
|
output: OutputInfo,
|
||||||
rcv: ValueCommitTrapdoor,
|
rcv: ValueCommitTrapdoor,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionInfo {
|
impl ActionInfo {
|
||||||
fn new(spend: SpendInfo, output: RecipientInfo, rng: impl RngCore) -> Self {
|
fn new(spend: SpendInfo, output: OutputInfo, rng: impl RngCore) -> Self {
|
||||||
ActionInfo {
|
ActionInfo {
|
||||||
spend,
|
spend,
|
||||||
output,
|
output,
|
||||||
|
@ -256,12 +256,12 @@ impl ActionInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder that constructs a [`Bundle`] from a set of notes to be spent, and recipients
|
/// A builder that constructs a [`Bundle`] from a set of notes to be spent, and outputs
|
||||||
/// to receive funds.
|
/// to receive funds.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
spends: Vec<SpendInfo>,
|
spends: Vec<SpendInfo>,
|
||||||
recipients: Vec<RecipientInfo>,
|
outputs: Vec<OutputInfo>,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
anchor: Anchor,
|
anchor: Anchor,
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ impl Builder {
|
||||||
pub fn new(flags: Flags, anchor: Anchor) -> Self {
|
pub fn new(flags: Flags, anchor: Anchor) -> Self {
|
||||||
Builder {
|
Builder {
|
||||||
spends: vec![],
|
spends: vec![],
|
||||||
recipients: vec![],
|
outputs: vec![],
|
||||||
flags,
|
flags,
|
||||||
anchor,
|
anchor,
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ impl Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an address which will receive funds in this transaction.
|
/// Adds an address which will receive funds in this transaction.
|
||||||
pub fn add_recipient(
|
pub fn add_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
ovk: Option<OutgoingViewingKey>,
|
ovk: Option<OutgoingViewingKey>,
|
||||||
recipient: Address,
|
recipient: Address,
|
||||||
|
@ -334,7 +334,7 @@ impl Builder {
|
||||||
return Err(OutputError);
|
return Err(OutputError);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.recipients.push(RecipientInfo {
|
self.outputs.push(OutputInfo {
|
||||||
ovk,
|
ovk,
|
||||||
recipient,
|
recipient,
|
||||||
value,
|
value,
|
||||||
|
@ -353,7 +353,7 @@ impl Builder {
|
||||||
/// Returns the action output components that will be produced by the
|
/// Returns the action output components that will be produced by the
|
||||||
/// transaction being constructed
|
/// transaction being constructed
|
||||||
pub fn outputs(&self) -> &Vec<impl OutputView> {
|
pub fn outputs(&self) -> &Vec<impl OutputView> {
|
||||||
&self.recipients
|
&self.outputs
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The net value of the bundle to be built. The value of all spends,
|
/// The net value of the bundle to be built. The value of all spends,
|
||||||
|
@ -372,16 +372,16 @@ impl Builder {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|spend| spend.note.value() - NoteValue::zero())
|
.map(|spend| spend.note.value() - NoteValue::zero())
|
||||||
.chain(
|
.chain(
|
||||||
self.recipients
|
self.outputs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|recipient| NoteValue::zero() - recipient.value),
|
.map(|output| NoteValue::zero() - output.value),
|
||||||
)
|
)
|
||||||
.fold(Some(ValueSum::zero()), |acc, note_value| acc? + note_value)
|
.fold(Some(ValueSum::zero()), |acc, note_value| acc? + note_value)
|
||||||
.ok_or(OverflowError)?;
|
.ok_or(OverflowError)?;
|
||||||
i64::try_from(value_balance).and_then(|i| V::try_from(i).map_err(|_| value::OverflowError))
|
i64::try_from(value_balance).and_then(|i| V::try_from(i).map_err(|_| value::OverflowError))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a bundle containing the given spent notes and recipients.
|
/// Builds a bundle containing the given spent notes and outputs.
|
||||||
///
|
///
|
||||||
/// The returned bundle will have no proof or signatures; these can be applied with
|
/// The returned bundle will have no proof or signatures; these can be applied with
|
||||||
/// [`Bundle::create_proof`] and [`Bundle::apply_signatures`] respectively.
|
/// [`Bundle::create_proof`] and [`Bundle::apply_signatures`] respectively.
|
||||||
|
@ -389,11 +389,11 @@ impl Builder {
|
||||||
mut self,
|
mut self,
|
||||||
mut rng: impl RngCore,
|
mut rng: impl RngCore,
|
||||||
) -> Result<Bundle<InProgress<Unproven, Unauthorized>, V>, BuildError> {
|
) -> Result<Bundle<InProgress<Unproven, Unauthorized>, V>, BuildError> {
|
||||||
// Pair up the spends and recipients, extending with dummy values as necessary.
|
// Pair up the spends and outputs, extending with dummy values as necessary.
|
||||||
let pre_actions: Vec<_> = {
|
let pre_actions: Vec<_> = {
|
||||||
let num_spends = self.spends.len();
|
let num_spends = self.spends.len();
|
||||||
let num_recipients = self.recipients.len();
|
let num_outputs = self.outputs.len();
|
||||||
let num_actions = [num_spends, num_recipients, MIN_ACTIONS]
|
let num_actions = [num_spends, num_outputs, MIN_ACTIONS]
|
||||||
.iter()
|
.iter()
|
||||||
.max()
|
.max()
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -402,21 +402,20 @@ impl Builder {
|
||||||
self.spends.extend(
|
self.spends.extend(
|
||||||
iter::repeat_with(|| SpendInfo::dummy(&mut rng)).take(num_actions - num_spends),
|
iter::repeat_with(|| SpendInfo::dummy(&mut rng)).take(num_actions - num_spends),
|
||||||
);
|
);
|
||||||
self.recipients.extend(
|
self.outputs.extend(
|
||||||
iter::repeat_with(|| RecipientInfo::dummy(&mut rng))
|
iter::repeat_with(|| OutputInfo::dummy(&mut rng)).take(num_actions - num_outputs),
|
||||||
.take(num_actions - num_recipients),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Shuffle the spends and recipients, so that learning the position of a
|
// Shuffle the spends and outputs, so that learning the position of a
|
||||||
// specific spent note or output note doesn't reveal anything on its own about
|
// specific spent note or output note doesn't reveal anything on its own about
|
||||||
// the meaning of that note in the transaction context.
|
// the meaning of that note in the transaction context.
|
||||||
self.spends.shuffle(&mut rng);
|
self.spends.shuffle(&mut rng);
|
||||||
self.recipients.shuffle(&mut rng);
|
self.outputs.shuffle(&mut rng);
|
||||||
|
|
||||||
self.spends
|
self.spends
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(self.recipients.into_iter())
|
.zip(self.outputs.into_iter())
|
||||||
.map(|(spend, recipient)| ActionInfo::new(spend, recipient, &mut rng))
|
.map(|(spend, output)| ActionInfo::new(spend, output, &mut rng))
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -749,7 +748,7 @@ pub trait OutputView {
|
||||||
fn value<V: From<u64>>(&self) -> V;
|
fn value<V: From<u64>>(&self) -> V;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputView for RecipientInfo {
|
impl OutputView for OutputInfo {
|
||||||
fn value<V: From<u64>>(&self) -> V {
|
fn value<V: From<u64>>(&self) -> V {
|
||||||
V::from(self.value.inner())
|
V::from(self.value.inner())
|
||||||
}
|
}
|
||||||
|
@ -793,7 +792,7 @@ pub mod testing {
|
||||||
sk: SpendingKey,
|
sk: SpendingKey,
|
||||||
anchor: Anchor,
|
anchor: Anchor,
|
||||||
notes: Vec<(Note, MerklePath)>,
|
notes: Vec<(Note, MerklePath)>,
|
||||||
recipient_amounts: Vec<(Address, NoteValue)>,
|
output_amounts: Vec<(Address, NoteValue)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RngCore + CryptoRng> ArbitraryBundleInputs<R> {
|
impl<R: RngCore + CryptoRng> ArbitraryBundleInputs<R> {
|
||||||
|
@ -807,12 +806,12 @@ pub mod testing {
|
||||||
builder.add_spend(fvk.clone(), note, path).unwrap();
|
builder.add_spend(fvk.clone(), note, path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (addr, value) in self.recipient_amounts.into_iter() {
|
for (addr, value) in self.output_amounts.into_iter() {
|
||||||
let scope = fvk.scope_for_address(&addr).unwrap();
|
let scope = fvk.scope_for_address(&addr).unwrap();
|
||||||
let ovk = fvk.to_ovk(scope);
|
let ovk = fvk.to_ovk(scope);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.add_recipient(Some(ovk.clone()), addr, value, None)
|
.add_output(Some(ovk.clone()), addr, value, None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +833,7 @@ pub mod testing {
|
||||||
fn arb_bundle_inputs(sk: SpendingKey)
|
fn arb_bundle_inputs(sk: SpendingKey)
|
||||||
(
|
(
|
||||||
n_notes in 1usize..30,
|
n_notes in 1usize..30,
|
||||||
n_recipients in 1..30,
|
n_outputs in 1..30,
|
||||||
|
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
|
@ -843,12 +842,12 @@ pub mod testing {
|
||||||
arb_positive_note_value(MAX_NOTE_VALUE / n_notes as u64).prop_flat_map(arb_note),
|
arb_positive_note_value(MAX_NOTE_VALUE / n_notes as u64).prop_flat_map(arb_note),
|
||||||
n_notes
|
n_notes
|
||||||
),
|
),
|
||||||
recipient_amounts in vec(
|
output_amounts in vec(
|
||||||
arb_address().prop_flat_map(move |a| {
|
arb_address().prop_flat_map(move |a| {
|
||||||
arb_positive_note_value(MAX_NOTE_VALUE / n_recipients as u64)
|
arb_positive_note_value(MAX_NOTE_VALUE / n_outputs as u64)
|
||||||
.prop_map(move |v| (a, v))
|
.prop_map(move |v| (a, v))
|
||||||
}),
|
}),
|
||||||
n_recipients as usize
|
n_outputs as usize
|
||||||
),
|
),
|
||||||
rng_seed in prop::array::uniform32(prop::num::u8::ANY)
|
rng_seed in prop::array::uniform32(prop::num::u8::ANY)
|
||||||
) -> ArbitraryBundleInputs<StdRng> {
|
) -> ArbitraryBundleInputs<StdRng> {
|
||||||
|
@ -873,7 +872,7 @@ pub mod testing {
|
||||||
sk,
|
sk,
|
||||||
anchor: frontier.root().into(),
|
anchor: frontier.root().into(),
|
||||||
notes: notes_and_auth_paths,
|
notes: notes_and_auth_paths,
|
||||||
recipient_amounts
|
output_amounts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -922,7 +921,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.add_recipient(None, recipient, NoteValue::from_raw(5000), None)
|
.add_output(None, recipient, NoteValue::from_raw(5000), None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let balance: i64 = builder.value_balance().unwrap();
|
let balance: i64 = builder.value_balance().unwrap();
|
||||||
assert_eq!(balance, -5000);
|
assert_eq!(balance, -5000);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
//! - Define your `valueBalanceOrchard` type to enforce your valid value range. This can
|
//! - Define your `valueBalanceOrchard` type to enforce your valid value range. This can
|
||||||
//! be checked in its `TryFrom<i64>` implementation.
|
//! be checked in its `TryFrom<i64>` implementation.
|
||||||
//! - Define your own "amount" type for note values, and convert it to `NoteValue` prior
|
//! - Define your own "amount" type for note values, and convert it to `NoteValue` prior
|
||||||
//! to calling [`Builder::add_recipient`].
|
//! to calling [`Builder::add_output`].
|
||||||
//!
|
//!
|
||||||
//! Inside the circuit, note values are constrained to be unsigned 64-bit integers.
|
//! Inside the circuit, note values are constrained to be unsigned 64-bit integers.
|
||||||
//!
|
//!
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
//! [`Bundle`]: crate::bundle::Bundle
|
//! [`Bundle`]: crate::bundle::Bundle
|
||||||
//! [`Bundle::value_balance`]: crate::bundle::Bundle::value_balance
|
//! [`Bundle::value_balance`]: crate::bundle::Bundle::value_balance
|
||||||
//! [`Builder::value_balance`]: crate::builder::Builder::value_balance
|
//! [`Builder::value_balance`]: crate::builder::Builder::value_balance
|
||||||
//! [`Builder::add_recipient`]: crate::builder::Builder::add_recipient
|
//! [`Builder::add_output`]: crate::builder::Builder::add_output
|
||||||
//! [Rust documentation]: https://doc.rust-lang.org/stable/std/primitive.i64.html
|
//! [Rust documentation]: https://doc.rust-lang.org/stable/std/primitive.i64.html
|
||||||
|
|
||||||
use core::fmt::{self, Debug};
|
use core::fmt::{self, Debug};
|
||||||
|
|
|
@ -44,7 +44,7 @@ fn bundle_chain() {
|
||||||
|
|
||||||
let mut builder = Builder::new(Flags::from_parts(false, true), anchor);
|
let mut builder = Builder::new(Flags::from_parts(false, true), anchor);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
builder.add_recipient(None, recipient, NoteValue::from_raw(5000), None),
|
builder.add_output(None, recipient, NoteValue::from_raw(5000), None),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
let unauthorized = builder.build(&mut rng).unwrap();
|
let unauthorized = builder.build(&mut rng).unwrap();
|
||||||
|
@ -86,7 +86,7 @@ fn bundle_chain() {
|
||||||
let mut builder = Builder::new(Flags::from_parts(true, true), anchor);
|
let mut builder = Builder::new(Flags::from_parts(true, true), anchor);
|
||||||
assert_eq!(builder.add_spend(fvk, note, merkle_path), Ok(()));
|
assert_eq!(builder.add_spend(fvk, note, merkle_path), Ok(()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
builder.add_recipient(None, recipient, NoteValue::from_raw(5000), None),
|
builder.add_output(None, recipient, NoteValue::from_raw(5000), None),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
let unauthorized = builder.build(&mut rng).unwrap();
|
let unauthorized = builder.build(&mut rng).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue