diff --git a/tips/TIP-0040/assets/delayed-claiming.png b/tips/TIP-0040/assets/delayed-claiming.png new file mode 100755 index 000000000..5335261f7 Binary files /dev/null and b/tips/TIP-0040/assets/delayed-claiming.png differ diff --git a/tips/TIP-0040/assets/delegation-epochs.png b/tips/TIP-0040/assets/delegation-epochs.png new file mode 100755 index 000000000..f694163e0 Binary files /dev/null and b/tips/TIP-0040/assets/delegation-epochs.png differ diff --git a/tips/TIP-0040/assets/selection-timing.png b/tips/TIP-0040/assets/selection-timing.png new file mode 100644 index 000000000..e37d733a6 Binary files /dev/null and b/tips/TIP-0040/assets/selection-timing.png differ diff --git a/tips/TIP-0040/constraints.md b/tips/TIP-0040/constraints.md new file mode 100644 index 000000000..e19985e13 --- /dev/null +++ b/tips/TIP-0040/constraints.md @@ -0,0 +1,165 @@ +# Parameters constraints + +Due to the use of fixed point arithmetics, some contraints on the rewards parameters are needed to prevent overflowing of the variables used for the calculations. + +## Constraints on the Mana Supply + +The first and most straighforward contraint is that the total maximum theoretical Mana in the system should not use more than $\text{Bits Count}$ bits. + +Let's start by calculating the Mana in the system generated by holding tokens $\text{Mana Holders}(n)$ until epoch $n$. + +$$ +\text{Mana Holders}(n)=\frac{\text{Token Supply} * \text{Generation Rate}}{1-\text{Decay per Epoch}} * 2^{\text{Slots per Epoch Exp}-\text{Generation Rate Exp}} (1-\text{Decay per Epoch}^{n+1}) +$$ + +with $\text{Decay per Epoch}=\text{Decay per Year}^{\frac{\text{Seconds per Epoch}}{\text{Seconds per Year}}}$. + +The maximum Mana in the system generated by holding tokens $\text{Max Mana Holders}$ is equivalent to the potential Mana generated by an output holding $\text{Token Supply}$ IOTA coins until epoch $n$, for $n$ large enough. This results: + +$$ +\begin{align*} +\text{Max Mana Holders} = \frac{\text{Token Supply} * \text{Generation Rate}}{1-\text{Decay per Epoch}}2^{\text{Slots per Epoch Exp}-\text{Generation Rate Exp}} +\end{align*} +$$ + +We denote by $\text{Max Reward Rate}(n) = \text{Max to Target Ratio} * \text{Target Rewards Rate}(n)$ the theoretical maximum reward distributed at epoch $n$. +In the case of fixed or top stakers based committees, the actual reward distributed per epoch is at most $\text{Target Rewards Rate}(n)$, i.e., $\text{Max to Target Ratio} = 1$. +For random committees, see [Random committees](#random-committees). + +### Mana Supply in the bootstrapping Phase + +In the bootstrapping Phase, the target reward decreases each epoch until reaching $\text{Final Target Rewards Rate}$. +The maximum amount of Mana distributed as rewards until epoch $n$ is: + +$$ +\sum_{i=1}^{n} \text{Decay}(\text{Max Reward Rate}(i),n-i) +$$ + +Since $\text{Max Reward Rate}(i)$ is proportional to the epoch target reward, this is equivalent to + +$$ +\begin{align*} +&\sum_{i=1}^{n} \text{Decay}(\text{Decay}(\text{Max Reward Rate}(1),i-1),n-i)\\ +=&n \text{Decay}(\text{Max Reward Rate}(1),n-1)\\ +=&n \text{Decay per Epoch}^{n-1} \text{Max Reward Rate}(1) +\end{align*} +$$ + +the function above is increasing if $n\leq \frac{-1}{\log(\text{Decay per Epoch})}$ and decreasing otherwise (i.e., it is a concave function). However, since the $\text{Bootstrapping Duration}$ is set such that $\text{Bootstrapping Duration in Years}*\text{Beta per Year}=1$, we have that $\text{Bootstrapping Duration in Years} = \frac{1}{\text{Beta per Year}}=\frac{-1}{\log(\text{Decay per Year})}$. Then, the maximum amount of Mana distributed as rewards in the bootstrapping Phase is achieved at $\text{Bootstrapping Duration}$, i.e., the maximum is + +$$ +\begin{align*} +&\text{Max Mana Supply Bootstrapping}\\ +&=\frac{1}{-\log(\text{Decay per Epoch})} * \text{Max to Target Ratio} * \text{Final Target Rewards Rate} +\end{align*} +$$ + +By definition, we have that $\text{Final Target Rewards Rate}$ is + +$$ +\begin{align*} +& \text{Final Target Rewards Rate} = \text{Token Supply} * \text{Reward To Generation Ratio}\\ +& * \text{Generation Rate} * 2^{\text{Slots per Epoch Exp}-\text{Generation Rate Exp}} +\end{align*} +$$ + +Then, the Maximum Mana supply in the bootstrapping phase is + +$$ +\begin{align*} +&\text{Max Mana Supply Bootstrapping}\\ +&=\text{Token Supply} * \text{Generation Rate} * 2^{\text{Slots per Epoch Exp}-\text{Generation Rate Exp}}\\ +&\left(\text{Reward To Generation Ratio} * \frac{1}{-\log(\text{Decay per Epoch})} * \text{Max to Target Ratio}\right.\\ ++&\left.\frac{1}{1-\text{Decay per Epoch}}\right)\\ +&\leq \text{Token Supply} * \text{Generation Rate} * 2^{\text{Slots per Epoch Exp}-\text{Generation Rate Exp}}\\ +&\frac{1+\text{Reward To Generation Ratio} * \text{Max to Target Ratio}}{1-\text{Decay per Epoch}} +\end{align*} +$$ + +### Mana Supply after the bootstrapping Phase + +By construction, $\text{Final Target Rewards Rate}$ is such that the target reward per epoch is $\text{Reward To Generation Ratio}$ times the generation by holding tokens in that epoch. + +Then, we have that the total Mana in the system will never be larger than $\text{Max Mana Holders} (1 + \text{Max to Target Ratio} * \text{Reward To Generation Ratio})$, i.e. the Mana circulating Supply will be always smaller than : + +$$ +\begin{align*} +&\text{Max Mana Supply}\\ +&=\text{Token Supply} * \text{Generation Rate} * 2^{\text{Slots per Epoch Exp}-\text{Generation Rate Exp}}\\ +&\frac{1+\text{Reward To Generation Ratio} * \text{Max to Target Ratio}}{1-\text{Decay per Epoch}} +\end{align*} +$$ + +which is the same bound found for the bootstrapping Phase. +Thus, the protocol parameters should be set so that the $\text{Max Mana Supply}$ above is at most $2^{\text{Bits Count}}-1$. + +### Mana Supply for Random committees + +In the case of random commitees, we cap the individual pool reward such that no pool will receive more than $\text{Max Pool Reward}(n) = \text{Max Reward Coeff} * \text{Target Rewards Rate}(n)$ per epoch. +Then, in a single epoch, no more than $\text{Target Committee Size} * \text{Max Reward Coeff} * \text{Target Rewards Rate}(n)$ Mana will be distributed, i.e., in this case, $\text{Max to Target Ratio} = \text{Target Committee Size} * \text{Max Reward Coeff}$. +Since, in general, $\text{Target Committee Size} * \text{Max Reward Coeff}$ might be larger than 1, we must alredy set proper maximim values for $\text{Max to Target Ratio}$ to prevent overflowing in case of a future change in the committee selection. +Here, we set $\text{Max to Target Ratio}=20$. +Note that, for fixed committees, this ratio is naturally respected, without the need to add any type of cap in the rewards. +However, in the case of a future protocol upgrade such that the committee selection becomes random, a cap respecting a maximum of $\text{Max to Target Ratio}=20$ must be introduced. + +## Constraints due to fixed point arithmetics + +Additionally to the parameter constraints to prevent the Mana supply from overflowing, other parameter constraints must be introduced to that the function defined in TIP 40 do not overflow using 64 bits variables. + +In particular, in this TIP we define the following operations: +- `Token Supply << Profit Margin Exponent`: this value must be smaller than 264, +- `Pool Coefficient = ((Pool Stake(i) << Pool Coefficient Exponent)/Total Stake) + (Validator Stake(i) << Pool Coefficient Exponent) / Total Validator Stake`: +Since both `Pool Stake(i)` and `Validator Stake(i)` are at most `Token Supply`, to not overflow the calculation, `Pool Coefficient Exponent` must be such that (Token Supply << Pool Coefficient Exponent)< 264. +`Pool Coefficient` will then use at most `Pool Coefficient Exponent + 1` bits. +- `res = (Pool Coefficient * Target Rewards Rate(n))>>PoolCoefficientExponent`: this implies that `Pool Coefficient * Target Rewards Rate(n))` must always be smaller than 264, which is guaranteed by the condition Initial Target Rewards Rate <263-Pool Coefficient Exponent. +- `Pool Reward = ((res * Epoch Performance Factor)/Validation Blocks Per Slot)>>1`: since `res` is at most two times `Initial Target Rewards Rate`, and `Epoch Performance Factor` is at most `Validation Blocks Per Slot <= 32`, this imples that Initial Target Rewards Rate * Validation Blocks Per Slot < 263. + +- `Profit Margin Factor = (Profit Margin(n) * (Pool Rewards(n) - Fixed Cost(n))) >> Profit Margin Exponent`: this implies that `Initial Target Rewards Rate<2^(64-Profit Margin Exponent) ` + +## Constraints due to parameter compatibility + +To avoid locally calculating the parameters, some of them are provided in the snapshot file, even thought they not are defined independently in the Whitepaper. +To avoid problems in the parameter setting, we define some sanity checks for these parameters below: + +## Lookup Table and Annual Decay + +Let `Seconds In An Epoch = Slot Duration In Seconds << Slots Per Epoch Exponent` and `Seconds In A Year = 60 * 60 * 24* 365`. +Then the epoch duration in years is given by `Epoch Duration In Years = Seconds In An Epoch/Seconds In A Year`. +Additionally, let `Annual Decay Factor = Annual Decay Factor Percentage/100`. + +The entry `Lookup Table(epochDiff)` in the Lookup table relative to `epochDiff` should be such that + +`0 <= delta < 1`, where + +`delta = (Annual Decay Factor)^(epochDiff*Epoch Duration In Years)*(2**decay Factor Exp) - Lookup Table(epochDiff)` + +## Initial and Final rewards + +Let `Seconds In An Epoch = Slot Duration In Seconds << Slots Per Epoch Exponent` and `Seconds In A Year = 60 * 60 * 24* 365`. +Then the epoch duration in years is given by `Epoch Duration In Years = Seconds In An Epoch/Seconds In A Year`. +The bootstrapping duration in years is, then: +`Bootstrapping Duration In Years = Epoch Duration In Years * Bootstrapping Duration` +Additionally, let `Annual Decay Factor = Annual Decay Factor Percentage/100`. + +Let `Expected Final Target Rewards Rate = (Total Supply * Reward To Generation Ratio * Generation Rate) >> (Generation Rate Exponent - Slots Per Epoch Exponent)` and `Expected Initial Target Rewards Rate = Final Target Rewards Rate / (Annual Decay Factor ^ Bootstrapping Duration In Years)`. + +Then, we need + +`0 <= Expected Final Target Rewards Rate - Final Target Rewards Rate < 1` +and +`0 <= Expected Initial Target Rewards Rate - Initial Target Rewards Rate < 1` + +## Bootstrapping Duration and Decay + +Let `Seconds In An Epoch = Slot Duration In Seconds << Slots Per Epoch Exponent` and `Seconds In A Year = 60 * 60 * 24 * 365`. +Then the number of epochs in a years is given by `Epochs In An Year = Seconds In A Year/Seconds In An Epoch`. +Additionally, let `Annual Decay Factor = Annual Decay Factor Percentage/100`. +Translating this to an exponential decay (as in the Whitepaper), we have that `Beta Per Year = -log(Annual Decay Factor)`. + +The bootstrapping duration should be an integer approximation of `Epochs In An Year/Beta Per Year` + +## Decay Factor Epoch Sum and Decay + +Decay Factor Epoch Sum should be an integer approximation of + +`2^Decay Factor Epoch Sum Exponent* Decay per Epoch/(1-Decay per Epoch)` diff --git a/tips/TIP-0040/tip-0040.md b/tips/TIP-0040/tip-0040.md new file mode 100644 index 000000000..372440846 --- /dev/null +++ b/tips/TIP-0040/tip-0040.md @@ -0,0 +1,834 @@ +--- +tip: 40 +title: Staking & Delegation +description: Staking, Delegation and Mana Rewards +author: + Philipp Gackstatter (@PhilippGackstatter) , Olivia Saa (@oliviasaa) + , Daria Dziubałtowska (@daria305) +discussions-to: TODO +status: Draft +type: Standards +layer: Core +created: 2023-05-03 +requires: TIP-19, TIP-20, TIP-21 and TIP-22 +--- + +# Summary + +Staking and delegation are mechanisms by which users contribute to the network's security and for which they are +rewarded. Stakers lock IOTA coins to become eligible to be selected for the validator committee and consequently give +weight to blocks and transactions. On the other hand, delegators delegate IOTA coins (which does not imply locking these +tokens) to a validator, forming a validator pool. The weight that validators give to blocks is derived from the total +stake of the pool (i.e., from the locked tokens of the staker and the delegated tokens of all its delegators) and the +total combined stake among pools. If the validator of a pool performs its task well, the pool is rewarded with Mana. +Each participant in the pool can claim rewards roughly proportional to the amount of staked or delegated tokens. This +results in a mechanism that incentivizes users to contribute to the security and well-functioning of the network while +receiving rewards for their contribution. Note that the size of the committee is bounded, so not all pools might get +rewards for a given epoch. + +This TIP specifies the details of staking, delegation, committee selection, and Mana rewards. + +# Motivation + +In IOTA 1.5, nodes use the milestones issued by the Coordinator to reach a consensus on which transactions they should +consider confirmed. The Coordinator was always intended as a temporary solution; thus, it is removed with the upgrade to +IOTA 2.0 (a.k.a. Coordicide). In IOTA 2.0, the Coordinator is replaced by a weight-based voting scheme to resolve +conflicts and finalize transactions. Each of those votes must have a weight associated with it, which depends on the +identity that cast the vote. Determining the weight of an identity is closely related to the type of Sybil protection +mechanism used. + +IOTA 2.0 uses Proof-of-Stake as the Sybil protection mechanism. Proof-of-Stake assigns to every participant a weight +proportional to the number of tokens they hold. Since tokens are a scarce resource, they can be used as a base for a +Sybil protection mechanism, being much more efficient than relying on scarce resources external to the system, such as +hardware or electricity, as in Proof-of-Work-based systems. + +The IOTA 2.0 consensus protocol is founded upon the principle of seat-based committees, determined through staking and +committee-selection mechanisms. At any given point in time, the validator committee is composed of a limited number of +seats, with each seat exclusively assigned to a single validator. The rules governing acceptance, confirmation, and +finalization are contingent on the number of seats that have endorsed (cast their votes in favor of) a block +(transaction). This voting mechanism inherently enables decentralization, as a single entity can, at most, occupy one +seat within the committee and, thus, have a restricted level of influence in the voting process, proportional to the +staked and delegated tokens. + +Using Proof-of-Stake in IOTA 2.0 results in a system with low financial barriers to entry. The technical requirements +for participation are also low and allow everyone to contribute to the network's security. Those who cannot or do not +want to vote (i.e., stake) can delegate stake instead while still adding to the network's security. Proof-of-Stake is, +moreover, energy efficient and environmentally friendly. + +In line with IOTA's goal for _Digital Autonomy_, these properties make Proof-of-Stake a good choice. + +# Building Blocks + +## Data Types & Subschema Notation + +Data types and subschemas used throughout this TIP are defined in [TIP-21](../TIP-0021/tip-0021.md). + +## Protocol Parameters + +Protocol parameters used throughout this TIP are defined in [TIP-49](../TIP-0049/tip-0049.md). + +## Transaction Payload + +[TIP-45](../TIP-0045/tip-0045.md) is the basis for output validation in this TIP. + +## Common Parameters and Functions + +- Let `Decay(value, epochIndexDiff)` be defined as in [TIP-39 (Decay Function)](../TIP-0039/tip-0039.md#decay-function). + +# Staking + +The IOTA protocol accepts blocks and transactions after they reach a certain weight through voting. The voters are a +selected validator committee. The following gives a high-level idea of the selection process, while the rest of the +section specifies its normative details. + +Stakers, or interchangeably called _registered validators_, must lock their IOTA coins to stake them. By locking the +tokens, the stakers prove control over them, so the protocol assigns them a proportional amount of _stake_ in exchange. +Other users - the so-called delegators - can _delegate_ their IOTA coins to a staker to further increase their influence +in the system. A staker plus all its delegators are called a _staking or validator pool_. Stakers are eligible to be +selected into a committee for a certain duration. Only the votes of those selected into the committee are considered to +determine the _Witness Weight_, used for the acceptance of blocks, and _Approval Weight_, used for conflict resolution +and transaction acceptance. Stake is only used to determine who is selected for the committee. Once selected, every +validator in the committee occupies a seat, and every seat has the same voting weight. + +The IOTA protocol slices time into slots and epochs. An epoch is simply a specified number of slots, and a slot has a +protocol-defined duration in seconds. A new validator committee is selected for each epoch. Shortly before an epoch +ends, the current activity of all registered validators, as well as the pools' stakes, are determined. Then, a committee +is selected out of all the registered stakers with enough block issuance activity, depending on their pool stake. Once +selected, each validator is responsible for issuing _Validation Blocks_ across the epoch through which they vote on +conflicts. A performance factor is calculated based on how many such blocks they issued for each slot and how many they +were expected to issue. This factor determines the amount of _Mana rewards_ the validator's pool receives. + +After an epoch ends, the delegators of the pool can claim their rewards. The validator may continue to stake or end its +stake by going through an unbonding period of its locked tokens. After this period ends, the validator can unlock their +IOTA coins and claim their Mana rewards. + +## Validator Registration + +Accounts are considered registered as committee candidates for epoch `Candidate Epoch` if they satisfy all of the +following conditions: + +- The account has a [_Staking Feature_](../TIP-0042/tip-0042.md#staking-feature) in their _Features_ where + `End Epoch >= Candidate Epoch`. +- The account issues a Basic Block in a slot `Block Slot` with a _Candidacy Announcement Payload_ where + `Start Slot(Candidate Epoch - 1) <= Block Slot <= Registration Slot(Candidate Epoch)`. `Epoch Start Slot` and + `Registration Slot` are defined in [committee selection](#committee-selection). + +### Candidacy Announcement + +A _Candidacy Announcement Payload_ does not contain any data as it is only used to signal candidacy. It is serialized as +follows: + +
+ Candidacy Announcement +
Signals candidacy for committee selection for the epoch after the one in which it is issued.
+
+ + + + + + + + + + + +
+ Name + + Type + + Description +
Payload Typeuint8Set to value 2 to denote a Candidacy Announcement Payload.
+ +## Committee Selection + +![Overview of the timing around committee selection in epochs](./assets/selection-timing.png) + +_This figure gives an overview of the timing around committee selection in epochs. Note that the exact length of those +windows is not accurately depicted here and instead depends on the value of the corresponding Protocol Parameters._ + +The following explains how the committee selection for a certain epoch `n` works, with the following time boundaries +used in the algorithm: + +- Let `Epoch Start Slot(n)` be the first slot index of epoch `n`. +- Let `Registration Slot(n)` be the registration slot with index `Epoch Start Slot(n) - Epoch Nearing Threshold - 1`. To + be eligible for the committee selection of epoch `n`, a potential validator must register until this slot, as defined + in [validator registration](#validator-registration). +- Let `Cutoff Slot(n)` be the slot with index `Epoch Start Slot(n) - Maximum Committable Age - 1`. This slot is used in + checks to decide whether the committee will be rotated or not in the epoch. + +The committee will be a subset of the active _registered validators_. To define this subset, the following steps are +taken: + +- The set of _registered validators_ is defined as all Account Outputs that + [registered for Epoch n](#validator-registration). +- For any validator `i` in the set of _registered validators_ the pool stake is equal to `Stake_i + DelegatedStake_i` at + the end of the slot with index `Registration Slot(n)`, where: + - `Stake_i` is the `Staked Amount` of the validator's _Staking Feature_. + - `DelegatedStake_i` is the sum of all _Delegation Output's_ `Amount` field where the value of the `Validator Address` + field is equal to the Account Address of `i`. +- The set of _registered validators_ is sorted as follows and with decreasing priority in the sort condition. To compare + two validators from the set: + - If pool stakes are not equal, sort by pool stake in descending order. + - If validator stakes are not equal, sort by validator stake in descending order. + - If stake end epochs are not equal, sort by stake end epoch in descending order. + - If fixed costs are not equal, sort by fixed cost in ascending order. + - Otherwise sort by Account ID in descending order. + - Since two validators never have the same Account ID, this ensures a selection criteria as a last resort. +- The size of the committee `Committee Size` is set to the minimum of the `Target Committee Size` and the number of + registered validators. +- The first `Committee Size` entries in the _registered validators_ set is Epoch `n`'s preliminary committee. +- The preliminary committee becomes the selected committee if the `Registration Slot(n)` is finalized before the + `Cutoff Slot(n)` is committed; otherwise, the committee of the current epoch becomes the selected committee of the + next epoch. + +### Committee Tasks + +The selected members of the committee are expected to issue _Validation Blocks_, defined in +[TIP-46](../TIP-0046/tip-0046.md). Only the votes of those selected into the committee are considered to determine the +Witness Weight, used for the acceptance of blocks, and Approval Weight, used for conflict resolution and transaction +acceptance. The [performance](#epoch-performance-factor) of a validator is determined by the issued Validation Blocks, and +affects the validator pool's Mana rewards. + +# Delegation + +By delegating IOTA coins, a user increases a validator's stake proportionally to the number of tokens they delegate +without becoming a validator themselves. To delegate, a _Delegation Output_ must be created. The following section +specifies how delegation is implemented. + +## Delegation Output + +Delegation is implemented with a special output type, the so-called Delegation Output. + +Upon the creation of a Delegation Output, the protocol assigns to it a unique identifier called `Delegation ID`. The +`Delegation ID` is the BLAKE2b-256 hash of the `Output ID` that created the Delegation Output. + +
+ Delegation Output +
Describes a Delegation Output, which delegates its contained IOTA coins to a validator.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Output Typeuint8Set to value 5 to denote a Delegation Output.
Amountuint64The amount of IOTA coins held by the output.
Delegated Amountuint64The amount of delegated IOTA coins.
Delegation IDByteArray[32]Unique identifier of the Delegation Output, which is the BLAKE2b-256 hash of the Output ID that created it.
Validator Address oneOf +
+ Account Address +
An Address derived from an Account ID which can be unlocked by unlocking the corresponding Account. Defined in TIP-38 (Account Address).
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Address Typeuint8Set to value 8 to denote an Account Address.
Account IDByteArray[32]The raw bytes of the Account ID which is the BLAKE2b-256 hash of the Output ID that created it.
+
+
Start Epochuint64The index of the first epoch for which this output delegates.
End Epochuint64The index of the last epoch for which this output delegates.
Unlock Conditions Countuint8The number of unlock conditions following.
Unlock Conditions atMostOneOfEach +
+ Address Unlock Condition +
Defines the Address that owns this output. It can unlock the output with the proper Unlock in a transaction. Defined in TIP-38 (Address Unlock Condition).
+ + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Unlock Condition Typeuint8Set to value 0 to denote an Address Unlock Condition.
Address oneOf +
+ Ed25519 Address +
An Address derived from an Ed25519 Public Key. Defined in TIP-38 (Ed25519 Address).
+
+
+ Account Address +
An Address derived from an Account ID which can be unlocked by unlocking the corresponding Account. Defined in TIP-38 (Account Address).
+
+
+ NFT Address +
An Address derived from an NFT ID which can be unlocked by unlocking the corresponding NFT. Defined in TIP-38 (NFT Address).
+
+
+ Anchor Address +
An Address derived from an Anchor ID which can be unlocked by unlocking the corresponding Anchor. Defined in TIP-38 (Anchor Address).
+
+
+ Multi Address +
Defines a Multi Address that consists of addresses with weights and a threshold value. The Multi Address can be unlocked if the cumulative weight of all unlocked addresses is equal to or exceeds the threshold. Defined in TIP-52 (Multi Address).
+
+
+ Restricted Address +
An address that contains another address and allows for configuring its capabilities. Defined in TIP-50 (Restricted Address).
+
+
+
+
+ +### Additional Transaction Syntactic Validation Rules + +- It must hold true that `Unlock Conditions Count = 1`. +- `Unlock Condition Type` of an _Unlock Condition_ must define one of the following types: + - _Address Unlock Condition_ +- _Unlock Conditions_ must be sorted in ascending order based on their `Unlock Condition Type`. +- Syntactic validation of all present unlock conditions must pass. +- The underlying `Account ID` of `Validator Address` must not be zeroed out. +- A _Commitment Input_ must be present. + +### Additional Transaction Semantic Validation Rules + +- A _Commitment Input_ must be present when a _Delegation Output_ is on the input side of a transaction. +- Explicit `Delegation ID`: `Delegation ID` is taken as the value of the `Delegation ID` field in the Delegation output. +- Implicit `Delegation ID`: When a Delegation output is consumed as an input in a transaction and `Delegation ID` field + is zeroed out, take the BLAKE2b-256 hash of the `Output ID` of the input as `Delegation ID`. +- For every non-zero explicit `Delegation ID` on the output side there must be a corresponding Delegation Output on the + input side. The corresponding Delegation output has the explicit or implicit `Delegation ID` equal to that of the + Delegation output on the output side. +- Let `Past Bounded Slot Index` be given by `Commitment Index + Max Committable Age` where `Commitment Index` is the + slot index of the commitment input. +- Let `Past Bounded Epoch Index` be the epoch index corresponding to the slot index `Past Bounded Slot Index`. +- Let `Future Bounded Slot Index` be given by `Commitment Index + Min Committable Age` where `Commitment Index` is the + slot index of the commitment input. +- Let `Future Bounded Epoch Index` be the epoch index corresponding to the slot index `Future Bounded Slot Index`. + +#### Consumed Outputs + +Whenever a Delegation output is consumed in a transaction, it means that the output is transitioned into its next state. +From its initial state, the _Delegating State_, a Delegation Output can either be destroyed or transitioned to a +_Delayed Claiming_ state, from which it can then be destroyed. The current state is defined as the consumed Delegation +output, while the next state is defined as the Delegation output with the same explicit `Delegation ID` on the output +side. There are thus two types of transitions: delayed claiming transition and destruction transition. + +- Delayed Claiming Transition + - Is identified by a zeroed-out `Delegation ID` on the input side and a non-zeroed-out `Delegation ID` on the output + side. + - The fields `Delegated Amount`, `Start Epoch` and `Validator Address` must not be changed. + - `End Epoch` on the output must be set as follows. + - Let `Registration Slot(n)` be defined as in [committee selection](#committee-selection), where `n` is equal to + `Future Bounded Epoch Index`. + - If `Future Bounded Slot Index <= Registration Slot(n+1)` then `End Epoch` must be set to + `Future Bounded Epoch Index`, otherwise to `Future Bounded Epoch Index + 1`. +- Destruction Transition + - Is identified by the absence of a Delegation Output on the output side with an explicit `Delegation ID` that + corresponds to the `Delegation ID` of the one on the input side, which may be an implicit or explicit Delegation ID. + The next state is the empty state. + - During this transition, Mana rewards may be added to the total sum of Mana on the output side of the transaction, + according to [delegator rewards](#delegator-rewards). + +#### Created Outputs + +- When `Delegation ID` is zeroed out certain fields of the Delegation Output must be set as follows. + - Let `Registration Slot(n)` be defined as in [committee selection](#committee-selection), where `n` is equal to + `Past Bounded Epoch Index`. + - If `Past Bounded Slot Index <= Registration Slot(n+1)` then `Start Epoch` must be set to + `Past Bounded Epoch Index + 1`, otherwise to `Past Bounded Epoch Index + 2`. + - Set `Delegated Amount` to the value of the `Amount` field. + - Set `End Epoch` to `0`. + +### Storage Score + +A Delegation Output incurs additional computational cost in order to compute the total stake of a validator. Due to +this, such an output has an additional storage score offset, the `Storage Score Parameters::Offset Delegation` as +defined in [TIP-49](../TIP-0049/tip-0049.md). + +# Mana Rewards + +Mana Rewards are claimed and tracked for past epochs on an epoch level. +For an ongoing epoch, they are tracked on a slot level and are then combined into an epoch rewards entry when the +epoch ends (i.e., when its last slot is committed). +Rewards for an epoch become claimable only after the epoch ends. +In the following sections, we define how the rewards are calculated and tracked at the slot level (i.e., for a +still unfinished epoch) and how they are combined and tracked at the epoch level (i.e., after the epoch ends). + +## Calculations done at the Slot Level + +For each slot, the performance factor of each validator in the selected committee must be tracked. For an ongoing epoch, +this results in a list of performance factors for a validator. The rewards for an ongoing epoch are tracked by keeping a +map of slot indices to a map of the validator's activity in that slot, identified by the `Validator ID`. The activity is +thus tracked per slot, per validator with objects consisting of these data: + + + + + + + + + + + + + + + + +
NameTypeDescription
Slot Activity Vectoruint32A bitmap where each bit corresponds to a subslot in the slot for which the performance factor is tracked. +
Blocks Issued Countuint8The total number of blocks issued by the validator in the slot.
+ +### Slot Performance Factor + +This performance factor for a slot is defined as follows. + +#### Input values + +- Let `Validation Blocks Per Slot` be a protocol parameter representing the number of validation blocks a validator is + supposed to issue per slot. `Validation Blocks Per Slot` must be less or equal than 32 in order for all subslots to + fit into the `Slot Activity Vector` bitmap. + +#### Calculations + +- Divide the slot representing times `[Slot Start, Slot End)` into `Validation Blocks Per Slot` subslots of length + `Subslot Duration = Slot Duration In Seconds/Validation Blocks Per Slot` given by + `[Slot Start + (i - 1) * Subslot Duration, Slot Start + i * Subslot Duration)`, for + `i = 1,...,Validation Blocks Per Slot`. +- Determine which of these subslots have at least one validation block issued in them. + Set `Slot Activity Vector` such that: + - If subslot `i` has at least one validation block issued in it, set the bit in `Slot Activity Vector` with the index `i` to 1. + - Otherwise, set the bit in `Slot Activity Vector` with the index `i` to 0. +- Set `Blocks Issued Count` to the total number of validation blocks issued in this slot. + Validators are supposed to issue at most `Validation Blocks Per Slot` validation blocks per slot. + If the number of blocks issued in this slot is greater than `Validation Blocks Per Slot`, + set `Blocks Issued Count` to `Validation Blocks Per Slot + 1` to signal that the + validator issued more validation blocks than it was supposed to and that it should be punished + when combining the slot performance factors into an epoch performance factor. + Since `Validation Blocks Per Slot` must be less or equal than 32, this approach will not overflow `Blocks Issued Count`. +- The `Slot Performance Factor` is then defined as + - The sum of the bits in `Slot Activity Vector`, if `Blocks Issued Count ≤ Validation Blocks Per Slot`. + - 0, otherwise. + +The `Slot Performance Factor` is then an integer between 0 and `Validation Blocks Per Slot`. +Note that there is no need to explicitly calculate the `Slot Performance Factor` for each slot, since they will all be aggregated +as an single `Epoch Performance Factor` after the epoch ends. +Instead, one should simply store all `Slot Activity Vector` and `Blocks Issued Count` (one pair for each slot) until the epoch ends. + +## Mana Rewards at a Epoch Level + +After an epoch has ended, the performance factors tracked at the slot level can be combined into a single performance factor for the whole epoch. +The profit margin of the epoch (which is common for all pools) is also calculated. +With those values determined, the rewards for the whole pool are calculated. +We define the procedure to do so in the next sections. + +### Epoch Performance Factor + +The `Epoch Performance Factor` is given by the average between the values of `Slot Performance Factor`, rounded down to the nearest integer. +This can be calculated as the sum of bits set to `1` in each `Slot Activity Vector` with a subsequent _zero-fill right-shift_ operation by +`Slots Per Epoch Exponent`. If the validator issued more than `Validation Blocks Per Slot` validation blocks in any slot, that is, if +`Blocks Issued Count > Validation Blocks Per Slot` in any of the slots in the epoch, then `Epoch Performance Factor` is set to 0 as a form of +punishment. +Note that the value of the `Epoch Performance Factor` will be an integer between 0 and `Validation Blocks Per Slot`. + +### Profit Margin + +#### Input values for the Profit Margin calculation + +- Let `Total Stake` be the sum of all `Pool Stake` values, that is, the total amount of delegated and staked IOTA coins + in the selected committee. +- Let `Total Validator Stake` be the sum of `Validator Stake(i)` for each validator `i` in the selected committee. + +#### Profit Margin calculation + +- Let `Profit Margin Exponent` be as definced in [TIP-49](../TIP-0049/tip-0049.md). +- Given the values defined above, then + `Profit Margin = (Total Validator Stake << Profit Margin Exponent)/(Total Validator Stake + Total Stake)`. Note that + this will be an integer strictly smaller than 2Profit Margin Exponent, so `Profit Margin` can + be set to use `Profit Margin Exponent` bits. +- To prevent overflows in the calculation above, (Token Supply << Profit Margin Exponent)< 264, where `Token Supply` is the current token supply on the network, as defined in [TIP-49](../TIP-0049/tip-0049.md). + +The `Profit Margin` must be tracked for each epoch: + + + + + + + + + + + + +
NameTypeDescription
Profit Marginuint8 + An integer representing the epoch profit margin, scaled to 2Profit Margin Exponent. +
+ +### Pool Rewards for an Epoch + +The pool rewards of an epoch are tracked by keeping a map from epoch indices to a map from `Validator ID`s to values +consisting of these fields: + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
Pool Stakeuint64The total amount of IOTA coins staked by the validator and all its delegators.
Pool Rewardsuint64The total amount of rewards the validator pool received.
Fixed Costuint64The fixed cost of the validator in that epoch.
+ +The present section defines how `Pool Rewards` can be obtained from the slot-level data, after the commitment of the last +slot of that epoch. + +#### Input values for Pool Rewards calculations + +- Let `Bootstrapping Duration`, `Reward To Generation Ratio`, `Final Target Rewards Rate`, `Initial Target Rewards Rate`, and `Pool Coefficient Exponent` be as defined in [TIP-49](../TIP-0049/tip-0049.md). +- Let `Validator Stake(i)` be the amount of IOTA coins staked by the validator with Account ID `i`, i.e. the + `Staked Amount` in the _Staking Feature_ of the validator at the end of the registration slot. +- Let `Pool Stake(i)` be the total amount of delegated and staked IOTA coins by the validator pool `i`, identified by +the validator's `Account ID`, which was determined at the time of the pool stake calculation, i.e. the end of the +registration slot. +- Let `Total Stake` be the sum of `Pool Stake(i)` for all validators `i` in the selected committee. +- Let `Total Validator Stake` be the sum of `Validator Stake(i)` for all validators `i` in the selected committee. + +#### Pool Rewards calculations + +- The total target rewards rate `Target Rewards Rate(n)` for an epoch index `n` is defined as: + - `Decay(Initial Target Rewards Rate, n)` if `n <= Bootstrapping Duration`. + - `Final Target Rewards Rate` if `n > Bootstrapping Duration`. +- The Pool Reward `Pool Reward` for an epoch index `n`, and pool `i` is calculated as follows: + - Let `Pool Coefficient` be + `((Pool Stake(i) << Pool Coefficient Exponent)/Total Stake) + (Validator Stake(i) << Pool Coefficient Exponent) / Total Validator Stake`. + - Since both `Pool Stake(i)` and `Validator Stake(i)` are at most `Token Supply`, to not overflow the + calculation, `Pool Coefficient Exponent` must be such that (Token Supply << Pool Coefficient Exponent)< 264. `Pool Coefficient` will then use at most + `Pool Coefficient Exponent + 1` bits. + - Take the `Epoch Performance Factor` for the whole epoch `n` according to + [Epoch Performance Factor](#epoch-performance-factor). + - To calculate `Pool Reward`, we first calculate `res = (Pool Coefficient * Target Rewards Rate(n))>>PoolCoefficientExponent`. Then, `Pool Reward = ((res * Epoch Performance Factor)/Validation Blocks Per Slot)>>1`. + Note that if this value is smaller than `Fixed Cost`, the validator will not receive rewards from this epoch. + This is done to incentivize validators to define reasonable values for their fixed cost. + +## Validator Rewards + +An account with a _Staking Feature_ can claim rewards in the same transaction where the feature is removed. The +transaction validation rules for removing the feature are defined in [TIP-42](../TIP-0042/tip-0042.md). Upon removal, +the amount of Mana Rewards that can be claimed is defined as follows. + +### Parameters for Validator Rewards calculation + +- Let `Profit Margin Exponent` be as defined in [TIP-49](../TIP-0049/tip-0049.md). + +### Input Values for Validator Rewards calculation + +- Let `Profit Margin(n)` be the `Profit Margin` for epoch index `n`. +- Let `Pool Rewards(n)` be the `Pool Rewards` of the entry in `Claimable Rewards` with epoch index `n`. +- Let `Pool Stake(n)` be the `Pool Stake` of the entry in `Claimable Rewards` with epoch index `n`. +- Let `Fixed Cost(n)` be the `Fixed Cost` defined in the _Staking Feature_ at epoch `n`. + +### Validator Rewards calculation + +To calculate the claimable rewards of a validator relative to a past epoch `n`, we must first calculate `Undecayed Validator Rewards(n)`. +This value corresponds to the claimable reward if the validator claimed them right after the epoch ended. +If the claiming epoch is larger than `n+1`, this value has to be decayed to account for this epoch difference. +To calculate the `Undecayed Validator Rewards(n)` for a given epoch `n`, we proceed as follows: + +- If `Pool Rewards(n) - Fixed Cost(n) < 0`, then `Undecayed Validator Rewards(n)` is zero. +- If `Pool Rewards(n) - Fixed Cost(n) >= 0`, then `Undecayed Validator Rewards(n)` is + `Fixed Cost(n) + Profit Margin Factor + Residual Validator Factor`, where: + - `Profit Margin Factor = (Profit Margin(n) * (Pool Rewards(n) - Fixed Cost(n))) >> Profit Margin Exponent`. + - `Residual Validator Factor = ((Profit Margin Complement * (Pool Rewards(n) - Fixed Cost(n))) >> Profit Margin Exponent) * Staked Amount/Pool Stake(n)` + where `Profit Margin Complement = (1 << Profit Margin Exponent) - Profit Margin(n)`. + - Note that `((Profit Margin Complement * Pool Rewards(n)) >> Profit Margin Exponent) * Staked Amount` can use more than 64 bits. Then, to prevent overflowing, this factor should be either stored as + a 128 bits integer or it should be stored as 2 `uint64` variables (and the proper 128 by 64 division algorithm must be used). + +Finally, given `Undecayed Validator Rewards(n)`, we can calculate the decayed rewards relative to epoch `n`, by applying `Validator Rewards(Decay End Epoch, n) = Decay(Undecayed Validator Rewards(n), Decay End Epoch - n)`. + +Given the values of `Validator Rewards(Decay End Epoch, n)`, we calculate the total claimable reward for a validator as follows: + +- Let `Future Bounded Slot Index` be given by `Commitment Index + Min Committable Age` where `Commitment Index` is the + slot index of the commitment input. If no _Commitment Input_ is present, the transaction is invalid. + - Note that the presence of a _Commitment Input_ is already required for any transaction containing a _Staking + Feature_ on the input or output side. +- Let `Future Bounded Epoch Index` be the epoch index corresponding to the slot index `Future Bounded Slot Index`. +- Let the `Claimable Rewards(id)` be all reward entries for the validator identified by the Account ID `id` of the + account that removes the Staking Feature, where the reward entry's epoch index `Epoch Index` satisfies all of the + following conditions: + - `Epoch Index >= Start Epoch + 1`. + - `Epoch Index < Last Reward Epoch` where `Last Reward Epoch` is the minimum of `Future Bounded Epoch Index` and + `End Epoch + 1`. +- Let `Validator Rewards(Account ID)` be the total claimable decayed rewards for the Account Output identified by + `Account ID`. It is the sum of `Validator Rewards(Decay End Epoch, n)` for each epoch `n` in `Claimable Rewards(Account ID)` + where `Decay End Epoch` is the maximum of `Future Bounded Epoch Index - 1` (or `0` if that would underflow) and + `Last Reward Epoch`. + - Note: The `- 1` is applied to allow claiming the full, undecayed reward for an epoch `n - 1` in epoch `n`. + +## Delegator Rewards + +To claim rewards, a _Delegation Output_ must be destroyed. Depending on the state it is in at that point, different +conditions for claiming rewards apply. An output destroyed in _Delegating State_ will always forfeit _potential_ rewards +for the epoch in which it is destroyed, since the rewards for that epoch only become available in the subsequent epoch. +They are _potential_ since the validator to which the output is delegating may not have been selected into the committee +for that epoch. + +### Parameters for Delegator Rewards calculation + +- Let `Profit Margin Exponent` be as defined in [TIP-49](../TIP-0049/tip-0049.md). + +### Input Values for Delegator Rewards calculation + +- Let `Profit Margin(n)` be the `Profit Margin` for epoch index `n`. +- Let `Pool Rewards(n)` be the `Pool Rewards` of the entry in `Claimable Rewards(id)` with epoch index `n` for validator + `id`. +- Let `Pool Stake(n)` be the `Pool Stake` of the entry in `Claimable Rewards(id)` with epoch index `n` for validator + `id`. +- Let `Fixed Cost(n)` be the `Fixed Cost` defined in the _Staking Feature_ at epoch `n`. + +### Delegator Rewards calculation + +Similarly to the validator rewards calculation, the amount of Mana Rewards that can be claimed for a _Delegation Output_ which is destroyed is defined as follows. We begin by calculating the undecayed claimable rewards relative to a past epoch `n`, denoted by `Undecayed Delegator Rewards(n)`. +This value corresponds to the claimable reward if the delegator claimed them right after the epoch ended. +If the claiming epoch is larger than `n+1`, this value has to be decayed to account for this epoch difference. +To calculate the `Undecayed Delegator Rewards(n)` for a given epoch `n`, we proceed as follows: + +- If `Pool Rewards(n) - Fixed Cost(n) < 0`, then `Undecayed Delegator Rewards(n)` is + `((Profit Margin Complement * Pool Rewards(n)) >> Profit Margin Exponent) * Delegated Amount/Pool Stake(n)`. +- If `Pool Rewards(n) - Fixed Cost(n) >= 0`, then `Undecayed Delegator Rewards(n)` is + `((Profit Margin Complement * (Pool Rewards(n) - Fixed Cost(n))) >> Profit Margin Exponent) * Delegated Amount/Pool Stake(n)`. + - Note that `((Profit Margin Complement * Pool Rewards(n)) >> Profit Margin Exponent) * Delegated Amount` can use more than 64 bits. Then, to prevent overflowing, this factor should be either stored as + a 128 bits integer or it should be stored as 2 `uint64` variables (and the proper 128 by 64 division algorithm must be used). + +Finally, given `Undecayed Delegator Rewards(n)`, we can calculate the decayed rewards relative to epoch `n`, by applying `Delegator Rewards(Decay End Epoch, n) = Decay(Undecayed Delegator Rewards(n), Decay End Epoch - n)`. +Given the values of `Delegator Rewards(Decay End Epoch, n)`, we calculate the total claimable reward for a delegator as follows: + +- Let the `Claimable Rewards(address)` be all reward entries for the validator identified by the Account ID + corresponding to the `address`, which is the `Validator Address` field in the Delegation Output, where the entry's + epoch index `Epoch Index` satisfies `Epoch Index >= Start Epoch` and `Epoch Index <= Delegation End`, where: + - If the output is in _Delegating State_ let `Delegation End` be `Future Bounded Epoch Index - 1`, where: + - `Future Bounded Slot Index` is given by `Commitment Index + Min Committable Age` where `Commitment Index` is the + slot index of the commitment input. If no _Commitment Input_ is present, the transaction is invalid. + - Note that the presence of a _Commitment Input_ is already required for any transaction containing a _Delegation + Output_ on the input or output side. + - `Future Bounded Epoch Index` is the epoch index corresponding to the slot index `Future Bounded Slot Index`. + - Note that no transaction validation rule exists to prevent claiming rewards too early, that is, before the rewards + of the previous epoch became available, thus forfeiting the potential rewards of that previous epoch. + - If the output is in _Delayed Claiming State_ let `Delegation End` be `End Epoch`. +- Let `Delegator Rewards(Delegation ID)` be the total claimable decayed rewards for the Delegation Output identified by + `Delegation ID` with `address` set to the `Validator Address`. It is the sum of `Delegator Rewards(Decay End Epoch, n)` for each + epoch `n` in `Claimable Rewards(address)`, where `Decay End Epoch` is the maximum of `Future Bounded Epoch Index - 1` + (or `0` if that would underflow) and `Delegation End`. + - Note: The `- 1` is applied to allow claiming the full, undecayed reward for an epoch `n - 1` in epoch `n`. + +# Rationale & Design + +This section describes the rationale behind some of the design choices and explains how the introduced concepts fit +together. It is however not part of the formal specification and thus non-normative. + +## Delegation Output + +Using dedicated Delegation Outputs over a Delegation Feature in an Account has some advantages. First, it makes it +easily possible to delegate to multiple validators from the same account, by creating multiple outputs. In the Stardust +Design ([TIP-18](../TIP-0018/tip-0018.md)), Features are assumed to be unique in an output, and thus having multiple +Delegation Features to allow for multiple delegation targets would require changing that assumption. Second, it +decouples the delegation logic from the Account. Delegation, in contrast to staking, does not require that an account +must be the delegator. A Delegation Output can be owned by a plain Ed25519 address or an NFT or Account Address, making +it more flexible. A Delegation Feature would only allow for Delegation from an account. + +### Delayed Claiming + +Mana Rewards for some epoch `X` only become available after that epoch ends. At that point, the pool stake for the +following epoch `X+1` has already been calculated. That means, if one waits until the rewards for `X` are available and +consumes their Delegation Output to claim rewards, they have already delegated for `X+1` but will lose out on the +rewards they would get for that delegation. + +With delayed claiming, however, a user can delegate for `X` and then transition to delayed claiming. At that point, the +output only needs to contain the minimum storage deposit. The remaining funds can be put in a new Delegation Output to +delegate for `X+1`, which can repeat this procedure. In this manner, one can delegate for one epoch at a time and never +lose out on any rewards. The following figure exemplifies this procedure. + +![Example of delayed claiming](./assets/delayed-claiming.png) + +Delayed Claiming also allows for a high degree of liquidity while delegating. Even without delayed claiming, this +delegation mechanism implements _liquid delegation_ as Delegation Outputs are never locked and can be accessed anytime. +However, one might lose out on rewards. Delayed Claiming fixes this: If one delegated for the current epoch but needs to +access the funds immediately, one can transition to delayed claiming and access all the funds (minus the small storage +deposit), and still claim rewards later. + +Additionally, Delayed Claiming enables Layer 2 Smart Contract Chains to hold their funds in Delegation Outputs and +delegate the tokens of their users for them, while they can use those wrapped tokens on Layer 2. Since an Account Output +belonging to an SC chain is transitioned very frequently, without Delayed Claiming, they would never hold the Delegation +Output long enough for it to be able to claim rewards. With Delayed Claiming SC chains can implement this kind of +delegation. + +#### Start and End Epoch + +This figure showcases how epochs are set when creating and transitioning Delegation Outputs. Note that the length of +epochs in slots is not accurately depicted here. What matters for epoch setting is 1) what the current epoch is and 2) +whether the creation or transition happens before or after the registration slot for the following epoch. + +![How epochs are set when creating and transitioning Delegation Outputs](./assets/delegation-epochs.png) + +- Delegation Output X is created before the end of the Registration Slot. Therefore its `Start Epoch` is set to `21`, as + that is the earliest epoch for which it could receive rewards. However, it is also transitioned before the end of the + slot, so its `End Epoch` is set to `20`, as that is the last epoch for which it could receive rewards. However, the + condition for claiming rewards is not satisfied for any epoch index. There will be no epoch index `A` that satisfies + `A >= 21 && A <= 20`. This Delegation Output will consequently not be able to claim any rewards at all, as it was + never included in any pool stake calculation. +- Delegation Output Y is created before the end of the Registration Slot. Therefore its `Start Epoch` is set to `21`, as + that is the earliest epoch for which it could receive rewards. It is transitioned after the end of the Registration + Slot, so it was included in the pool stake calculation. Therefore the last epoch for which it could get rewards is + `21`, which is the value of `End Epoch`. In sum, the delegation output will therefore be able to claim rewards for + epoch `21` only. +- Delegation Output Z is analogous to X, only shifted by one epoch. It is created after the Registration Slot of Epoch + 21 but before the Registration Slot of Epoch 22. Therefore its `Start Epoch` is set to `22`, as that is the earliest + epoch for which it could receive rewards. It is however transitioned before the Registration Slot of Epoch 22, so it + will not be included in the pool stake calculation for said epoch. Its `End Epoch` is thus set to `21`, as that may be + the last epoch for which it could get rewards. Similar to Output X, the delegation output will not be able to claim + any rewards as it was never included in any pool stake calculation and no epoch index `A` satisfies + `A >= 22 && A <= 21`. + +These examples show that transitioning a Delegation Output without crossing a Registration Slot boundary does not yield +any rewards. At least one such boundary must be crossed for any rewards to be claimable. + +### Time Boundaries + +When designing transaction validation rules, a choice must be made between choosing to bound the past or the future, +that is, whether to prevent faking the past or faking the future. To maximize rewards, users are incentivized to make +the range of epochs for which they can claim rewards as large as possible. Thus, there's an incentive to set +`Start Epoch` as early or low as possible and `End Epoch` as high or late as possible. To prevent malicious behavior, +like setting `Start Epoch` to the current epoch when the block itself, that contained the transaction in which the +delegation started, was issued past the registration slot of the next epoch, the boundaries must be set appropriately. +Thus, `Start Epoch` must be set to or compared against the past-bounded slot index, which prevents faking the past. A +past-bounded slot index is always at least equal to the slot to which the block belongs, based on its `Issuing Time`, +since the oldest, valid commitment that can be picked is `Max Committable Age` slots old. Analogously, `End Epoch` must +be set to or compared against the future-bounded slot index, which prevents faking the future. A future-bounded slot +index is always at most equal to the slot to which the block belongs, based on its `Issuing Time`, since the newest, +valid commitment that can be picked is `Min Committable Age` slots old. + +# Test Vectors + +The protocol parameters used in the following test vectors are the same as in +[TIP-49 (Protocol Parameters Hash)](../TIP-0049/tip-0049.md#protocol-parameters-hash). + +## Storage Score + +The following test vector shows the calculation of the storage score according to [TIP-47](../TIP-0047/tip-0047.md). + +Delegation Output (json-encoded): + +```json +{ + "type": 5, + "amount": "200000000", + "delegatedAmount": "500000000", + "delegationId": "0x08b987baffaacb9da156734275ee01a42a35fe06653823be654821a7ddf92380", + "validatorAddress": { + "type": 8, + "accountId": "0x17432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a" + }, + "startEpoch": 30, + "endEpoch": 50, + "unlockConditions": [ + { + "type": 0, + "address": { + "type": 0, + "pubKeyHash": "0xed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a" + } + } + ] +} +``` + +Delegation Output (hex-encoded binary serialization): + +``` +0x0500c2eb0b000000000065cd1d0000000008b987baffaacb9da156734275ee01a42a35fe06653823be654821a7ddf923800817432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a1e00000032000000010000ed1484f4d1f7d8c037087fed661dd92faccae1eed3c01182d6fdd6828cea144a +``` + +Delegation Output Storage Score: `313`. + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).