lisk-framework
Version:
Lisk blockchain application platform
155 lines • 8.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DynamicRewardModule = void 0;
const lisk_utils_1 = require("@liskhq/lisk-utils");
const lisk_validator_1 = require("@liskhq/lisk-validator");
const base_module_1 = require("../base_module");
const constants_1 = require("./constants");
const constants_2 = require("../reward/constants");
const state_machine_1 = require("../../state_machine");
const method_1 = require("./method");
const endpoint_1 = require("./endpoint");
const schemas_1 = require("./schemas");
const reward_minted_1 = require("../reward/events/reward_minted");
const end_of_round_timestamp_1 = require("./stores/end_of_round_timestamp");
const calculate_reward_1 = require("../reward/calculate_reward");
const schemas_2 = require("../reward/schemas");
const utils_1 = require("./utils");
class DynamicRewardModule extends base_module_1.BaseModule {
constructor() {
super();
this.method = new method_1.DynamicRewardMethod(this.stores, this.events);
this.configSchema = schemas_1.configSchema;
this.endpoint = new endpoint_1.DynamicRewardEndpoint(this.stores, this.offchainStores);
this.stores.register(end_of_round_timestamp_1.EndOfRoundTimestampStore, new end_of_round_timestamp_1.EndOfRoundTimestampStore(this.name, 0));
this.events.register(reward_minted_1.RewardMintedEvent, new reward_minted_1.RewardMintedEvent(this.name));
}
addDependencies(tokenMethod, randomMethod, validatorMethod, posMethod) {
this._tokenMethod = tokenMethod;
this._randomMethod = randomMethod;
this._validatorMethod = validatorMethod;
this._posMethod = posMethod;
this.endpoint.addDependencies(this._validatorMethod, this._posMethod);
}
metadata() {
return {
...this.baseMetadata(),
endpoints: [
{
name: this.endpoint.getDefaultRewardAtHeight.name,
request: schemas_2.getDefaultRewardAtHeightRequestSchema,
response: schemas_2.getDefaultRewardAtHeightResponseSchema,
},
{
name: this.endpoint.getAnnualInflation.name,
request: schemas_2.getAnnualInflationRequestSchema,
response: schemas_2.getAnnualInflationResponseSchema,
},
{
name: this.endpoint.getRewardTokenID.name,
response: schemas_2.getRewardTokenIDResponseSchema,
},
{
name: this.endpoint.getExpectedValidatorRewards.name,
request: schemas_1.getExpectedValidatorRewardsRequestSchema,
response: schemas_1.getExpectedValidatorRewardsResponseSchema,
},
],
};
}
async init(args) {
const { moduleConfig } = args;
const config = lisk_utils_1.objects.mergeDeep({}, {
...constants_1.defaultConfig,
tokenID: `${args.genesisConfig.chainID}00000000`,
}, moduleConfig);
lisk_validator_1.validator.validate(schemas_1.configSchema, config);
this._moduleConfig = {
...config,
brackets: config.brackets.map(bracket => BigInt(bracket)),
rewardReductionFactorBFT: BigInt(config.rewardReductionFactorBFT),
tokenID: Buffer.from(config.tokenID, 'hex'),
};
this.method.init({ config: this._moduleConfig });
this.endpoint.init(this._moduleConfig, args.genesisConfig.blockTime);
}
async initGenesisState(context) {
await this.stores
.get(end_of_round_timestamp_1.EndOfRoundTimestampStore)
.set(context, constants_1.EMPTY_BYTES, { timestamp: context.header.timestamp });
}
async beforeTransactionsExecute(context) {
const defaultReward = await this._getDefaultBlockReward(context.getMethodContext(), context.header);
const [blockReward, reduction] = await this._getBlockRewardDeduction(context.getMethodContext(), context.header, context.assets, defaultReward);
context.contextStore.set(constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REWARD, blockReward);
context.contextStore.set(constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REDUCTION, reduction);
}
async afterTransactionsExecute(context) {
let blockReward = (0, state_machine_1.getContextStoreBigInt)(context.contextStore, constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REWARD);
let reduction = (0, state_machine_1.getContextStoreNumber)(context.contextStore, constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REDUCTION);
if (blockReward !== BigInt(0)) {
const userSubstoreExists = await this._tokenMethod.userSubstoreExists(context, context.header.generatorAddress, this._moduleConfig.tokenID);
if (userSubstoreExists) {
await this._tokenMethod.mint(context.getMethodContext(), context.header.generatorAddress, this._moduleConfig.tokenID, blockReward);
await this._posMethod.updateSharedRewards(context.getMethodContext(), context.header.generatorAddress, this._moduleConfig.tokenID, blockReward);
}
else {
blockReward = BigInt(0);
reduction = constants_2.REWARD_REDUCTION_NO_ACCOUNT;
}
}
const isEndOfRound = await this._posMethod.isEndOfRound(context.getMethodContext(), context.header.height);
if (isEndOfRound) {
await this.stores
.get(end_of_round_timestamp_1.EndOfRoundTimestampStore)
.set(context, constants_1.EMPTY_BYTES, { timestamp: context.header.timestamp });
}
this.events.get(reward_minted_1.RewardMintedEvent).log(context, context.header.generatorAddress, {
amount: blockReward,
reduction,
});
}
async _getBlockRewardDeduction(context, header, assets, defaultReward) {
const isSeedRevealValid = await this._randomMethod.isSeedRevealValid(context, header.generatorAddress, assets);
if (!isSeedRevealValid) {
return [BigInt(0), constants_2.REWARD_REDUCTION_SEED_REVEAL];
}
if (!header.impliesMaxPrevotes) {
return [
defaultReward / this._moduleConfig.rewardReductionFactorBFT,
constants_2.REWARD_REDUCTION_MAX_PREVOTES,
];
}
return [defaultReward, constants_2.REWARD_NO_REDUCTION];
}
async _getDefaultBlockReward(context, header) {
const roundLength = this._posMethod.getRoundLength(context);
const { timestamp } = await this.stores.get(end_of_round_timestamp_1.EndOfRoundTimestampStore).get(context, constants_1.EMPTY_BYTES);
const generatorsMap = await this._validatorMethod.getGeneratorsBetweenTimestamps(context, timestamp, header.timestamp);
const defaultReward = (0, calculate_reward_1.calculateDefaultReward)(this._moduleConfig, header.height);
const minimalRewardActiveValidators = (0, utils_1.getMinimalRewardActiveValidators)(this._moduleConfig, defaultReward);
if (Object.keys(generatorsMap).length >= roundLength) {
return minimalRewardActiveValidators;
}
const validatorsParams = await this._validatorMethod.getValidatorsParams(context);
let bftWeightSum = BigInt(0);
let bftValidator;
for (const v of validatorsParams.validators) {
bftWeightSum += v.bftWeight;
if (v.address.equals(header.generatorAddress)) {
bftValidator = v;
}
}
if (!bftValidator) {
throw new Error('Invalid generator. Validator params does not include the validator.');
}
const stakeRewardActiveValidators = await (0, utils_1.getStakeRewardActiveValidators)(context, this._validatorMethod, defaultReward, minimalRewardActiveValidators);
if (bftValidator.bftWeight > BigInt(0)) {
return (minimalRewardActiveValidators +
(bftValidator.bftWeight * stakeRewardActiveValidators) / bftWeightSum);
}
return defaultReward;
}
}
exports.DynamicRewardModule = DynamicRewardModule;
//# sourceMappingURL=module.js.map