Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
thibault-martinez committed Dec 18, 2023
1 parent 476095e commit a0ad146
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 131 deletions.
128 changes: 127 additions & 1 deletion sdk/src/types/block/mana/allotment.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use packable::Packable;
use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
use core::ops::RangeInclusive;

use derive_more::Deref;
use iterator_sorted::is_unique_sorted;
use packable::{bounded::BoundedU16, prefix::BoxedSlicePrefix, Packable};

use crate::types::block::{
output::AccountId,
Expand Down Expand Up @@ -62,6 +67,127 @@ fn verify_mana<const VERIFY: bool>(mana: &u64, params: &ProtocolParameters) -> R
Ok(())
}

pub(crate) type ManaAllotmentCount =
BoundedU16<{ *ManaAllotments::COUNT_RANGE.start() }, { *ManaAllotments::COUNT_RANGE.end() }>;

/// A list of [`ManaAllotment`]s with unique [`AccountId`]s.
#[derive(Clone, Debug, Eq, PartialEq, Deref, Packable)]
#[packable(unpack_visitor = ProtocolParameters)]
#[packable(unpack_error = Error, with = |e| e.unwrap_item_err_or_else(|p| Error::InvalidManaAllotmentCount(p.into())))]
pub struct ManaAllotments(
#[packable(verify_with = verify_mana_allotments)] BoxedSlicePrefix<ManaAllotment, ManaAllotmentCount>,
);

impl ManaAllotments {
/// The minimum number of mana allotments of a transaction.
pub const COUNT_MIN: u16 = 0;
/// The maximum number of mana allotments of a transaction.
pub const COUNT_MAX: u16 = 128;
/// The range of valid numbers of mana allotments of a transaction.
pub const COUNT_RANGE: RangeInclusive<u16> = Self::COUNT_MIN..=Self::COUNT_MAX; // [1..128]

/// Creates a new [`ManaAllotments`] from a vec.
pub fn from_vec(allotments: Vec<ManaAllotment>) -> Result<Self, Error> {
verify_mana_allotments_unique_sorted(&allotments)?;

Ok(Self(
allotments
.into_boxed_slice()
.try_into()
.map_err(Error::InvalidManaAllotmentCount)?,
))
}

/// Creates a new [`ManaAllotments`] from an ordered set.
pub fn from_set(allotments: BTreeSet<ManaAllotment>) -> Result<Self, Error> {
Ok(Self(
allotments
.into_iter()
.collect::<Box<[_]>>()
.try_into()
.map_err(Error::InvalidManaAllotmentCount)?,
))
}

/// Gets a reference to an [`ManaAllotment`], if one exists, using an [`AccountId`].
#[inline(always)]
pub fn get(&self, account_id: &AccountId) -> Option<&ManaAllotment> {
self.0.iter().find(|a| a.account_id() == account_id)
}
}

fn verify_mana_allotments<const VERIFY: bool>(
allotments: &[ManaAllotment],
protocol_params: &ProtocolParameters,
) -> Result<(), Error> {
if VERIFY {
verify_mana_allotments_unique_sorted(allotments)?;
verify_mana_allotments_sum(allotments, protocol_params)?;
}

Ok(())
}

fn verify_mana_allotments_unique_sorted<'a>(
allotments: impl IntoIterator<Item = &'a ManaAllotment>,
) -> Result<(), Error> {
if !is_unique_sorted(allotments.into_iter()) {
return Err(Error::ManaAllotmentsNotUniqueSorted);
}
Ok(())
}

pub(crate) fn verify_mana_allotments_sum<'a>(
allotments: impl IntoIterator<Item = &'a ManaAllotment>,
protocol_params: &ProtocolParameters,
) -> Result<(), Error> {
let mut mana_sum: u64 = 0;
let max_mana = protocol_params.mana_parameters().max_mana();

for ManaAllotment { mana, .. } in allotments {
mana_sum = mana_sum.checked_add(*mana).ok_or(Error::InvalidManaAllotmentSum {
sum: mana_sum as u128 + *mana as u128,
max: max_mana,
})?;

if mana_sum > max_mana {
return Err(Error::InvalidManaAllotmentSum {
sum: mana_sum as u128,
max: max_mana,
});
}
}

Ok(())
}

