Skip to content

Commit

Permalink
feat: support for feeByEvent query param which will abstract the fe…
Browse files Browse the repository at this point in the history
…es by events (#970)

* add query param feeByEvent to all applicable controllers

* add compare integers

* support for query param feeByEvent

* fix grumble

* fix compare.spec.ts

* inline comments

* add tests for getPartialFeeByEvents

* change error message

* create mock event data

* remove unneccessary comments

* add tests getPartialFeeInfo

* export constructEvent

* docs

* provide a better description for feeByEvent in docs

* create areFeesSimilar

* create findEvent
  • Loading branch information
TarikGul committed Jul 7, 2022
1 parent 0a911de commit 92c155d
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/dist/app.bundle.js

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions docs/src/openapi-v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,31 @@ paths:
example: 0-499
schema:
type: string
- name: eventDocs
in: query
description: When set to `true`, every event will have an extra `docs`
property with a string of the events documentation.
required: false
schema:
type: boolean
default: false
- name: extrinsicDocs
in: query
description: When set to `true`, every extrinsic will have an extra `docs`
property with a string of the extrinsics documentation.
required: false
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -427,6 +452,15 @@ paths:
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -507,6 +541,15 @@ paths:
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -554,6 +597,15 @@ paths:
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down
12 changes: 9 additions & 3 deletions src/controllers/blocks/BlocksController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@ export default class BlocksController extends AbstractController<BlocksService>
* @param res Express Response
*/
private getLatestBlock: RequestHandler = async (
{ query: { eventDocs, extrinsicDocs, finalized } },
{ query: { eventDocs, extrinsicDocs, finalized, feeByEvent } },
res
) => {
const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';

let hash, queryFinalizedHead, omitFinalizedTag;
if (!this.options.finalizes) {
Expand All @@ -149,6 +150,7 @@ export default class BlocksController extends AbstractController<BlocksService>
checkFinalized: false,
queryFinalizedHead,
omitFinalizedTag,
getFeeByEvent,
};

const historicApi = await this.api.at(hash);
Expand All @@ -166,7 +168,7 @@ export default class BlocksController extends AbstractController<BlocksService>
* @param res Express Response
*/
private getBlockById: RequestHandler<INumberParam> = async (
{ params: { number }, query: { eventDocs, extrinsicDocs } },
{ params: { number }, query: { eventDocs, extrinsicDocs, feeByEvent } },
res
): Promise<void> => {
const checkFinalized = isHex(number);
Expand All @@ -175,6 +177,7 @@ export default class BlocksController extends AbstractController<BlocksService>

const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';

const queryFinalizedHead = !this.options.finalizes ? false : true;
const omitFinalizedTag = !this.options.finalizes ? true : false;
Expand All @@ -185,6 +188,7 @@ export default class BlocksController extends AbstractController<BlocksService>
checkFinalized,
queryFinalizedHead,
omitFinalizedTag,
getFeeByEvent,
};

// HistoricApi to fetch any historic information that doesnt include the current runtime
Expand Down Expand Up @@ -249,7 +253,7 @@ export default class BlocksController extends AbstractController<BlocksService>
unknown,
IRangeQueryParam
> = async (
{ query: { range, eventDocs, extrinsicDocs } },
{ query: { range, eventDocs, extrinsicDocs, feeByEvent } },
res
): Promise<void> => {
if (!range) throw new BadRequest('range query parameter must be inputted.');
Expand All @@ -259,6 +263,7 @@ export default class BlocksController extends AbstractController<BlocksService>

const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';
const queryFinalizedHead = !this.options.finalizes ? false : true;
const omitFinalizedTag = !this.options.finalizes ? true : false;
const options = {
Expand All @@ -267,6 +272,7 @@ export default class BlocksController extends AbstractController<BlocksService>
checkFinalized: false,
queryFinalizedHead,
omitFinalizedTag,
getFeeByEvent,
};

const pQueue = new PromiseQueue(4);
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/blocks/BlocksExtrinsicsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,23 @@ export default class BlocksExtrinsicsController extends AbstractController<Block
private getExtrinsicByTimepoint: RequestHandler<INumberParam> = async (
{
params: { blockId, extrinsicIndex },
query: { eventDocs, extrinsicDocs },
query: { eventDocs, extrinsicDocs, feeByEvent },
},
res
): Promise<void> => {
const hash = await this.getHashForBlock(blockId);

const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';

const options = {
eventDocs: eventDocsArg,
extrinsicDocs: extrinsicDocsArg,
checkFinalized: true,
queryFinalizedHead: false,
omitFinalizedTag: true,
getFeeByEvent,
};

const historicApi = await this.api.at(hash);
Expand Down
97 changes: 96 additions & 1 deletion src/services/blocks/BlocksService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
kusamaRegistry,
polkadotRegistry,
} from '../../test-helpers/registries';
import { IBlock } from '../../types/responses/';
import { IBlock, ISanitizedEvent } from '../../types/responses/';
import {
blockHash20000,
blockHash100000,
Expand All @@ -39,6 +39,12 @@ import {
} from '../test-helpers/mock';
import block789629 from '../test-helpers/mock/data/block789629.json';
import { events789629 } from '../test-helpers/mock/data/events789629Hex';
import {
balancesDepositEvent,
constructEvent,
treasuryEvent,
withdrawEvent,
} from '../test-helpers/mock/data/mockEventData';
import { validators789629Hex } from '../test-helpers/mock/data/validators789629Hex';
import { parseNumberOrThrow } from '../test-helpers/mock/parseNumberOrThrow';
import block789629Extrinsic from '../test-helpers/responses/blocks/block789629Extrinsic.json';
Expand Down Expand Up @@ -128,6 +134,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};

expect(
Expand Down Expand Up @@ -163,6 +170,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};
const tempGetBlock = mockApi.rpc.chain.getBlock;
mockApi.rpc.chain.getBlock = (() =>
Expand All @@ -189,6 +197,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: true,
getFeeByEvent: false,
};

const block = await blocksService.fetchBlock(
Expand Down Expand Up @@ -413,6 +422,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};

it('Returns the correct extrinisics object for block 789629', async () => {
Expand Down Expand Up @@ -518,6 +528,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};

it('Should correctly store the most recent queried blocks', async () => {
Expand All @@ -542,4 +553,88 @@ describe('BlocksService', () => {
expect(cache.length).toBe(2);
});
});

describe('FeeByEvent', () => {
describe('getPartialFeeByEvents', () => {
const partialFee = polkadotRegistry.createType('Balance', '2490128143');
const expectedResponse = { partialFee: '2490128143' };

it('Should retrieve the correct fee for balances::withdraw events', () => {
const response = blocksService['getPartialFeeByEvents'](
withdrawEvent,
partialFee
);

expect(response).toStrictEqual(expectedResponse);
});

it('Should retrieve the correct fee for treasury::deposit events', () => {
const response = blocksService['getPartialFeeByEvents'](
treasuryEvent,
partialFee
);

expect(response).toStrictEqual(expectedResponse);
});

it('Should retrieve the correct fee for balances::deposit events', () => {
const response = blocksService['getPartialFeeByEvents'](
balancesDepositEvent,
partialFee
);

expect(response).toStrictEqual(expectedResponse);
});

it('Should error correctly when there is no fee in the events', () => {
const expectedResponseWithError = {
...expectedResponse,
error: 'Could not find a reliable fee within the events data.',
};
const emptyArray = [] as unknown as ISanitizedEvent[];
const response = blocksService['getPartialFeeByEvents'](
emptyArray,
partialFee
);

expect(response).toStrictEqual(expectedResponseWithError);
});
});

describe('getPartialFeeInfo', () => {
const mockEvent = [
constructEvent('balances', 'Withdraw', ['0x', '149000011']),
];

it('Should correctly handle `getEventByFee` when true', async () => {
const response = await blocksService['getPartialFeeInfo'](
mockEvent,
'0x',
blockHash789629,
true
);

expect(sanitizeNumbers(response)).toStrictEqual({
dispatchClass: 'Normal',
partialFee: '149000011',
error: undefined,
});
});

it('Should correctly handle `getEventByFee` when false', async () => {
const response = await blocksService['getPartialFeeInfo'](
mockEvent,
'0x',
blockHash789629,
false
);

expect(sanitizeNumbers(response)).toStrictEqual({
dispatchClass: 'Normal',
partialFee: '149000000',
error: undefined,
});
});
});
});
});
Loading

0 comments on commit 92c155d

Please sign in to comment.