Skip to content

Latest commit

 

History

History
225 lines (150 loc) · 10 KB

lip-0042.md

File metadata and controls

225 lines (150 loc) · 10 KB
LIP: 0042
Title: Define state transitions of Reward module
Author: Iker Alustiza <iker@lightcurve.io>
        Mehmet Egemen Albayrak <mehmet.albayrak@lightcurve.io>
Discussions-To: https://research.lisk.com/t/define-state-transitions-of-reward-module
Status: Active
Type: Standards Track
Created: 2021-08-03
Updated: 2024-01-04
Requires: 0042, 0051, 0058

Abstract

The Reward module provides the base reward system for a blockchain developed with the Lisk SDK. In this LIP, we specify the protocol logic that this module injects during the block lifecycle as well as the functions that can be called from off-chain services.

Copyright

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

Motivation

The goal of this LIP is to modularize the rewards assignment logic when a new block is generated. For this purpose, we specify the Reward module, which will make it easier to customize this logic and replace it if necessary.

Rationale

The Reward module induces specific logic after the application of a block:

  • After applying the block, a certain quantity of the native token of the blockchain is minted and assigned to the block generator. The exact amount assigned to the block generator, i.e., the reward, is calculated depending on the rules of the Random module and the property impliesMaxPrevotes of the block header.

Specification

In this section, we specify the protocol logic in the lifecycle of a block injected by the Reward module as well as the functions that can be called from off-chain services. It depends on the token and random modules.

Types

Name Type Validation Description
BlockHeader object see LIP 0055 The header of a block.
Block object see LIP 0055 The block object.
BlockAssets object see LIP 0055 An object representing the block assets property of a block.

Constants

Name Type Value Description
MODULE_NAME_REWARD string "reward" The module name of the Reward 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_NO_ACCOUNT uint32 3 Return code for block reward reduction because the TOKEN_ID_REWARD account is not initialized.
Configurable Constants Suggested Value
TOKEN_ID_REWARD bytes specified as part of module configuration The token ID of the token used for the reward system of the blockchain.
REWARD_REDUCTION_FACTOR_BFT uint32 4 The reduction factor for the block reward in case the block header does not imply the maximal number of prevotes.

Token for rewards

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

Reward Brackets

As part of the Reward 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(height), which returns a 64-bit unsigned integer value, the default block reward, given the block height height as input.

Reward Brackets Example

As an example, consider the reward brackets for the Lisk Mainchain:

Heights 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.

Functions from Other Modules

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

State Store

This module does not define any state store.

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 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, and REWARD_REDUCTION_NO_ACCOUNT.

Internal Functions

The Reward module has the following internal function.

getBlockReward

This function is used to retrieve the reward of a block at a given height.

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, and REWARD_REDUCTION_NO_ACCOUNT.
Execution
def getBlockReward(blockHeader: BlockHeader, blockAssets: BlockAssets) -> tuple[uint64, uint32]:
  if Random.isSeedRevealValid(blockHeader.generatorAddress, blockAssets) == False:
    return (0, REWARD_REDUCTION_SEED_REVEAL)

  defaultReward = getDefaultRewardAtHeight(blockHeader.height)
  
  if blockHeader.impliesMaxPrevotes == False:
    return (defaultReward // REWARD_REDUCTION_FACTOR_BFT, REWARD_REDUCTION_MAX_PREVOTES)

  return (defaultReward, REWARD_NO_REDUCTION)

Protocol Logic for Other Modules

This module does not define any specific logic for other modules.

Endpoints for Off-Chain Services

This section specifies the non-trivial or recommended endpoints of the Reward module and does not include all endpoints.

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.

Block Processing

Before Transactions Execution

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

def beforeTransactionsExecute(b: Block) -> None:
    (ctx.blockReward, ctx.reduction) = getBlockReward(b.header, b.blockAssets)

Here, we calculate the reward for the block generator; then this value will be stored in the context in memory for the afterTransactionsExecute in order to mint this reward and assign it to the generator. The reason for calculating the reward here is to make sure that during the call to getBlockReward function, the subsequent call to isSeedRevealValid function of Random module takes the value from the validatorReveals array. Therefore, if we calculate the reward in afterTransactionsExecute, there might be a case where validatorReveals array are being updated by Random module before calculating the reward and then it might not produce a correct result.

After Transactions Execution

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

def afterTransactionsExecute(b: Block) -> None:
    if ctx.blockReward > 0:
        if Token.userSubstoreExists(b.header.generatorAddress, TOKEN_ID_REWARD):
            Token.mint(b.header.generatorAddress, TOKEN_ID_REWARD, ctx.blockReward)
        else:
            ctx.blockReward = 0
            ctx.reduction = REWARD_REDUCTION_NO_ACCOUNT

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

where TOKEN_ID_REWARD is the token ID of the token used for the reward system of the blockchain.

Backwards Compatibility

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

Reference Implementation

Introduce Reward Module