impl TryFrom<Vec<ManaAllotment>> for ManaAllotments {
type Error = Error;

#[inline(always)]
fn try_from(allotments: Vec<ManaAllotment>) -> Result<Self, Self::Error> {
Self::from_vec(allotments)
}
}

impl TryFrom<BTreeSet<ManaAllotment>> for ManaAllotments {
type Error = Error;

#[inline(always)]
fn try_from(allotments: BTreeSet<ManaAllotment>) -> Result<Self, Self::Error> {
Self::from_set(allotments)
}
}

impl IntoIterator for ManaAllotments {
type Item = ManaAllotment;
type IntoIter = alloc::vec::IntoIter<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
Vec::from(Into::<Box<[ManaAllotment]>>::into(self.0)).into_iter()
}
}

#[cfg(feature = "serde")]
pub(super) mod dto {
use serde::{Deserialize, Serialize};
Expand Down
136 changes: 6 additions & 130 deletions sdk/src/types/block/mana/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,135 +5,11 @@ mod allotment;
mod parameters;
mod rewards;

use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
use core::ops::RangeInclusive;

use derive_more::Deref;
use iterator_sorted::is_unique_sorted;
use packable::{bounded::BoundedU16, prefix::BoxedSlicePrefix, Packable};

#[cfg(feature = "serde")]
pub use self::allotment::dto::ManaAllotmentDto;
pub use self::{allotment::ManaAllotment, parameters::ManaParameters, rewards::RewardsParameters};
use super::{output::AccountId, protocol::ProtocolParameters, Error};

pub(crate) type ManaAllotmentCount =
BoundedU16<{ *ManaAllotments::COUNT_RANGE.start() }, { *ManaAllotments::COUNT_RANGE.end() }>;

/// A list of [`ManaAllotment`]s with unique [`AccountId`]s.
#[derive(Clone, Debug, Eq, PartialEq, Deref, Packable)]
#[packable(unpack_visitor = ProtocolParameters)]
#[packable(unpack_error = Error, with = |e| e.unwrap_item_err_or_else(|p| Error::InvalidManaAllotmentCount(p.into())))]
pub struct ManaAllotments(
#[packable(verify_with = verify_mana_allotments)] BoxedSlicePrefix<ManaAllotment, ManaAllotmentCount>,
);

impl ManaAllotments {
/// The minimum number of mana allotments of a transaction.
pub const COUNT_MIN: u16 = 0;
/// The maximum number of mana allotments of a transaction.
pub const COUNT_MAX: u16 = 128;
/// The range of valid numbers of mana allotments of a transaction.
pub const COUNT_RANGE: RangeInclusive<u16> = Self::COUNT_MIN..=Self::COUNT_MAX; // [1..128]

/// Creates a new [`ManaAllotments`] from a vec.
pub fn from_vec(allotments: Vec<ManaAllotment>) -> Result<Self, Error> {
verify_mana_allotments_unique_sorted(&allotments)?;

Ok(Self(
allotments
.into_boxed_slice()
.try_into()
.map_err(Error::InvalidManaAllotmentCount)?,
))
}

/// Creates a new [`ManaAllotments`] from an ordered set.
pub fn from_set(allotments: BTreeSet<ManaAllotment>) -> Result<Self, Error> {
Ok(Self(
allotments
.into_iter()
.collect::<Box<[_]>>()
.try_into()
.map_err(Error::InvalidManaAllotmentCount)?,
))
}

/// Gets a reference to an [`ManaAllotment`], if one exists, using an [`AccountId`].
#[inline(always)]
pub fn get(&self, account_id: &AccountId) -> Option<&ManaAllotment> {
self.0.iter().find(|a| a.account_id() == account_id)
}
}

fn verify_mana_allotments<const VERIFY: bool>(
allotments: &[ManaAllotment],
protocol_params: &ProtocolParameters,
) -> Result<(), Error> {
if VERIFY {
verify_mana_allotments_unique_sorted(allotments)?;
verify_mana_allotments_sum(allotments, protocol_params)?;
}

Ok(())
}

fn verify_mana_allotments_unique_sorted<'a>(
allotments: impl IntoIterator<Item = &'a ManaAllotment>,
) -> Result<(), Error> {
if !is_unique_sorted(allotments.into_iter()) {
return Err(Error::ManaAllotmentsNotUniqueSorted);
}
Ok(())
}

pub(crate) fn verify_mana_allotments_sum<'a>(
allotments: impl IntoIterator<Item = &'a ManaAllotment>,
protocol_params: &ProtocolParameters,
) -> Result<(), Error> {
let mut mana_sum: u64 = 0;
let max_mana = protocol_params.mana_parameters().max_mana();

for ManaAllotment { mana, .. } in allotments {
mana_sum = mana_sum.checked_add(*mana).ok_or(Error::InvalidManaAllotmentSum {
sum: mana_sum as u128 + *mana as u128,
max: max_mana,
})?;

if mana_sum > max_mana {
return Err(Error::InvalidManaAllotmentSum {
sum: mana_sum as u128,
max: max_mana,
});
}
}

Ok(())
}

impl TryFrom<Vec<ManaAllotment>> for ManaAllotments {
type Error = Error;

#[inline(always)]
fn try_from(allotments: Vec<ManaAllotment>) -> Result<Self, Self::Error> {
Self::from_vec(allotments)
}
}

impl TryFrom<BTreeSet<ManaAllotment>> for ManaAllotments {
type Error = Error;

#[inline(always)]
fn try_from(allotments: BTreeSet<ManaAllotment>) -> Result<Self, Self::Error> {
Self::from_set(allotments)
}
}

impl IntoIterator for ManaAllotments {
type Item = ManaAllotment;
type IntoIter = alloc::vec::IntoIter<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
Vec::from(Into::<Box<[ManaAllotment]>>::into(self.0)).into_iter()
}
}
pub(crate) use self::allotment::{verify_mana_allotments_sum, ManaAllotmentCount};
pub use self::{
allotment::{ManaAllotment, ManaAllotments},
parameters::ManaParameters,
rewards::RewardsParameters,
};
7 changes: 7 additions & 0 deletions sdk/src/types/block/mana/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl ManaParameters {
if self.generation_rate() == 0 || slot_delta == 0 {
return 0;
}

fixed_point_multiply(
amount,
slot_delta * self.generation_rate() as u32,
Expand Down Expand Up @@ -121,12 +122,14 @@ impl ProtocolParameters {
self.epoch_index_of(slot_index_created),
self.epoch_index_of(slot_index_target),
);

if epoch_index_created > epoch_index_target {
return Err(Error::InvalidEpochDelta {
created: epoch_index_created,
target: epoch_index_target,
});
}

Ok(self
.mana_parameters()
.decay(mana, epoch_index_target.0 - epoch_index_created.0))
Expand All @@ -140,12 +143,14 @@ impl ProtocolParameters {
claimed_epoch: impl Into<EpochIndex>,
) -> Result<u64, Error> {
let (reward_epoch, claimed_epoch) = (reward_epoch.into(), claimed_epoch.into());

if reward_epoch > claimed_epoch {
return Err(Error::InvalidEpochDelta {
created: reward_epoch,
target: claimed_epoch,
});
}

Ok(self.mana_parameters().decay(reward, claimed_epoch.0 - reward_epoch.0))
}

Expand All @@ -162,6 +167,7 @@ impl ProtocolParameters {
self.epoch_index_of(slot_index_created),
self.epoch_index_of(slot_index_target),
);

if epoch_index_created > epoch_index_target {
return Err(Error::InvalidEpochDelta {
created: epoch_index_created,
Expand All @@ -171,6 +177,7 @@ impl ProtocolParameters {
if slot_index_created >= slot_index_target {
return Ok(0);
}

let mana_parameters = self.mana_parameters();

Ok(if epoch_index_created == epoch_index_target {
Expand Down

0 comments on commit a0ad146

Please sign in to comment.