Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Implement afterBlockExecute hook for the reward module - Closes #6690 #6784

Merged
23 changes: 18 additions & 5 deletions framework/src/modules/reward/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class RewardModule extends BaseModule {
this._tokenAPI = tokenAPI;
this._randomAPI = randomAPI;
this._bftAPI = bftAPI;
this.api.addDependencies(bftAPI, randomAPI);
this.api.addDependencies(this._bftAPI, this._randomAPI);
}

// eslint-disable-next-line @typescript-eslint/require-await
Expand All @@ -62,9 +62,22 @@ export class RewardModule extends BaseModule {
});
}

// eslint-disable-next-line @typescript-eslint/require-await
public async afterBlockExecute(_context: BlockAfterExecuteContext): Promise<void> {
// eslint-disable-next-line no-console
console.log(this._tokenAPI, this._bftAPI, this._randomAPI, this._tokenIDReward);
public async afterBlockExecute(context: BlockAfterExecuteContext): Promise<void> {
const blockReward = await this.api.getBlockReward(
context.getAPIContext(),
context.header,
context.assets,
);

if (blockReward <= BigInt(0)) {
throw new Error('Reward amount to be minted is not valid.');
}

await this._tokenAPI.mint(
context.getAPIContext(),
context.header.generatorAddress,
this._tokenIDReward,
blockReward,
);
}
}
47 changes: 42 additions & 5 deletions framework/test/unit/modules/reward/reward_module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Removal or modification of this copyright notice is prohibited.
*/
import { RewardModule } from '../../../../src/modules/reward';
import { createBlockContext, createBlockHeaderWithDefaults } from '../../../../src/testing';

describe('RewardModule', () => {
const genesisConfig: any = {};
Expand All @@ -30,14 +31,15 @@ describe('RewardModule', () => {
const generatorConfig: any = {};

let rewardModule: RewardModule;

beforeAll(async () => {
let mint: any;
beforeEach(async () => {
mint = jest.fn();
rewardModule = new RewardModule();
await rewardModule.init({ genesisConfig, moduleConfig, generatorConfig });
rewardModule.addDependencies(
{ mint: jest.fn() } as any,
{ isValidSeedReveal: jest.fn() } as any,
{ impliesMaximalPrevotes: jest.fn() } as any,
{ mint } as any,
{ isValidSeedReveal: jest.fn().mockReturnValue(true) } as any,
{ impliesMaximalPrevotes: jest.fn().mockReturnValue(true) } as any,
);
});

Expand All @@ -46,4 +48,39 @@ describe('RewardModule', () => {
expect(rewardModule['_moduleConfig']).toEqual(moduleConfig);
});
});

const { brackets, offset, distance } = moduleConfig as {
brackets: ReadonlyArray<bigint>;
offset: number;
distance: number;
};

describe.each(Object.entries(brackets))(
'afterBlockExecute test for brackets',
(index, _rewardFromConfig) => {
const nthBracket = Number(index);
const currentHeight = offset + nthBracket * distance;

it(`should call mint in afterBlockExecute hook for valid ${nthBracket}th bracket`, async () => {
const blockHeader = createBlockHeaderWithDefaults({ height: currentHeight });
const blockAfterExecuteContext = createBlockContext({
header: blockHeader,
}).getBlockAfterExecuteContext();
await rewardModule.afterBlockExecute(blockAfterExecuteContext);

expect(mint).toHaveBeenCalledTimes(1);
});
},
);

it('should afterBlockExecute hook throw an error for 0 reward', async () => {
const blockHeader = createBlockHeaderWithDefaults({ height: 1 });
const blockAfterExecuteContext = createBlockContext({
header: blockHeader,
}).getBlockAfterExecuteContext();

await expect(async () =>
rewardModule.afterBlockExecute(blockAfterExecuteContext),
).rejects.toThrow('Reward amount to be minted is not valid.');
});
});