232
(which is equivalent, by contruction to 0≤`Decay Factors Exponent`≤3),
+- `slotIndexDiff * Generation Rate`< 232
,
+- `Decay Factor Epochs Sum * Generation Rate`< 232
.
diff --git a/tips/TIP-0039/img/data_flow_overview.png b/tips/TIP-0039/img/data_flow_overview.png
new file mode 100644
index 000000000..8eefd208e
Binary files /dev/null and b/tips/TIP-0039/img/data_flow_overview.png differ
diff --git a/tips/TIP-0039/img/slots_potential_mana-2.png b/tips/TIP-0039/img/slots_potential_mana-2.png
new file mode 100644
index 000000000..30772b644
Binary files /dev/null and b/tips/TIP-0039/img/slots_potential_mana-2.png differ
diff --git a/tips/TIP-0039/img/slots_potential_mana.png b/tips/TIP-0039/img/slots_potential_mana.png
new file mode 100644
index 000000000..bce7c8186
Binary files /dev/null and b/tips/TIP-0039/img/slots_potential_mana.png differ
diff --git a/tips/TIP-0039/tip-0039.md b/tips/TIP-0039/tip-0039.md
new file mode 100644
index 000000000..caa460fec
--- /dev/null
+++ b/tips/TIP-0039/tip-0039.md
@@ -0,0 +1,528 @@
+---
+tip: 39
+title: Mana for IOTA 2.0
+description: Define Mana, Mana dynamics, and other Mana-related concepts in the IOTA 2.0 protocol
+author:
+ Olivia Saa (@oliviasaa) 2Slots Per Epoch Exponent
slots, the epoch changes, meaning that every set of consecutive
+2Slots Per Epoch Exponent
slots will be in the same epoch.
+
+The decay parameter `Annual Decay` (together with the Mana generation parameter `Mana Structure::Generation Rate`) was
+set so the maximum theoretical Mana in the system is smaller than 2Bits Count - 1
, where
+`Bits Count` refers to the `Mana Structure::Bits Count` protocol parameter. This means that, even though Mana is stored
+as a uint64, it effectively uses less than 64 bits (in the case of BIC, it uses at most `Bits Count + 1` bits,
+`Bits Count` for the value and one for the sign). Note that the system will almost certainly never use all the
+`Bits Count` to store Mana since, for the Mana supply to get to this value, nobody can spend their Mana for years. In
+practice, we expect to work with Mana values way smaller than 2Bits Count - 1
; however, we must
+count on what would be an unreasonably large value in practice to avoid overflowing of the variables even if with a
+minimal probability.
+
+### Mana Decay Parameters
+
+The tables below describe the key parameters used for the Mana decay calculations in the next sections of this TIP.
+Notice that the parameters in the first table are only used in the explanations in this TIP, but not explicitly in the
+code.
+
+Name | +Description | +
Annual Decay |
+ + Global annual decay parameter. + | +
γ |
+ + Defines fixed potential Mana generation per slot. + | +
Decay per Epoch = Annual Decay(Seconds per Epoch/Seconds per Year)
+
+where
+
+- `Seconds per Year = 60*60*24*365`
+- Seconds per Epoch = Slot Duration In Seconds * 2Slots Per Epoch Exponent
+
+## Mana and fixed point arithmetics
+
+Floating point operations might lead to inconsistencies among results in different nodes due to the different rounding
+behaviors in different architectures. The results of the operations involving floating point variables might differ by
+amounts that are considered negligible for the modules that deal with local decisions (as the congestion control module,
+for example); however, differences that would be considered negligible by those modules can be fatal for the transaction
+validation and slot commitments, leading to forks and other undesirable behaviors in the system. For that reason, fixed
+point arithmetics (which do not expose the nodes to these rounding divergencies) must be used in all the modules that
+require exact consensus over values. In particular, all the Mana and rewards calculations have to be done with fixed
+point arithmetics.
+
+### Lookup Table
+
+The derivation of the `Mana Parameters::Decay Factors` protocol parameter, also referred to as the _lookup table_ is
+described in the present section. This parameter must be calculated exactly once for a network's protocol parameters
+to avoid differences in floating point operations on different machines. This Table is provided in the snapshot files;
+thus, its definition is explained here just for the sake of clarification. The values on the table **must not** be
+calculated locally in the node or any application to avoid inconsistencies in the calculations.
+
+The lookup table is an integer approximation of 2Decay Factors ExponentDecay per
+Epochn
, for different values of `n` ranging from 1 to `Decay Factors Length`.
+In general lines, to obtain the decayed value of a certain amont of Mana `M` after `n` epochs have been passed, the
+basic idea is to multiply `M` by the entry of `Mana Parameters::Decay Factors` relative to `n` and then execute a
+right shift of `Decay Factors Exponent` bits.
+However, in some cases, a slighly more complex algorithm must be used, which we define in the next section.
+
+### Decay Function
+
+In this section, we define a function `Decay(value, epochIndexDiff)`, that decays an amount of Mana `value` by the
+factor relative to `epochIndexDiff` epochs. Note that the table `Decay Factors` defined above only gives the values of
+decays factors for up to `Decay Factors Length` epochs. To calculate the decay for larger periods of time, we combine
+values defined in the [lookup table](#lookup-table) for other numbers smaller than `Decay Factors Length`, using an
+algorithm that will be defined below. First, we define three auxiliary functions:
+
+- Let `Upper Bits(value, n)` be: given a uint64 integer `value`, returns its upper `n` bits
+- Let `Lower Bits(value, n)` be: given a uint64 integer `value`, returns its lower `n` bits
+- `Multiplication And Shift(valueHi, valueLo, multFactor, shiftFactor)`: the goal of this function is to return the
+ result
+- of a multiplication of a uint64 by a uint32, shifted `shiftFactor` times to the right, whenever this result is smaller
+- than 264
. To do so, it uses the following algorithm:
+ - Let `valueHi` and `valueLo` be the upper and lower 32 bits of an integer smaller than 264
,
+ `multFactor` be an integer smaller than 232
, and `shiftFactor` be an integer between 0
+ and 32.
+ - Let `>>` be a right shift (thus, `>>n` means shifting to the right `n` times). Analogously, let `<<` be a left
+ shift.
+ - Then compute `valueHi = valueHi * multFactor`.
+ - Then compute
+ `valueLo = Lower Bits(valueHi, shiftFactor) << (32 - shiftFactor) + (valueLo * multFactor) >> shiftFactor`.
+ - Then compute `valueHi = (valueHi >> shiftFactor) + Upper Bits(valueLo, 32)`.
+ - Then compute `valueLo = Lower Bits(valueLo, 32)`.
+ - Return `(valueHi<<32) + valueLo`, representing the result.
+
+With the functions above defined, we proceed to define the `Decay` function that takes as input a uint64 value `value`
+and decays it by the correct decay factor relative to `epochIndexDiff` epochs. OBS: note that here,
+`Decay Factors(epochIndexDiff)` denotes the value of the table relative to `epochIndexDiff` epochs, which not
+necessarily corresponds to the `epochIndexDiff`th entry of the table.
+
+- Let `Decay(value, epochIndexDiff)` be:
+ - If `value == 0` or `epochIndexDiff == 0`, return `value`.
+ - Else:
+ - Let `m` and `n` be natural numbers such that `m + n * Decay Factors Length = epochIndexDiff`, and
+ `m < Decay Factors Length`.
+ - Apply
+ `value = Multiplication And Shift(Upper Bits(value, 32), Lower Bits(value, 32), Decay Factors(Decay Factors Length), Decay Factors Exponent)`
+ `n` times.
+ - Apply `value = Multiplication And Shift(Upper Bits(value, 32), Lower Bits(value, 32), Decay Factors(m), Decay Factors Exponent)`
+ once.
+ - Return `value`.
+
+Other implementations of the functions above are possible; however, one must be careful with the order of operations,
+which must be done as defined above. Having a well-defined order is crucial since sequences of divisions and
+multiplications with integers variables might lead to different results when the order is altered.
+
+## Potential Mana
+
+_Potential Mana_ is a form of Mana generated from IOTA coins over time. Every IOTA coin (besides storage deposits)
+generates potential Mana. The view on the potential Mana value can be deterministically derived from the UTXO ledger,
+based on the UTXO IOTA coin value and the time it was created, which corresponds to the `Creation Slot` of the
+transaction that created the UTXO.
+
+### Rationale behind the Potential Mana formulas
+
+We model the potential Mana generated by an output holding `S` IOTA coins as the combination of a fixed generation per
+slot `γS` and a decay equivalent to a multiplication by Decay per Epoch
every time an epoch ends.
+
+![Creation and consumption slots of an output](./img/slots_potential_mana-2.png)
+
+Let `i` be the epoch of the creation slot and `j` be the epoch of the consumption slot. Let `n=j-i`, and for the sake of
+the explanation, assume `n`>1. All the Mana generated in epoch `i` "crosses" n decay boundaries; thus, it must be
+decayed `n` times. The Mana generated in epoch `i+1` "crosses" n-1 decay boundaries, so it must be decayed n-1 times,
+and so on, until the Mana generated in epoch `j`, which is not decayed at all. Adding these values, we find the
+following formulas (where d is the number of slots in an epoch):
+
+Potential Mana = γSd1 Decay per Epochn + ΣγSd Decay per Epochi +
+γSd2
, where the summation is over
+i = 1,...,n-1
.
+
+Solving the sum, this results:
+
+Potential Mana = γSd1 Decay per Epochn + γSd2 + γSd Decay per Epoch (1 - Decay
+per Epochn-1) / (1-Decay per Epoch)
,
+
+Analogously, if `n=1`, Potential Mana = γSd1 Decay per Epoch + γSd2
; if `n=0`,
+Potential Mana = γSδ
, where δ
is the difference between the creation and consumption slots.
+
+### Potential Mana formulas with fixed point arithmetics
+
+The formulas found in the last section are the exact formulas for the model proposed. However, we must not use floating
+point arithmetics, so these formulas must be adapted for the implementation. We begin by rearranging the formula for
+n>1, noticing that we already approximated 2 `Decay Factors Exponent` Decay per
+Epochi
by `Decay Factors(i)`, where `Decay Factors Exponent` is the precision of the
+[lookup table](#lookup-table) used. The parameter `γ` is then represented as
+`Generation Rate`*2-`Generation Rate Exponent`
, and
+Decay per Epoch/(1 - Decay per Epoch)
is approximated by
+ `Decay Factor Epochs Sum`*2-`Decay Factor Epochs Sum Exponent`
. For additional explanations
+about these approximations, see the
+[Incentives Whitepaper](https://files.iota.org/papers/IOTA_2.0_Incentives_And_Tokenomics_Whitepaper.pdf).
+
+We begin by defining an auxiliary procedure `Generate Mana` that (intuitively) generates Mana without applying any type
+of decay (note that we use some of the procedures and constants defined in the last sections):
+
+- `Generate Mana(value,slotIndexDiff)` returns the generated mana from holding `value` tokens for `slotIndexDiff` slots,
+ without applying any decay:
+ - if `slotIndexDiff` == 0 or `Generation Rate` == 0, the procedure returns `0`
+ - otherwise, it returns `Multiplication And Shift(Upper Bits(value, 32), Lower Bits(value, 32), slotIndexDiff * Generation Rate, Generation Rate Exponent)`.
+
+This means that `slotIndexDiff * Generation Rate` must be an integer smaller than 2 `32`
and
+`Generation Rate Exponent` must be an integer between 0 and 32.
+Now we define the procedure `Potential Mana` that actually calculates the Potential Mana using the formulas defined in
+the last section (including the decays):
+
+Let `Potential Mana(Amount, Output Creation Slot, Transaction Creation Slot)` be the procedure that calculates the
+Potential Mana generated by holding `Amount` IOTA coins from `Output Creation Slot` to `Transaction Creation Slot` and
+applies the decay to the result, where:
+
+- `Amount` is the amount of IOTA coins held in the output.
+- `Output Creation Slot` is the slot index in which the output was created.
+- `Transaction Creation Slot` is the slot index in which the output is consumed.
+- If `Output Creation Slot ≥ Transaction Creation Slot` return `0`.
+- Otherwise:
+ - Let `Output Creation Epoch` be the epoch to which `Output Creation Slot` belongs.
+ - Let `Transaction Creation Epoch` be the epoch to which `Transaction Creation Slot` belongs.
+ - See [TIP-46 (Time)](TIP-0046/tip-0046.md#time) for the conversion procedure.
+ - If `Output Creation Epoch == Transaction Creation Epoch`:
+ - Return `Generate Mana(Amount, Transaction Creation Slot - Output Creation Slot)`.
+ - Let `Slots Before Next Epoch` be the difference between `Output Creation Slot` and the first slot of epoch
+ `Output Creation Epoch + 1`.
+ - Let `Slots Since Epoch Start` be the difference between `Transaction Creation Slot` and the last slot of epoch
+ `Transaction Creation Epoch - 1`.
+ - If `Output Creation Epoch == Transaction Creation Epoch - 1`:
+ - Return `Mana Decayed + Mana Generated`, where
+ - `Mana Decayed = Decay(Generate Mana(Amount, Slots Before Next Epoch), 1)`
+ - `Mana Generated = Generate Mana(Amount, Slots Since Epoch Start)`
+ - If `Output Creation Epoch < Transaction Creation Epoch - 1`:
+ - Let `Epoch Index Diff` be `Transaction Creation Epoch - Output Creation Epoch`.
+ - Return
+ `Potential Mana First Epoch + Potential Mana Intermediate Epochs + Potential Mana Last Epoch - Correction Term`,
+ where
+ - `Potential Mana First Epoch = Decay(Generate Mana(Amount, Slots Before Next Epoch), Epoch Index Diff)`
+ - `Potential Mana Intermediate Epochs = c - c2`
+ - `Potential Mana Last Epoch = Generate Mana(Amount, Slots Since Epoch Start)`
+ - `Correction Term = c >> Decay Factors Exponent`
+ - `c = Multiplication And Shift(Upper Bits(Amount, 32), Lower Bits(Amount, 32), Decay Factor Epochs Sum * Generation Rate , Decay Factor Epochs Sum Exponent+generationRateExponent-slotsPerEpochExponent)`.
+ - `c2 = Decay(c, Epoch Index Diff - 1)`
+
+## Stored Mana
+
+_Stored Mana_ is the main form of Mana. It is a UTXO-based form (i.e., it is contained in outputs, just like IOTA coins)
+of Mana that can be transferred within certain rules between different users, which allows for the development of a Mana
+market.
+
+All output types, except Foundry and Delegation Outputs, can hold Stored Mana in the _Mana_ field. This field represents
+the amount of stored Mana at the output's creation time until the time when the output is consumed without decay applied
+to it.
+
+Decay must, therefore, be applied whenever an output containing Stored Mana is consumed.
+
+Let `Stored Mana(Mana Amount, Output Creation Slot, Transaction Creation Slot)` be the procedure that calculates the
+decay whenever Stored Mana is consumed, where:
+
+- `Mana Amount` is the amount of Stored Mana held in an output.
+- `Output Creation Slot` is the slot index in which the output was created.
+- `Transaction Creation Slot` is the slot index in which the output is consumed.
+- Let `Output Creation Epoch` be the epoch to which `Output Creation Slot` belongs.
+- Let `Transaction Creation Epoch` be the epoch to which `Transaction Creation Slot` belongs.
+ - See [TIP-46 (Time)](TIP-0046/tip-0046.md#time) for the conversion procedure.
+- If `Output Creation Epoch == Transaction Creation Epoch` return `Mana Amount`.
+- Otherwise return `Decay(Mana Amount, Transaction Creation Epoch - Output Creation Epoch)`.
+
+## Block Issuance Credit
+
+_Block Issuance Credit (BIC)_ Mana is used for congestion control, i.e., to pay for blocks to be scheduled and gossiped
+around the network and seen by everyone. Congestion control manages which blocks should be gossiped to neighbors based
+on Mana burned from the block issuance credits by the block. It is important to distinguish between **blocks** and
+**transactions**: congestion control only deals with blocks, which are the containers that carry transactions around the
+network. It does not care about the transactions inside the blocks.
+
+The example below shows a ledger with a conflicting branch (perhaps due to a double spend), so only one branch (either
+the set of red or the set of green transactions) can ultimately modify the ledger, but never both. However, all these blocks
+must be gossiped, whether they contain red or green transactions. Thus, they must pay for the BIC used to get through
+schedulers regardless of whether the transaction within modifies the ledger. This is why BIC cannot be burned by a
+transaction - it can only be burned by a block.
+
+![Data flow overview](./img/data_flow_overview.png)
+
+Because a block cannot modify the UTXO ledger but only the Mana balances, the amount burnt by a block must be deducted
+from the account's BIC balance. The BIC is stored in an accounts ledger;
+i.e., a map from the Account IDs to the block issuers' data,
+including the BIC balance, the block issuer keys and the Block Issuer Feature expiration (among other data).
+The BIC balance of an account can only be modified in two ways:
+
+- BIC is subtracted from the ledger when the corresponding account issues a block signed by one of its Block Issuer Keys.
+- BIC is increased in the ledger when a transaction allots Mana to that account.
+
+Updates to the BIC balance happen upon slot commitments. Mana Decay is applied to the BIC of the accounts whose BIC was
+changed in that slot.
+
+### Block Issuance Credit Semantic Validation
+
+When applying Mana Decay to BIC at the end of a slot, it must be applied as follows:
+
+- Let `i` be a slot where the BIC of an account `account` was changed.
+Let `BIC(i)` be the amount of BIC held by `account` at the end of slot `i`.
+- Suppose that slot `i+d` is the first slot after `i` that the BIC of `account` is changed.
+- Suppose in this slot, the account issued a block (thus, burning `burnt BIC` BIC) containing a transaction that allots
+`allotted BIC` BIC to the same account.
+- Let `epoch(i)` and `epoch(i+d)` be the epochs to which slots `i` and `i+d` belong, respectively.
+- Since `allotted BIC` was already decayed (otherwise, the transaction allotting this BIC would fail its
+[transaction validation rules](#mana-transaction-validation-rules)), only the previous value of BIC must be decayed,
+relative to the last slot it was decayed in, by applying:
+ - `decayed old BIC = Decay(BIC(i), epoch(d+i)-epoch(i))`
+- Then, the balance is updated with the burnt and allotted amounts:
+ - `BIC(i+d) = decayed old BIC + allotted BIC - burnt BIC`
+
+TO DO: talk to Andrew about where exactly the BIC balance is checked.
+
+## Mana Transaction Validation Rules
+
+A transaction can only be valid if either of the following conditions holds (note that these are not the _only_
+conditions for a transaction to be valid, but the ones relative to Mana balances):
+
+- `Total Mana In == Total Mana Out`.
+- `Total Mana In > Total Mana Out` and the _Can Burn Mana_ Flag in the _Transaction Capabilities_ is **set**.
+
+where `Total Mana In` and `Total Mana Out` are defined as follows:
+
+- Let `Transaction Creation Slot` be the `Creation Slot` of the transaction being validated. For each input `i`
+of the transaction, we define:
+ - `Input Creation Slot(i)` is the `Creation Slot` of the transaction that created each input `i`.
+ - `Amount(i)` is the `Amount` of input `i` .
+ - `Min Deposit(i)` is the minimum necessary storage deposit of `i`.
+ - `Stored Mana_i` is the `Mana` of `i`.
+ - `Generation Amount(i)` is defined as `Amount(i) - Min Deposit(i)`, if `Min Deposit(i) < Amount(i)`, and `0` otherwise.
+
+- Then, `Total Mana Out` will be the total amount of Mana on the output side of a transaction, consisting of
+ `Total Stored Mana + Total Allotted Mana`, where:
+ - `Total Stored Mana` is the sum of `Mana` fields for each output.
+ - `Total Allotted Mana` is the sum of `Mana` fields for each _Allotment_.
+- Additionally, `Total Mana In` will be the total amount of Mana relative to the input side of a transaction, consisting of
+ `Total Potential Mana + Total Stored Mana + Total Mana Rewards`, where:
+ - `Total Potential Mana` is the sum of the generated Potential Mana for each input `i`.
+ Each of those Potential Mana factors are calculated as
+ `Potential Mana(Generation Amount(i), Input Creation Slot(i), Transaction Creation Slot)` according to [Potential Mana](#potential-mana).
+ - `Total Stored Mana` is the sum of Stored Mana for each input `i`.
+ Each of those Stored Mana factors are calculated as `Stored Mana(Stored Mana(i), Input Creation Slot(i), Transaction Creation Slot)`.
+ - `Total Mana Rewards` is the sum of total claimable rewards from each input referenced by a _Reward Input_ in the transaction,
+ each of which is calculated as follows:
+ - If the pointee of the _Reward Input_ is an _Account Output_ with its `Account ID`, the rewards are calculated with
+ [`Validator Rewards(Account ID)`](../TIP-0040/tip-0040.md#validator-rewards).
+ - If the pointee of the _Reward Input_ is a _Delegation Output_ with its `Delegation ID`, the rewards are calculated
+ with [`Delegation Rewards(Delegation ID)`](../TIP-0040/tip-0040.md#delegator-rewards).
+
+| :warning: Potential Overflows |
+| ----------------------------- |
+
+It is highly recommended to use overflow checks for arithmetic operations when calculating Mana balances to avoid over-
+and underflows.
+
+# Test Vectors
+
+The protocol parameters used in the following test vectors are the same as in
+[TIP-49](../TIP-0049/tip-0049.md#protocol-parameters-hash).
+
+## Vectors for Mana Generation
+
+The following structure consists of a base token `amount` to which the [Potential Mana Generation](#potential-mana)
+formula is applied with the given slots, resulting in the generated `potentialMana` value.
+
+```json
+{
+ "testVectors": [
+ {
+ "amount": "1000000000",
+ "outputCreationSlot": 1,
+ "transactionCreationSlot": 10000,
+ "potentialMana": "76228441"
+ },
+ {
+ "amount": "1000000000",
+ "outputCreationSlot": 9000,
+ "transactionCreationSlot": 10000,
+ "potentialMana": "7629394"
+ },
+ {
+ "amount": "800000000000000000",
+ "outputCreationSlot": 1,
+ "transactionCreationSlot": 10000,
+ "potentialMana": "60982753715241244"
+ },
+ {
+ "amount": "800000000000000000",
+ "outputCreationSlot": 9000,
+ "transactionCreationSlot": 10000,
+ "potentialMana": "6103515625000000"
+ }
+ ]
+}
+```
+
+## Vectors for Mana Decay
+
+The following structure consists of a `mana` value to which the [Decay function](#decay-function) is applied with
+`epochIndexDiff = targetEpoch - creationEpoch`, resulting in the `decayedMana` value.
+
+```json
+{
+ "testVectors": [
+ {
+ "mana": "25000000000",
+ "creationEpoch": 1,
+ "targetEpoch": 1000,
+ "decayedMana": "9907379812"
+ },
+ {
+ "mana": "25000000000",
+ "creationEpoch": 900,
+ "targetEpoch": 1000,
+ "decayedMana": "22787760727"
+ },
+ {
+ "mana": "9000000000000000",
+ "creationEpoch": 1,
+ "targetEpoch": 1000,
+ "decayedMana": "3566656732891364"
+ },
+ {
+ "mana": "9000000000000000",
+ "creationEpoch": 900,
+ "targetEpoch": 1000,
+ "decayedMana": "8203593862010166"
+ }
+ ]
+}
+```
+
+# Copyright
+
+Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).