Introduce dynamic block rewards module

Hello everyone,

I would like to propose a new LIP for the roadmap objective “Improve consensus protocol”. This LIP introduces the “Dynamic Block Rewards module” that is responsible for providing the base reward system for the Lisk blockchain according to the delegate weight.

I’m looking forward to your feedback.

Here is the complete LIP draft:

LIP: <LIP number>
Title: Introduce dynamic block rewards module
Author: Vikas Jaiman <vikas.jaiman@lightcurve.io>
Type: Standards Track
Created: <YYYY-MM-DD>
Updated: <YYYY-MM-DD>
Required: LIP 0044, LIP 0051, LIP 0057, LIP 0058

Abstract

This LIP introduces the Dynamic Block Rewards module that is responsible for providing the base reward system for the Lisk blockchain according to the delegate weight. In this LIP, we specify the properties of the Dynamic Block Rewards module, along with their default values. Furthermore, we specify the protocol logic injected during the block lifecycle, and the functions that can be called from other modules or off-chain services. This module is mainly used for Delegate Proof-of-Stake (DPoS) in the Lisk ecosystem.

Copyright

This LIP is licensed under the Creative Commons Zero 1.0 Universal.

Motivation

In the current Lisk protocol, the rewards are the same for all active and standby delegates (selected according to the selection mechanism described in LIP 0022 and LIP 0023) who forge a block in a round, irrespective of their delegate weight. In the current scenario, a delegate with a large delegate weight does not have incentives to lock further tokens via self-votes as the rewards are fixed. Moreover, delegates with a large number of tokens are not motivated enough to lock more tokens unless they run multiple delegates which is not desirable for them due to operational costs and maintenance efforts. Thus, the LIP aims to simplify DPoS participation for delegates to lock the large number of tokens. By more participation, we expect to increase the Total Value Locked (TVL) and therefore, the security of the Lisk Mainchain. To achieve this, we assign block rewards to also depend on the weight of the delegate generating the block.

Rationale

​​The main purpose of Dynamic Block Rewards module is to compute the block rewards according to the delegate weight for active delegates and induces specific logic after the application of a block:

  • This module assigns a minimum reward i.e. MINIMUM_REWARD_ACTIVE_DELEGATES per round to all active delegates to cover the minimal operational cost to run a delegate. It is calculated as FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES * getDefaultRewardAtHeight(blockHeader.height) where FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES is the fractional parameter for calculating minimum rewards of all active delegates. The FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES is chosen to 1000 i.e. 10% for the Lisk mainchain and can be configurable for sidechains. For technical convenience, the fraction FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES is represented as an integer that takes values from 0 to 10000 and we use two decimals precision, i.e., FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES/100 determines the percentage of minimum rewards assigned equally to all active delegates. In addition, the module distributes the remaining rewards i.e. STAKE_REWARD_ACTIVE_DELEGATES proportional to the delegate weights. This way, the module achieves fairness (higher weight implies higher rewards) while ensuring that rewards of low-weight delegates do not go below the threshold of profitability.
  • In principle, if FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES == 0 i.e. 0%, it will be a proof-of-stake system where rewards are proportional to the delegate weight. Moreover, if FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES == 10000 i.e. 100%, it will be the current delegate proof-of-stake (DPoS) system where each delegate will receive the same reward for forging a block.
  • This module assigns DEFAULT_REWARD_STANDBY_DELEGATES to all stand-by delegates i.e. there is a fixed reward irrespective of the delegate weight. This will help stand-by delegates to cover the costs of running a node even though the probability of the selection is low in a round.
  • Currently, in the Lisk protocol if a delegate misses a block, some other delegates forge the block and the delegate gets getDefaultRewardAtHeight(blockHeader.height)(1 LSK for mainchain) as a reward. The reason is, the total rewards shouldn’t exceed in a round it if a delegate misses a block. Now, in the dynamic block rewards, delegates get rewards proportional to the delegate weight. If a delegate misses a block then a delegate forging the block second time will get the reward proportional to their weight. This results in imbalancing the total reward in a round. In terms of inflation, currently in the Lisk mainchain, there is a maximum minting of 6*60*24*365 = 3153600 LSK per year. Every time a delegate misses their block, 1 LSK less is minted per year. So the important aspect that we want to guarantee here is that in the dynamic block rewards also never more than 3153600 LSK are minted per year so that there is a reliable upper bound on the inflation. In terms of incentives, it is also important that it should never be profitable for a delegate if someone misses a block. Therefore, for missed blocks, delegates forging blocks for the second time in the round, gets MINIMUM_REWARD_ACTIVE_DELEGATES. Since delegates are already running full nodes and there is no additional effort for them to forge a missed block. There is a possibility that the minting of the tokens will be less if there are missed blocks.
  • After applying the block, a certain quantity of the native token of the blockchain is minted. The exact amount assigned to the block generator, i.e. the reward is calculated depending on the rules of the Random module and the Lisk-BFT protocol. Specifically, the reward is reduced for not participating in BFT block finalization or failure to properly reveal the random seed. This reduction happens exactly as before mentioned in the previous Reward module. After minting the block rewards, updateSharedRewards function is called from the reward sharing mechanism of the DPoS module which locks the amount of the rewards which will be shared with the voters.

Specification

In this section, we specify the protocol logic in the lifecycle of a block injected by the Dynamic Block Rewards module as well as the functions that can be called from off-chain services. It depends on the Token, Random module, and Lisk-BFT protocol. (see the table below).

Notation and Constants

We define the following constants:

Name Type Value Description
MODULE_NAME_DYNAMIC_BLOCK_REWARDS string “dynamicBlockRewards” The module name of the Dynamic Block Rewards module.
EVENT_NAME_REWARD_MINTED string “rewardMinted” Name of the event during minting of the rewards.
REWARD_NO_REDUCTION uint32 0 Return code for no block reward reduction.
REWARD_REDUCTION_SEED_REVEAL uint32 1 Return code for block reward reduction because of the failed seed reveal.
REWARD_REDUCTION_MAX_PREVOTES uint32 2 Return code for block reward reduction because the block header does not imply the maximal number of prevotes.
REWARD_REDUCTION_FACTOR_BFT uint32 4 The reduction factor for validator block reward in case when the block header does not imply the maximal number of prevotes.
SUBSTORE_PREFIX_END_OF_ROUND_TIMESTAMP bytes 0xe000 The substore prefix of the End-Of-Round timestamp substore.
SUBSTORE_PREFIX_BLOCK_REWARD bytes 0xf000 The substore prefix of the block reward substore.
Configurable Constants Mainchain Value
FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES uint32 1000 It determines the percentage of rewards assigned equally to all active delegates. The percentage can be obtained by dividing the value by 100, i.e., a value of 1000 corresponds to 10% .
MINIMUM_REWARD_ACTIVE_DELEGATES uint64 10^7 The minimum reward (in beddows) per round assigned to all active delegates. It is calculated as FACTOR_MINIMUM_REWARD_ACTIVE_DELEGATES * getDefaultRewardAtHeight(blockHeader.height)//10000 where blockHeader.height is the current block height.
DEFAULT_REWARD_STANDBY_DELEGATES uint64 10^8 The default reward (in beddows) per round assigned to all stand-by delegates. It is calculated as getDefaultRewardAtHeight(blockHeader.height) where blockHeader.height is the current block height.
TOTAL_REWARD_ACTIVE_DELEGATES uint64 101*10^8 The total reward of the active delegates (per round) is calculated as NUMBER_ACTIVE_DELEGATES * getDefaultRewardAtHeight(blockHeader.height) where blockHeader.height is the current block height.
STAKE_REWARD_ACTIVE_DELEGATES uint64 90.9*10^8 The remaining stake rewards for the active delegates (per round) after giving the minimum reward. It is calculated as TOTAL_REWARD_ACTIVE_DELEGATES - NUMBER_ACTIVE_DELEGATES * MINIMUM_REWARD_ACTIVE_DELEGATES
TOKEN_ID_DYNAMIC_BLOCK_REWARD bytes TOKEN_ID_LSK = 0x 00 00 00 00 00 00 00 00 The token ID of the token used for the reward system of the Blockchain.
NUMBER_ACTIVE_DELEGATES uint32 101 The number of active delegates (as defined in DPoS module).
ROUND_LENGTH uint32 103 The round length (as defined in DPoS module).

Functions from Other Modules

Calling a function fct from another module (named module) is represented by module.fct(required inputs).

Dynamic Block Rewards Module Store

The key-value pairs in the module store are organized as follows:

End-Of-Round Timestamp Substore

Substore Prefix, Store Key, and Store Value

The entry in the end-of-round timestamp substore is as follows:

  • The substore prefix is set to SUBSTORE_PREFIX_END_OF_ROUND_TIMESTAMP.
  • The store key is set to empty bytes.
  • The store value is the serialization of an object following endOfRoundTimestampStoreSchema
  • Notation: For the rest of this proposal, let endOfRoundTimestamp be the timestamp property of the entry in the end-of-round timestamp substore.
JSON Schema
endOfRoundTimestampStoreSchema = {
    "type": "object",
    "required": ["timestamp"],
    "properties": {
        "timestamp": {
            "dataType": "uint32",
            "fieldNumber": 1
        }
    }
}
Properties
  • timestamp: The timestamp of the last block in a round.

Block Reward Substore

Substore Prefix, Store Key, and Store Value

The entry in the block reward substore is as follows:

  • The substore prefix is set to SUBSTORE_PREFIX_BLOCK_REWARD.
  • The store key is set to empty bytes.
  • The store value is the serialization of an object following blockRewardStoreSchema
  • Notation: For the rest of this proposal, let blockReward be the reward property of the entry in the block reward substore.
JSON Schema
blockRewardSchema = {
    "type": "object",
    "required": ["reward"],
    "properties": {
        "reward": {
            "dataType": "uint64",
            "fieldNumber": 1
        }
    }
}
Properties
  • reward: The reward of a block in a round.

Token for Rewards

The Dynamic Block Rewards module triggers the minting of rewards in the fungible token identified by the value of TOKEN_ID_DYNAMIC_BLOCK_REWARD, which denotes a token ID. The value of TOKEN_ID_DYNAMIC_BLOCK_REWARD is set according to the initial configuration of the Dynamic Block Rewards module.

Reward Brackets

As part of the Dynamic Block Rewards module configuration, the module has to define certain reward brackets, i.e., the values of the default block reward depending on the height of the block. For this LIP, we assume the reward brackets are given by the function getDefaultRewardAtHeight, which returns a 64-bit unsigned integer value, the default block reward, given the block height as input.

Lisk Mainchain Configuration

Mainchain Rewards Token

The token for rewards on the Lisk mainchain is the LSK token.

Mainchain Reward Brackets

The reward brackets for the Lisk Mainchain are as follows:

Height Default Reward
From 1,451,520 to 4,451,519 5 × 108
From 4,451,520 to 7,451,519 4 × 108
From 7,451,520 to 10,451,519 3 × 108
From 10,451,520 to 13,451,519 2 × 108
From 13,451,520 onwards 1 × 108

This corresponds to default rewards of 5 LSK, 4 LSK, 3 LSK, 2 LSK, and 1 LSK respectively.

Commands

This module does not define any command.

Events

rewardMinted

The event is emitted when the reward is minted. In case of a reward reduction, it provides information about the reason for the reduction. This event has the name = EVENT_NAME_REWARD_MINTED.

Topics

  • generatorAddress: the address of the block generator that obtains the reward.

Data

rewardMintedDataSchema = {
    "type": "object",
    "required": ["amount", "reduction"],
    "properties": {
        "amount": {
            "dataType": "uint64",
            "fieldNumber": 1
        },
        "reduction": {
            "dataType": "uint32",
            "fieldNumber": 2
        }
    }
}
  • amount: the amount of rewards minted.
  • reduction: an integer indicating whether the reward was reduced and for which reason. Allowed values are: REWARD_NO_REDUCTION, REWARD_REDUCTION_SEED_REVEAL, REWARD_REDUCTION_MAX_PREVOTES.

Internal Functions

The Dynamic Block Rewards module has the following internal functions.

getDynamicBlockReward

This function is used to retrieve the reward of a block for a delegate.

Returns

  • amount: amount of block reward to be minted.
  • reduction: an integer indicating whether the reward is reduced. Possible values are REWARD_NO_REDUCTION, REWARD_REDUCTION_SEED_REVEAL, REWARD_REDUCTION_MAX_PREVOTES.
def getDynamicBlockReward(blockHeader: BlockHeader)-> tuple[uint64, uint32]:
    if Random.isSeedRevealValid(blockHeader.generatorAddress, blockHeader.seedReveal) == False:
        return (0, REWARD_REDUCTION_SEED_REVEAL)

    defaultReward = getDefaultBlockReward(blockHeader)

    if blockHeader.impliesMaximalPrevotes == False:
        return (defaultReward // REWARD_REDUCTION_FACTOR_BFT, REWARD_REDUCTION_MAX_PREVOTES)

    return (defaultReward, REWARD_NO_REDUCTION)

Here // represents integer division.

getDefaultBlockReward

This function is used to retrieve the default block reward for a delegate.

Returns

  • reward: amount of default block reward.
def getDefaultBlockReward(blockHeader: BlockHeader) -> uint64:
    if len(Validators.getGeneratorsBetweenTimestamps(endOfRoundTimestamp, blockHeader.timestamp)) >= ROUND_LENGTH:
        return MINIMUM_REWARD_ACTIVE_DELEGATES

    validatorParams = Validators.getValidatorParams()
    totalBftWeight = sum(validator.bftWeight for validator in validatorParams.validators)

    let validator be the item of validatorParams.validators with item.address == blockHeader.generatorAddress

    if validator.bftWeight > 0:
        reward = MINIMUM_REWARD_ACTIVE_DELEGATES + (validator.bftWeight*STAKE_REWARD_ACTIVE_DELEGATES)//totalBftWeight
        return reward
    else:
        return DEFAULT_REWARD_STANDBY_DELEGATES

Protocol Logic for Other Modules

The Dynamic Block Rewards module exposes the following functions for other modules.

getDefaultRewardAtHeight

This function is used to retrieve the expected default reward at a given height.

Parameters

The height of a block as a 32-bit unsigned integer.

Returns

The default reward of the block as a 64-bit unsigned integer.

Endpoints for Off-Chain Services

TBD.

Genesis Block Processing

Genesis State Initialization

After the genesis block b is executed, the following logic is executed:

  • Create the entry in the end-of-round timestamp substore, setting endOfRoundTimestamp.timestamp to b.header.timestamp.

Genesis State Finalization

The Dynamic Block Rewards module does not execute any logic during the genesis state finalization.

Block Processing

Before Transactions Execution

Before the transactions of a block b are executed, the following logic is executed:

def beforeTransactionsExecute(b: Block) -> None:
    #update blockReward value of the block reward substore
    (blockReward, reduction) = getDynamicBlockReward(b.header)

After Transactions Execution

The following function assigns block rewards after all transactions in the block are executed.

def afterTransactionsExecute(b: Block) -> None:
    if blockReward > 0:
        Token.mint(b.header.generatorAddress, TOKEN_ID_DYNAMIC_BLOCK_REWARD, blockReward)
        DPoS.updateSharedRewards(b.header.generatorAddress, TOKEN_ID_DYNAMIC_BLOCK_REWARD, blockReward)

    if DPoS.isEndOfRound(b.header.height):
	#update the entry in the End-Of-Round timestamp substore
        endOfRoundTimestamp = b.header.timestamp

    emitEvent(
        module = MODULE_NAME_DYNAMIC_BLOCK_REWARDS,
        name = EVENT_NAME_REWARD_MINTED,
        data = {
            "amount": blockReward,
            "reduction": reduction
            },
        topics = [b.header.generatorAddress]
    )

Backwards Compatibility

This LIP defines the interface for the Dynamic Block Rewards module but does not introduce any change to the protocol, hence it is a backward compatible change.

1 Like

I have created a PR for this proposal on GitHub: Add LIP "Introduce dynamic block rewards module" by vjaiman · Pull Request #189 · LiskHQ/lips · GitHub

1 Like

Seeing the numbers to help predict potential outcomes is very useful. So thank you for this response on another thread.

  1. From your example of 5 Poor Delegates being more profitable then voting for 1 Rich Delegate. I bring this up because the changes in core 3.0 helped ensure that there is no incentive to create groups and removed many cartels that were seen as an issue. Was this a conscious decision to re introduce incentives / leverage which could lead to groups reforming? I’m not saying it’s necessarily bad but it seems like a side effect, so I wonder what are your thoughts on this?

  2. In a similar scenario, what happens if 10 rich delegates are available. Would voters be incentivized to vote for 10 Rich Delegates over 10 Poor Delegates? How would small delegates compete?

  3. My third question involves the calculations. Is the idea of voting for more Poor Delegates being more profitable then a Rich Delegate only true up to a certain threshold?

For example, lets increase the Rich Delegate and reduce the Poor Delegate. This is still within the range of current and very possible amounts.

  • Rich delegate gets 0.1 + 90.9 * 0.04 = 3.736 LSK per round (doubled from original 2%)

  • Small delegates get 0.1 + 90.9 * 0.002 = 0.2818 LSK per round (halved from original .4%)

In this scenario, even voting for 10 Poor Delegates would not return as much as 1 Rich Delegate. If I am miss calculating then please feel free to correct me / explain the formula. Thanks.

1 Like

In general in the PoS system, rich delegates form groups to have a majority among delegates. As mentioned in the previous example, rich delegates are not profitable to form a group. On the other hand, if 5 poor delegates create groups then there is a possibility that they might not be in the list of next round since they are at the lowest stakes and every delegate would want to increase their stake to be in the next round. Therefore, in this proposal, the tradeoff for a voter is, if they vote for a poor delegate they will be slightly more compensated. On the other hand, a rich delegate is the stable delegate and more trustworthy so a voter might be interested to vote for the rich delegate with slightly less rewards.

The presentation in the previous post of comparing 1 rich delegate of 2% vs 2 delegates with 1% of TVL vs 5 small with 0.4% of TVL was just to make the example simpler. The idea being that if you vote amount X for the rich delegate you have a certain fraction of their total votes, call it W. Then, if you vote the same amount for a delegate of 0.4%, then the fraction of total votes for this delegate is 5*W, and the same exact result would be obtained. I just presented it in the way of voting X/5 for 5 delegates just to keep the focus on the % of TVL and not get into details of the fractions of votes for each delegate.
Concretely for your question, let us see the calculations that show that voters wouldn’t be incentivized more to vote for 10 rich delegates over 10 poor delegates (I assume everywhere that we compare delegates with the same commission). As per the previous example:
10 Rich delegates gets (0.1 + 90.9 * 0.02) * 10 = 19.18 LSK per round
10 poor delegates get (0.1 + 90.9 * 0.004) * 10 = 4.636 LSK per round
Assume that voting an amount X for the rich delegates (say X/10 to each of them - but this doesn’t really matter) implies voting fraction W of their total votes. Then, for poor delegates voting amount X would give 5 * W fraction of votes. Therefore, in the case of poor delegates the reward shared with the voter will be:

4.636 * 5 * W * (1 - commission) = 23.18 * W * (1 - commission)
On the other hand, the corresponding reward shared by rich delegates will be:

19.18 * W * (1 - commission),

which is clearly less. To make the example more concrete, assume that the voted amount X corresponds to 1% of total TVL. Then, W = 1/20, since the total votes of rich delegates correspond to 20% of total TVL. To see that it will be more profitable to vote for poor delegates than rich delegates, we calculate the actual rewards, assuming 10% commission from all considerer delegates.
For the rich delegates group, a voter with X = 1% of TVL, stake gets 19.18 * 1/20 * (1-commission) = 0.959 * 0.9 = 0.8631 LSK per round.
For a poor delegate group, a voter with X = 1% of TVL gets 4.636 * 5/20 * (1-commission) = 1.159 * 0.9 = 1.0431 LSK per round.
Clearly, poor delegates have a winning over rich delegates either they are individual or form a group.

In the scenario you mentioned, still poor delegates have a profit over rich delegates. Since the poor delegate is at 0.2% and the rich delegate is at 4%. Therefore a rich delegate is equivalent to 20 poor delegates.
0.2 % * 20 = 4%
Therefore by calculation 20 * 0.2818 = 5.636 LSK > 3.736 LSK.
Since (as explained above), there is no real need to split 1 vote of “rich” delegate to multiple votes for poor ones, then again, poor delegates are more profitable.

1 Like

The pull request was merged and the LIP has now status Draft:

1 Like

Thanks for the information and explanations.

If you scale this scenario, would a group of 10 rich delegates produce more then 100 poor delegates, making it impossible for poor delegates to compete?

This scenario would also only work if the voter has 200 LSK to be able to split into the minimum of 10 votes per delegate, so voters with only 100 LSK would be incentivized to vote for the 1 rich delegate instead of 10 poor delegates with these numbers?

I think the remaining concerns involve a concentration of power leading to a weakening of the network security. Such as a Pareto scenario where 20% of the network has +80% of the TVL and forging rewards. If the remaining 20% of the TVL is distributed between the remaining 80% of delegates then the cost to attack the network by purchasing 34 delegates would be 8.5% of the TVL.

If TVL is only 1/3 of the total supply then in this scenario one only needs 2.833% of the total supply to gains 34 delegate positions. This would put the cost of attack within the range of many single wallets. In a future with functioning Lisk defi it is not unlikely that 3% of the total supply could be secured with a loan.

What are your thoughts are on the above scenario and concerns with the potential decrease in security?

Has there been thought into the game theory and possible landscape of the delegates if these changes are implemented? If so, what is considered the most likely outcome and has the Pareto scenario I mentioned above been thought of as one outcome?

Perhaps one way to help mitigate this would be to decrease the maximum lock from 5 million to 2 million, or even less with incremental increases.

1 Like

In dynamic block rewards, the rewards distribution is proportional to the stakes. Therefore, rich delegates will get more rewards compared to poor delegates since they are holding more stakes. But as explained earlier, for an amount X of a voter, voters will be incentivized more to vote for poor delegates compared to rich delegates. And, this will increase the stakes of a poor delegate over a time period.
For a voter, there is no need to split their stakes (unless necessary) and it is always profitable to vote for poor delegates irrespective of their stakes.

We had a thought about it while writing the specifications. We made the changes in the LIP to avoid the situation you mentioned. Although the scenario is related to BFT-weights and therefore not a part of the new LIP draft. But this change has been included in the DPoS LIP update.

We set the BFT-weight of the active delegates proportional to the delegate weight. By setting the BFT weights proportional to delegate weight instead of uniform BFT weights for all active delegates as done before, we can improve the security guarantees of the BFT consensus protocol. For more information on how BFT-weights are set, please have a look here.

1 Like

Hello,

After reading the initial conversation and this LIP and I believe the biggest mistake made in the logic is that you consider the votes to be extremely liquid. They are not as liquid as you think. They actually are almost not liquid at all.

Once voters have set their votes, they forget about it.

When the new protocol kicks in, some rich delegates will rapidly secure a 5% position with high self-vote and high shares. After that, they can reduce the share percentage to something very low. They will still keep their self-vote because they need to retain their total weight to keep the 5% but the voters will be fucked.
The bottom delegates will be incentivized to set high share percentage to gain weight, but since the votes are not liquid at all, they will very likely fail to acquire enough weight to impact their dynamic block reward and feed the positive loop.
The top delegates will therefore increase their personnal token stack and will then be able to vote each others at the top, so they all keep their position. Eventually they will become rich enough to create a new 5% delegate.

Congratulations you have just introduced the Elite mafia inside the Lisk protocol.

This is a gigantic step backward, 5 years in the past.

The only way to mitigate this massive flaw is to make the reward protocol remove all votes when a delegate change its share percentage.

1 Like

My first thought after reading this LIP was that it would be better to have a reward structure that raises the standby delegates to active delegates.

Even if standby delegates can always get 1 LSK, the gap with active delegates will continue to widen because the percentage of standby delegates participating in forging is not even.

In my experience, voting(including self-voting), finally moves when the standby delegate and the active delegate are swapped.

In this LIP, active delegates with fewer votes will always have fewer votes, and delegates with more votes will always have more votes.

That does not change even if LIP:reward sharing mecanism is applied.

1 Like

Thank you @JesusTheHun for the query.

We have introduced a reward sharing mechanism which does not allow validators to increase the commission by more than 5% for each transaction. Moreover, after increasing the commission, a validator can not increase it again for the next COMMISSION_INCREASE_PERIOD = 30 days. Therefore, a validator can not increase the commission by more than 5% per month. When the new protocol kicks in, it is not possible for a validator to set the commission “low” initially and once it reaches to 5% position, increase the commission to “very high” suddenly.

  • Regarding your comment on non-liquid votes: The aforementioned constraints in the commission increase, are set to protect voters who don’t check their accounts regularly, therefore we have taken into account the fact that votes are not liquid. Still, we expect that voters who stake their tokens, check their accounts once every 4-5 months in order to claim their rewards.

So for example if a voter voted a validator with 10% commission, then after one month the commission can increase to at most 15% (share from 90% to 85%) therefore the voter gets 85/90 = 94.4% percent of their expected rewards for the first month. Even after 5 months commission can increase to at most 35% (share 65%), therefore they still get 65/90 = 72.2% of their expected rewards. I am not going to the precise calculation, but if you average this out, over 5 months they get more than 80% of their expected rewards. Then, if they observe that the validator is increasing the commission as much as they can, it is natural to switch votes and remove support from this validator. So your worry about voters is not valid.

  • About increasing the personal token stack and therefore leading to an elite-cartel: Due to the constraints discussed above, the increase in personal stack is not enough to balance the loss of votes for a validator who constantly increases commission as much as they can.

Therefore, for rich validators it is not possible to increase the personal token stack by just increasing the commission and creating another new 5% validator.

1 Like

Thank you @mdmg for your query.

Indeed, that is the exact reason why we kept the same reward structure for standby delegates as 1 LSK irrespective of their weight. The standby delegates are encouraged to lock more tokens and voters are encouraged to vote for standby delegates who are close to the weight of the lowest active delegate to earn more rewards. This way the standby delegate has a chance to become an active delegate.

As already mentioned in previous replies, for a voter it is always beneficial to vote for a delegate with low delegate weight to get more reward assuming the same commission is set by all delegates. Therefore, voters are always encouraged to vote for a low weight delegate and eventually the delegate with low weight delegate will get more votes.

1 Like

Can you share some simulations please?

1 Like

@JesusTheHun Please have a look on the spreadsheet.
As you can notice, a high weight validator can earn maximum ~4091 LSK, after increasing the commission to 35% (initially it was set to 10% and the maximum commission increase is 5% each month ) which is very low to increase their personal stack and create another delegate. Similarly, a staker (or voter) have an average loss of 16.67% in six months.

As mentioned before, we expect the stakers to check their account once in 6 month to claim rewards and then they can switch their stakes/votes to another validator when they notice that the validator is increasing the commission every month.

1 Like