Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Mana decay computation #1334

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions sdk/src/types/block/mana/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,88 @@ impl ManaStructure {
}

/// Returns the mana decay factor for the given epoch index.
pub fn decay_factor_at(&self, epoch_index: EpochIndex) -> Option<u32> {
self.decay_factors.get(*epoch_index as usize).copied()
pub fn decay_factor_at(&self, epoch_index: impl Into<EpochIndex>) -> Option<u32> {
self.decay_factors.get(*epoch_index.into() as usize).copied()
}

/// Returns the max mana that can exist with the mana bits defined.
pub fn max_mana(&self) -> u64 {
(1 << self.bits_count) - 1
}

pub fn decay(&self, value: u64, n: u64) -> u64 {
/// Returns the upper n bits of a u64 value.
fn upper_bits(v: u64, n: usize) -> u64 {
v >> n
}

/// Returns the lower n bits of a u64 value.
fn lower_bits(mut v: u64, n: usize) -> u64 {
v = v << (64 - n);
v >> (64 - n)
Comment on lines +61 to +62
Copy link

@DaughterOfMars DaughterOfMars Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
v = v << (64 - n);
v >> (64 - n)
v & 0xFFFFFFFF

}

/// Returns the result of the multiplication ((value_hi << 32 + value_lo) * mult_factor) >> shift_factor
/// (where mult_factor is a uint32, value_hi and value_lo are uint64 smaller than 2^32, and 0 <= shift_factor <=
/// 32), using only uint64 multiplication functions, without overflowing. The returned result is split
/// in 2 factors: value_hi and value_lo, one containing the upper 32 bits of the result and the other
/// containing the lower 32 bits.
fn multiplication_and_shift(
mut value_hi: u64,
mut value_lo: u64,
mult_factor: u32,
shift_factor: u8,
) -> (u64, u64) {
// multiply the integer part of value_hi by mult_factor
value_hi = value_hi * mult_factor as u64;

// the lower shift_factor bits of the result are extracted and shifted left to form the remainder.
// value_lo is multiplied by mult_factor and right-shifted by shift_factor bits.
// the sum of these two values forms the new lower part (value_lo) of the result.
value_lo = (lower_bits(value_hi, shift_factor as usize) << (32 - shift_factor)) as u64
+ (value_lo * mult_factor as u64)
>> shift_factor;

// the right-shifted value_hi and the upper 32 bits of value_lo form the new higher part (value_hi) of the
// result.
value_hi = (value_hi >> shift_factor) + upper_bits(value_lo, 32);

// the lower 32 bits of value_lo form the new lower part of the result.
value_lo = lower_bits(value_lo, 32);

// return the result as a fixed-point number composed of two 64-bit integers
(value_hi, value_lo)
}

// if value == 0 or n == 0 {
// return value
// }

// split the value into two uint64 variables to prevent overflowing
let mut value_hi = upper_bits(value, 32);
let mut value_lo = lower_bits(value, 32);

// we keep applying the lookup table factors as long as n epochs are left
let mut remaining_epochs = n;

while remaining_epochs > 0 {
let mut epochs_to_decay = remaining_epochs;

if epochs_to_decay > 365 {
epochs_to_decay = 365
}
Comment on lines +109 to +113

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mut epochs_to_decay = remaining_epochs;
if epochs_to_decay > 365 {
epochs_to_decay = 365
}
let epochs_to_decay = remaining_epochs.max(365);

Copy link

@DaughterOfMars DaughterOfMars Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or should this be using decay_factors.len()?

remaining_epochs -= epochs_to_decay;

let decay_factor = self.decay_factor_at(epochs_to_decay).unwrap();

// apply the decay using fixed-point arithmetics.
(value_hi, value_lo) =
multiplication_and_shift(value_hi, value_lo, decay_factor, self.decay_factors().len() as u8);
}

// combine both uint64 variables to get the actual value
value_hi << 32 + value_lo

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
value_hi << 32 + value_lo
value_hi << 32 | value_lo

}
}

impl Default for ManaStructure {
Expand Down
21 changes: 11 additions & 10 deletions sdk/src/types/block/output/feature/block_issuer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ impl Ed25519BlockIssuerKey {
/// The block issuer key kind of an [`Ed25519BlockIssuerKey`].
pub const KIND: u8 = 0;
/// Length of an ED25519 block issuer key.
pub const PUBLIC_KEY_LENGTH: usize = ed25519::PublicKey::LENGTH;
pub const LENGTH: usize = ed25519::PublicKey::LENGTH;

/// Creates a new [`Ed25519BlockIssuerKey`] from bytes.
pub fn try_from_bytes(bytes: [u8; Self::PUBLIC_KEY_LENGTH]) -> Result<Self, Error> {
pub fn try_from_bytes(bytes: [u8; Self::LENGTH]) -> Result<Self, Error> {
Ok(Self(ed25519::PublicKey::try_from_bytes(bytes)?))
}
}
Expand All @@ -94,7 +94,7 @@ impl Packable for Ed25519BlockIssuerKey {
unpacker: &mut U,
visitor: &Self::UnpackVisitor,
) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
Self::try_from_bytes(<[u8; Self::PUBLIC_KEY_LENGTH]>::unpack::<_, VERIFY>(unpacker, visitor).coerce()?)
Self::try_from_bytes(<[u8; Self::LENGTH]>::unpack::<_, VERIFY>(unpacker, visitor).coerce()?)
.map_err(UnpackError::Packable)
}
}
Expand Down Expand Up @@ -148,11 +148,11 @@ impl IntoIterator for BlockIssuerKeys {
}

impl BlockIssuerKeys {
/// The minimum number of block_issuer_keys in a [`BlockIssuerFeature`].
/// The minimum number of block issuer keys in a [`BlockIssuerFeature`].
pub const COUNT_MIN: u8 = 1;
/// The maximum number of block_issuer_keys in a [`BlockIssuerFeature`].
/// The maximum number of block issuer keys in a [`BlockIssuerFeature`].
pub const COUNT_MAX: u8 = 128;
/// The range of valid numbers of block_issuer_keys.
/// The range of valid numbers of block issuer keys.
pub const COUNT_RANGE: RangeInclusive<u8> = Self::COUNT_MIN..=Self::COUNT_MAX; // [1..128]

/// Creates a new [`BlockIssuerKeys`] from a vec.
Expand Down Expand Up @@ -186,9 +186,9 @@ impl BlockIssuerKeys {
#[derive(Clone, Debug, Eq, PartialEq, Hash, packable::Packable)]
#[packable(unpack_error = Error)]
pub struct BlockIssuerFeature {
/// The slot index at which the Block Issuer Feature expires and can be removed.
/// The slot index at which the feature expires and can be removed.
expiry_slot: SlotIndex,
/// The Block Issuer Keys.
/// The block issuer keys.
block_issuer_keys: BlockIssuerKeys,
}

Expand All @@ -204,18 +204,19 @@ impl BlockIssuerFeature {
) -> Result<Self, Error> {
let block_issuer_keys =
BlockIssuerKeys::from_vec(block_issuer_keys.into_iter().collect::<Vec<BlockIssuerKey>>())?;

Ok(Self {
expiry_slot: expiry_slot.into(),
block_issuer_keys,
})
}

/// Returns the Slot Index at which the Block Issuer Feature expires and can be removed.
/// Returns the expiry slot.
pub fn expiry_slot(&self) -> SlotIndex {
self.expiry_slot
}

/// Returns the Block Issuer Keys.
/// Returns the block issuer keys.
pub fn block_issuer_keys(&self) -> &[BlockIssuerKey] {
&self.block_issuer_keys
}
Expand Down
Loading