diff --git a/tips/TIP-0039/constraints.md b/tips/TIP-0039/constraints.md new file mode 100644 index 000000000..ddfe7b99a --- /dev/null +++ b/tips/TIP-0039/constraints.md @@ -0,0 +1,26 @@ + +# Parameters constraints + +Due to the use of fixed point arithmetics, some contraints on the Mana parameters are needed to prevent overflowing of the variables used for the Mana decay and generation calculations. + +In particular, the function `Multiplication And Shift(valueHi, valueLo, multFactor, shiftFactor)` is applied to the following variables: + +- `Multiplication And Shift(Upper Bits(value, 32), Lower Bits(value, 32), Decay Factors(m), Decay Factors Exponent)`. +- `Multiplication And Shift(Upper Bits(value, 32), Lower Bits(value, 32), slotIndexDiff * Generation Rate, Generation Rate Exponent)`. +- `Multiplication And Shift(Upper Bits(Amount, 32), Lower Bits(Amount, 32), Decay Factor Epochs Sum * Generation Rate , Decay Factor Epochs Sum Exponent+generationRateExponent-slotsPerEpochExponent)`. +By contruction, `Upper Bits(Amount, 32)` and `Upper Bits(Amount, 32)` will always use at most 32 bits (given that `Amount` uses at most 64 bits). + +Since `shiftFactor` must be an integer between 0 and 32, we have: + +- 0≤`Decay Factors Exponent`≤32. +- 0≤`Generation Rate Exponent`≤32. +- 0≤`Decay Factor Epochs Sum Exponent+generationRateExponent-slotsPerEpochExponent`≤32. + +The third variable `multFactor` must additionally use at most 32 bits, meaning that we have the following constraints: + +- `Decay Factors(m)`< 232 (which is equivalent, by contruction to 0≤`Decay Factors Exponent`≤3), +- `slotIndexDiff * Generation Rate`< 232, +- `Decay Factor Epochs Sum * Generation Rate`< 232, + + +TO DO: Rewards and maximum theoretical Mana in the system is smaller than 2Bits Count - 1 diff --git a/tips/TIP-0039/tip-0039.md b/tips/TIP-0039/tip-0039.md index 24dc73f4e..caa460fec 100644 --- a/tips/TIP-0039/tip-0039.md +++ b/tips/TIP-0039/tip-0039.md @@ -68,7 +68,7 @@ It is an essential element of the IOTA protocol, as it is used: - [**Block Issuance Credit**](#block-issuance-credit) (BIC) is the form of Mana used as an anti-spam mechanism to the block issuance process. During a transaction, Stored or Potential Mana can be _allotted as BIC_, which moves the Mana off the UTXO ledger and converts it to Block Issuance Credits. Only this form of Mana can be burnt to issue blocks. -- [**Mana Rewards**](#mana-rewards) reward participation in staking for validation and delegating IOTA coins. The Mana +- [**Mana Rewards**] reward participation in staking for validation and delegating IOTA coins. The Mana rewarded from these activities is not registered automatically in the UTXO ledger; thus, rewards must be claimed, as described in [TIP-40](../TIP-0040/tip-0040.md##mana-rewards). @@ -155,12 +155,6 @@ code. Defines fixed potential Mana generation per slot. - - Δ - - The duration of an epoch in years. - - Additionally, we use the protocol parameters, as defined in [TIP-49], and `Decay Factors Length`, defined as the length @@ -189,13 +183,15 @@ point arithmetics. 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. +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 has 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. +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 @@ -222,7 +218,7 @@ algorithm that will be defined below. First, we define three auxiliary functions `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, valueLo`, representing the upper 32 and the lower 32 bits, respectively, of the result. + - 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, @@ -232,16 +228,14 @@ 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 `valueHi = Upper Bits(value, 32)` and `valueLo = Lower Bits(value, 32)`. - Let `m` and `n` be natural numbers such that `m + n * Decay Factors Length = epochIndexDiff`, and `m < Decay Factors Length`. - Apply - `valueHi, valueLo = Multiplication And Shift(valueHi, valueLo, Decay Factors(Decay Factors Length), Decay Factors Exponent)` + `value = Multiplication And Shift(Upper Bits(value, 32), Lower Bits(value, 32), Decay Factors(Decay Factors Length), Decay Factors Exponent)` `n` times. - - Apply `valueHi, valueLo = Multiplication And Shift(valueHi, valueLo, Decay Factors(m), Decay Factors Exponent)` + - Apply `value = Multiplication And Shift(Upper Bits(value, 32), Lower Bits(value, 32), Decay Factors(m), Decay Factors Exponent)` once. - - The function should return `valueHi, valueLo` combined into a single `uint64`, i.e., it returns - `valueHi << 32 + valueLo`. + - 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 @@ -259,7 +253,7 @@ transaction that created the UTXO. 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. -![](./img/slots_potential_mana-2.png) +![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 @@ -298,8 +292,10 @@ of decay (note that we use some of the procedures and constants defined in the l - `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(value, slotIndexDiff * Generation Rate, Generation Rate Exponent)`. + - 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): @@ -370,74 +366,79 @@ on Mana burned from the block issuance credits by the block. It is important to 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, not both. However, all these blocks +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. -![](./img/data_flow_overview.png) +![Data flow overview](./img/data_flow_overview.png) -Because a block cannot modify the UTXO ledger but the Mana the block burns must be deducted from the account's BIC -balance, the BIC is stored in an accounts ledger. This ledger is a map from an Account ID to block issuer data, which -includes the BIC balance, the block issuer keys and when the Block Issuer Feature expires among other data. This -separate ledger is partly derived from the Block Issuer Feature in an account in the UTXO ledger. The BIC balance of an -account can only be modified in two ways: +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 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 for the accounts whose BIC was +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 `BIC_i` be the amount of BIC held by the account at the end of slot `i`. Since all additions of allotted BIC - were already decayed in that slot, only the previous value of BIC must be decayed, relative to the last slot it was - decayed in, by applying: +When applying Mana Decay to BIC at the end of a slot, it must be applied as follows: -TODO: This function doesn't take into account the last time the BIC was decayed and the current time. +- 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` -```go -if BIC > 0: - new_BIC = Decay(BIC, 1) -else: - new_BIC = BIC -``` +TO DO: talk to Andrew about where exactly the BIC balance is checked. ## Mana Transaction Validation Rules -- Let `Total Mana In` be the total amount of Mana on the input side of a transaction, consisting of +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: - - `Transaction Creation Slot` is the `Creation Slot` of the transaction, - - `Output Creation Slot` is the `Creation Slot` of the transaction that created the output. - - `Total Potential Mana` is the sum of Potential Mana for each input `i`: - - where its Potential Mana is calculated as - `Potential Mana(Generation Amount, Output Creation Slot, Transaction Creation Slot)` according to - [Potential Mana](#potential-mana) where: - - `Generation Amount` is defined as `Amount_i - Min Deposit`, if `Min Deposit < Amount_i`, otherwise `0`, where: - - `Amount_i` is the `Amount` of `i`, - - `Min Deposit` is the minimum necessary storage deposit of `i`. - - `Total Stored Mana` is the sum of Stored Mana for each input `i`: - - where its Stored Mana is calculated as - `Stored Mana(Stored Mana_i, Output Creation Slot, Transaction Creation Slot)`, where: - - `Stored Mana_i` is the `Mana` of `i`. - - `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: + - `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). -- Let `Total Mana Out` 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_. - -A transaction is only valid if either of the following conditions holds: - -- `Total Mana In == Total Mana Out`. -- `Total Mana In > Total Mana Out` and the _Can Burn Mana_ Flag in the _Transaction Capabilities_ is **set**. | :warning: Potential Overflows | | ----------------------------- | @@ -450,7 +451,7 @@ and underflows. The protocol parameters used in the following test vectors are the same as in [TIP-49](../TIP-0049/tip-0049.md#protocol-parameters-hash). -## Mana Generation +## 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. @@ -486,7 +487,7 @@ formula is applied with the given slots, resulting in the generated `potentialMa } ``` -## Mana Decay +## 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.