mirror of https://github.com/zcash/orchard.git
Apply suggestions from code review
Co-authored-by: str4d <thestr4d@gmail.com>
This commit is contained in:
parent
2e2c161d52
commit
938b203de5
|
@ -27,7 +27,7 @@ use crate::{
|
||||||
|
|
||||||
const MIN_ACTIONS: usize = 2;
|
const MIN_ACTIONS: usize = 2;
|
||||||
|
|
||||||
/// An enumeration of rules Orchard bundle construction.
|
/// An enumeration of rules for Orchard bundle construction.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum BundleType {
|
pub enum BundleType {
|
||||||
/// A transactional bundle will be padded if necessary to contain at least 2 actions,
|
/// A transactional bundle will be padded if necessary to contain at least 2 actions,
|
||||||
|
@ -60,7 +60,13 @@ impl BundleType {
|
||||||
Ok(core::cmp::max(num_requested_actions, MIN_ACTIONS))
|
Ok(core::cmp::max(num_requested_actions, MIN_ACTIONS))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BundleType::Coinbase => Ok(num_outputs),
|
BundleType::Coinbase => {
|
||||||
|
if num_spends > 0 {
|
||||||
|
Err("Coinbase bundles have spends disabled, so num_spends must be zero")
|
||||||
|
} else {
|
||||||
|
Ok(num_outputs)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +86,7 @@ pub enum BuildError {
|
||||||
SpendsDisabled,
|
SpendsDisabled,
|
||||||
/// Spends are disabled for the provided bundle type.
|
/// Spends are disabled for the provided bundle type.
|
||||||
OutputsDisabled,
|
OutputsDisabled,
|
||||||
/// The anchor provided to this builder doesn't match the merkle path used to add a spend.
|
/// The anchor provided to this builder doesn't match the Merkle path used to add a spend.
|
||||||
AnchorMismatch,
|
AnchorMismatch,
|
||||||
/// A bundle could not be built because required signatures were missing.
|
/// A bundle could not be built because required signatures were missing.
|
||||||
MissingSignatures,
|
MissingSignatures,
|
||||||
|
@ -217,6 +223,16 @@ impl SpendInfo {
|
||||||
merkle_path,
|
merkle_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_matching_anchor(&self, anchor: Anchor) -> bool {
|
||||||
|
if self.note.value() == NoteValue::zero() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
let cm = self.note.commitment();
|
||||||
|
let path_root = self.merkle_path.root(cm.into());
|
||||||
|
path_root == anchor
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a specific output to receive funds in an [`Action`].
|
/// Information about a specific output to receive funds in an [`Action`].
|
||||||
|
@ -324,6 +340,11 @@ impl ActionInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Type alias for an in-progress bundle that has no proofs or signatures.
|
||||||
|
///
|
||||||
|
/// This is returned by [`Builder::build`].
|
||||||
|
pub type UnauthorizedBundle<V> = Bundle<InProgress<Unproven, Unauthorized>, V>;
|
||||||
|
|
||||||
/// A builder that constructs a [`Bundle`] from a set of notes to be spent, and outputs
|
/// 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)]
|
||||||
|
@ -366,15 +387,14 @@ impl Builder {
|
||||||
return Err(SpendError::SpendsDisabled);
|
return Err(SpendError::SpendsDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let spend = SpendInfo::new(fvk, note, merkle_path).ok_or(SpendError::FvkMismatch)?;
|
||||||
|
|
||||||
// Consistency check: all anchors must be equal.
|
// Consistency check: all anchors must be equal.
|
||||||
let cm = note.commitment();
|
if !spend.has_matching_anchor(anchor) {
|
||||||
let path_root = merkle_path.root(cm.into());
|
|
||||||
if path_root != anchor {
|
|
||||||
return Err(SpendError::AnchorMismatch);
|
return Err(SpendError::AnchorMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.spends
|
self.spends.push(spend);
|
||||||
.push(SpendInfo::new(fvk, note, merkle_path).ok_or(SpendError::FvkMismatch)?);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -442,7 +462,7 @@ impl Builder {
|
||||||
pub fn build<V: TryFrom<i64>>(
|
pub fn build<V: TryFrom<i64>>(
|
||||||
self,
|
self,
|
||||||
rng: impl RngCore,
|
rng: impl RngCore,
|
||||||
) -> Result<Option<Bundle<InProgress<Unproven, Unauthorized>, V>>, BuildError> {
|
) -> Result<Option<UnauthorizedBundle<V>>, BuildError> {
|
||||||
bundle(rng, self.spends, self.outputs, self.bundle_type)
|
bundle(rng, self.spends, self.outputs, self.bundle_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,7 +476,7 @@ pub fn bundle<V: TryFrom<i64>>(
|
||||||
mut spends: Vec<SpendInfo>,
|
mut spends: Vec<SpendInfo>,
|
||||||
mut outputs: Vec<OutputInfo>,
|
mut outputs: Vec<OutputInfo>,
|
||||||
bundle_type: BundleType,
|
bundle_type: BundleType,
|
||||||
) -> Result<Option<Bundle<InProgress<Unproven, Unauthorized>, V>>, BuildError> {
|
) -> Result<Option<UnauthorizedBundle<V>>, BuildError> {
|
||||||
let (flags, anchor) = bundle_type.bundle_config();
|
let (flags, anchor) = bundle_type.bundle_config();
|
||||||
|
|
||||||
let num_requested_spends = spends.len();
|
let num_requested_spends = spends.len();
|
||||||
|
@ -465,12 +485,8 @@ pub fn bundle<V: TryFrom<i64>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
for spend in &spends {
|
for spend in &spends {
|
||||||
if spend.note.value() != NoteValue::zero() {
|
if !spend.has_matching_anchor(anchor) {
|
||||||
let cm = spend.note.commitment();
|
return Err(BuildError::AnchorMismatch);
|
||||||
let path_root = spend.merkle_path.root(cm.into());
|
|
||||||
if path_root != anchor {
|
|
||||||
return Err(BuildError::AnchorMismatch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue