diff --git a/sdk/src/types/block/mana/structure.rs b/sdk/src/types/block/mana/structure.rs index 68d926884a..6d1204675f 100644 --- a/sdk/src/types/block/mana/structure.rs +++ b/sdk/src/types/block/mana/structure.rs @@ -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 { - self.decay_factors.get(*epoch_index as usize).copied() + pub fn decay_factor_at(&self, epoch_index: impl Into) -> Option { + 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) + } + + /// 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 + } + 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 + } } impl Default for ManaStructure { diff --git a/sdk/src/types/block/output/feature/block_issuer.rs b/sdk/src/types/block/output/feature/block_issuer.rs index c7682bdf33..5f86e3931f 100644 --- a/sdk/src/types/block/output/feature/block_issuer.rs +++ b/sdk/src/types/block/output/feature/block_issuer.rs @@ -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 { + pub fn try_from_bytes(bytes: [u8; Self::LENGTH]) -> Result { Ok(Self(ed25519::PublicKey::try_from_bytes(bytes)?)) } } @@ -94,7 +94,7 @@ impl Packable for Ed25519BlockIssuerKey { unpacker: &mut U, visitor: &Self::UnpackVisitor, ) -> Result> { - 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) } } @@ -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 = Self::COUNT_MIN..=Self::COUNT_MAX; // [1..128] /// Creates a new [`BlockIssuerKeys`] from a vec. @@ -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, } @@ -204,18 +204,19 @@ impl BlockIssuerFeature { ) -> Result { let block_issuer_keys = BlockIssuerKeys::from_vec(block_issuer_keys.into_iter().collect::>())?; + 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 }