Skip to content

Commit

Permalink
Derive packable for MultiAddress
Browse files Browse the repository at this point in the history
  • Loading branch information
thibault-martinez committed Nov 12, 2023
1 parent f690b1b commit 1782d63
Showing 1 changed file with 15 additions and 51 deletions.
66 changes: 15 additions & 51 deletions sdk/src/types/block/address/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@ use core::{fmt, ops::RangeInclusive};

use derive_more::{AsRef, Deref, Display, From};
use iterator_sorted::is_unique_sorted;
use packable::{
bounded::BoundedU8,
error::{UnpackError, UnpackErrorExt},
packer::Packer,
prefix::BoxedSlicePrefix,
unpacker::Unpacker,
Packable,
};
use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable};

use crate::types::block::{address::Address, Error};

Expand Down Expand Up @@ -77,12 +70,17 @@ fn verify_weight<const VERIFY: bool>(weight: &u8, _visitor: &()) -> Result<(), E
/// An address that consists of addresses with weights and a threshold value.
/// The Multi Address can be unlocked if the cumulative weight of all unlocked addresses is equal to or exceeds the
/// threshold.
#[derive(Clone, Debug, Deref, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Clone, Debug, Deref, Eq, PartialEq, Ord, PartialOrd, Hash, Packable)]
#[packable(unpack_error = Error)]
#[packable(verify_with = verify_multi_address)]
pub struct MultiAddress {
/// The weighted unlocked addresses.
#[deref]
#[packable(verify_with = verify_addresses)]
#[packable(unpack_error_with = |e| e.unwrap_item_err_or_else(|p| Error::InvalidWeightedAddressCount(p.into())))]
addresses: BoxedSlicePrefix<WeightedAddress, WeightedAddressCount>,
/// The threshold that needs to be reached by the unlocked addresses in order to unlock the multi address.
#[packable(verify_with = verify_threshold)]
threshold: u16,
}

Expand All @@ -103,9 +101,11 @@ impl MultiAddress {
let addresses = BoxedSlicePrefix::<WeightedAddress, WeightedAddressCount>::try_from(addresses)
.map_err(Error::InvalidWeightedAddressCount)?;

verify_cumulative_weight::<true>(&addresses, &threshold, &())?;
let multi_address = Self { addresses, threshold };

Ok(Self { addresses, threshold })
verify_multi_address::<true>(&multi_address, &())?;

Ok(multi_address)
}

/// Returns the addresses of a [`MultiAddress`].
Expand All @@ -121,38 +121,6 @@ impl MultiAddress {
}
}

impl Packable for MultiAddress {
type UnpackError = Error;
type UnpackVisitor = ();

#[inline]
fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
self.addresses.pack(packer)?;
self.threshold.pack(packer)?;

Ok(())
}

#[inline]
fn unpack<U: Unpacker, const VERIFY: bool>(
unpacker: &mut U,
visitor: &Self::UnpackVisitor,
) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
let addresses =
BoxedSlicePrefix::<WeightedAddress, WeightedAddressCount>::unpack::<_, VERIFY>(unpacker, visitor)
.map_packable_err(|e| e.unwrap_item_err_or_else(|e| Error::InvalidWeightedAddressCount(e.into())))?;

verify_addresses::<VERIFY>(&addresses, &()).map_err(UnpackError::Packable)?;

let threshold = u16::unpack::<_, VERIFY>(unpacker, visitor).coerce()?;

verify_threshold::<VERIFY>(&threshold, &()).map_err(UnpackError::Packable)?;
verify_cumulative_weight::<VERIFY>(&addresses, &threshold, &()).map_err(UnpackError::Packable)?;

Ok(Self { addresses, threshold })
}
}

fn verify_addresses<const VERIFY: bool>(addresses: &[WeightedAddress], _visitor: &()) -> Result<(), Error> {
if VERIFY && !is_unique_sorted(addresses.iter().map(WeightedAddress::address)) {
return Err(Error::WeightedAddressesNotUniqueSorted);
Expand All @@ -169,18 +137,14 @@ fn verify_threshold<const VERIFY: bool>(threshold: &u16, _visitor: &()) -> Resul
}
}

fn verify_cumulative_weight<const VERIFY: bool>(
addresses: &[WeightedAddress],
threshold: &u16,
_visitor: &(),
) -> Result<(), Error> {
fn verify_multi_address<const VERIFY: bool>(address: &MultiAddress, _visitor: &()) -> Result<(), Error> {
if VERIFY {
let cumulative_weight = addresses.iter().map(|address| address.weight as u16).sum::<u16>();
let cumulative_weight = address.iter().map(|address| address.weight as u16).sum::<u16>();

if cumulative_weight < *threshold {
if cumulative_weight < address.threshold {
return Err(Error::InvalidMultiAddressCumulativeWeight {
cumulative_weight,
threshold: *threshold,
threshold: address.threshold,
});
}
}
Expand Down

0 comments on commit 1782d63

Please sign in to comment.