Skip to content

Commit

Permalink
fix(calc): rework calculating fees (#937)
Browse files Browse the repository at this point in the history
* remove calcFee

* remove all calcFee tests

* remove all calcFee associated types

* remove export for MetadataConsts

* adjust mock response to reflect api.rpc.payment.queryInfo

* remove ICalcFee

* handle minCalcFeeRuntime

* adjust minCalcFeeRuntime error message

* fix e2e tests for kusama

* adjust polkadot e2e-tests

* add a check for rpc.payment
  • Loading branch information
TarikGul committed Jun 3, 2022
1 parent f4f531a commit 3306466
Show file tree
Hide file tree
Showing 10 changed files with 35 additions and 519 deletions.
10 changes: 5 additions & 5 deletions e2e-tests/endpoints/kusama/blocks/10819306.json
Original file line number Diff line number Diff line change
Expand Up @@ -2027,7 +2027,7 @@
"info": {
"weight": "1177134000",
"class": "Normal",
"partialFee": "51999544"
"partialFee": "52002823"
},
"era": {
"mortalEra": [
Expand Down Expand Up @@ -2173,7 +2173,7 @@
"info": {
"weight": "2623797000",
"class": "Normal",
"partialFee": "51999582"
"partialFee": "52002823"
},
"era": {
"mortalEra": [
Expand Down Expand Up @@ -2379,7 +2379,7 @@
"info": {
"weight": "1659355000",
"class": "Normal",
"partialFee": "51999557"
"partialFee": "52002823"
},
"era": {
"mortalEra": [
Expand Down Expand Up @@ -2545,7 +2545,7 @@
"info": {
"weight": "1177134000",
"class": "Normal",
"partialFee": "51999544"
"partialFee": "52002823"
},
"era": {
"mortalEra": [
Expand Down Expand Up @@ -2691,7 +2691,7 @@
"info": {
"weight": "1177134000",
"class": "Normal",
"partialFee": "51999544"
"partialFee": "52002823"
},
"era": {
"mortalEra": [
Expand Down
4 changes: 3 additions & 1 deletion e2e-tests/endpoints/kusama/blocks/2350438.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@
"tip": "0",
"hash": "0x3f5a8e3b5dae4e28252d98e8464f29b50b08a49a36cf71ac009c9a791c1ffa82",
"info": {
"error": "Fee calculation not supported for 1062#kusama"
"weight": "195000000",
"class": "Normal",
"partialFee": "1000000000"
},
"era": {
"mortalEra": [
Expand Down
4 changes: 2 additions & 2 deletions e2e-tests/endpoints/kusama/blocks/6566865.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@
"info": {
"weight": "423471000",
"class": "Normal",
"partialFee": "4033332350"
"partialFee": "4033332622"
},
"era": {
"mortalEra": [
Expand Down Expand Up @@ -782,7 +782,7 @@
"info": {
"weight": "423471000",
"class": "Normal",
"partialFee": "4033332350"
"partialFee": "4033332622"
},
"era": {
"mortalEra": [
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/endpoints/polkadot/blocks/4392619.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@
"info": {
"weight": "181791000",
"class": "Normal",
"partialFee": "201000014"
"partialFee": "201000024"
},
"era": {
"mortalEra": [
Expand Down
192 changes: 2 additions & 190 deletions src/services/blocks/BlocksService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@

import { ApiPromise } from '@polkadot/api';
import { ApiDecoration } from '@polkadot/api/types';
import { AugmentedConst } from '@polkadot/api/types';
import { PromiseRpcResult } from '@polkadot/api-base/types/rpc';
import { GenericExtrinsic, u128, Vec } from '@polkadot/types';
import { GenericExtrinsic } from '@polkadot/types';
import { GenericCall } from '@polkadot/types/generic';
import { BlockHash, Hash, SignedBlock } from '@polkadot/types/interfaces';
import { FrameSupportWeightsWeightToFeeCoefficient } from '@polkadot/types/lookup';
import { BadRequest } from 'http-errors';
import LRU from 'lru-cache';

Expand All @@ -30,17 +28,13 @@ import { createCall } from '../../test-helpers/createCall';
import {
kusamaRegistry,
polkadotRegistry,
polkadotRegistryV9190,
} from '../../test-helpers/registries';
import { TypeFactory } from '../../test-helpers/typeFactory';
import { ExtBaseWeightValue, PerClassValue } from '../../types/chains-config';
import { IBlock, IExtrinsic } from '../../types/responses/';
import { IBlock } from '../../types/responses/';
import {
blockHash20000,
blockHash100000,
blockHash789629,
defaultMockApi,
mockBlock789629,
mockForkedBlock789629,
} from '../test-helpers/mock';
import block789629 from '../test-helpers/mock/data/block789629.json';
Expand Down Expand Up @@ -114,13 +108,6 @@ type GetBlock = PromiseRpcResult<
(hash?: string | BlockHash | Uint8Array | undefined) => Promise<SignedBlock>
>;

/**
* Interface for the reponse in `fetchBlock` test suite
*/
interface ResponseObj {
extrinsics: IExtrinsic[];
}

// LRU cache used to cache blocks
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const cache = new LRU({ max: 2 }) as LRU<string, IBlock>;
Expand Down Expand Up @@ -212,181 +199,6 @@ describe('BlocksService', () => {

expect(block.finalized).toEqual(undefined);
});

it('Return an error with a null calcFee when perByte is undefined', async () => {
mockHistoricApi.consts.transactionPayment.transactionByteFee =
undefined as unknown as u128 & AugmentedConst<'promise'>;

const configuredBlocksService = new BlocksService(mockApi, 0, new LRU());

// fetchBlock options
const options = {
eventDocs: true,
extrinsicDocs: true,
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
};

const response = sanitizeNumbers(
await configuredBlocksService.fetchBlock(
blockHash789629,
mockHistoricApi,
options
)
);

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const responseObj: ResponseObj = JSON.parse(JSON.stringify(response));

// Revert mockApi back to its original setting that was changed above.
mockHistoricApi.consts.transactionPayment.transactionByteFee =
polkadotRegistry.createType('Balance', 1000000) as u128 &
AugmentedConst<'promise'>;

expect(responseObj.extrinsics[3].info).toEqual({
error: 'Fee calculation not supported for 16#polkadot',
});
});
});

describe('createCalcFee & calc_fee', () => {
it('calculates partialFee for proxy.proxy in polkadot block 789629', async () => {
// Reset LRU cache
cache.reset();
// tx hash: 0x6d6c0e955650e689b14fb472daf14d2bdced258c748ded1d6cb0da3bfcc5854f
const { calcFee } = await blocksService['createCalcFee'](
mockApi,
mockHistoricApi,
'0xParentHash' as unknown as Hash,
mockBlock789629
);

expect(calcFee?.calc_fee(BigInt(399480000), 534, BigInt(125000000))).toBe(
'544000000'
);
});

it('calculates partialFee for utility.batch in polkadot block 789629', async () => {
// Reset LRU cache
cache.reset();
// tx hash: 0xc96b4d442014fae60c932ea50cba30bf7dea3233f59d1fe98c6f6f85bfd51045
const { calcFee } = await blocksService['createCalcFee'](
mockApi,
mockHistoricApi,
'0xParentHash' as unknown as Hash,
mockBlock789629
);

expect(
calcFee?.calc_fee(BigInt(941325000000), 1247, BigInt(125000000))
).toBe('1257000075');
});
});

describe('getPerByte', () => {
it('Correctly handles LengthToFee', () => {
// Reset LRU cache
cache.reset();

/**
* Setup a mockApiClone specific to v9190
*/
const mockHistoricApiClone = {
...mockHistoricApi,
registry: polkadotRegistryV9190,
} as unknown as ApiDecoration<'promise'>;

/**
* Typecast here because the typefactory just needs the registry so this is safe.
* It's a shortcut so that constructing a augmented api is not necessary.
*/
const polkadotV9190TypeFactory = new TypeFactory(
mockHistoricApiClone as ApiPromise
);

/**
* Create a Vec<FrameSupportWeightsWeightToFeeCoefficient> type
* The `coeffInteger` value here should be different from
* `transactionByteFee` set in mockHistoricApi in order to properly
* distinquish values.
*/
const lengthToFeeStruct = polkadotRegistryV9190.createType(
'FrameSupportWeightsWeightToFeeCoefficient',
{ coeffInteger: 12345678 }
);
const lengthToFee = polkadotV9190TypeFactory.vecOf([lengthToFeeStruct]);

/**
* Remove TransactionByteFee from our clone and replace it with LengthToFee
*/
(mockHistoricApiClone.consts.transactionPayment[
'transactionByteFee'
] as unknown) = undefined;
mockHistoricApiClone.consts.transactionPayment['lengthToFee'] =
lengthToFee as unknown as Vec<FrameSupportWeightsWeightToFeeCoefficient> &
AugmentedConst<'promise'>;

const result = blocksService['getPerByte'](mockHistoricApiClone);

expect(sanitizeNumbers(result)).toEqual('12345678');
});
});

describe('BlocksService.getWeight', () => {
it('Should return correct `extrinsicBaseWeight`', () => {
// Reset LRU cache
cache.reset();

const weightValue = blocksService['getWeight'](mockHistoricApi);

expect(
(weightValue as unknown as ExtBaseWeightValue).extrinsicBaseWeight
).toBe(BigInt(125000000));
});

it('Should return correct `blockWeights`', () => {
// Reset LRU cache
cache.reset();

/**
* This is the mockApi adjusted to mock a runtime that uses
* consts.system.blockWeights for its weight nomination.
*/
const mockHistoricApiAdjusted = {
consts: {
system: {
blockWeights: {
perClass: {
normal: {
baseExtrinsic: polkadotRegistry.createType('u64', 125000000),
},
operational: {
baseExtrinsic: polkadotRegistry.createType('u64', 125000000),
},
mandatory: {
baseExtrinsic: polkadotRegistry.createType('u64', 125000000),
},
},
},
},
},
} as unknown as ApiDecoration<'promise'>;

const weightValue = blocksService['getWeight'](mockHistoricApiAdjusted);

expect(
(weightValue as unknown as PerClassValue).perClass.normal.baseExtrinsic
).toBe(BigInt(125000000));
expect(
(weightValue as unknown as PerClassValue).perClass.operational
.baseExtrinsic
).toBe(BigInt(125000000));
expect(
(weightValue as unknown as PerClassValue).perClass.mandatory
.baseExtrinsic
).toBe(BigInt(125000000));
});
});

describe('BlocksService.parseGenericCall', () => {
Expand Down
Loading

0 comments on commit 3306466

Please sign in to comment.