Skip to content

Commit

Permalink
Add minimal tests to show that new runtime API endpoints exist (#2254)
Browse files Browse the repository at this point in the history
* Add minimal tests to show that new runtime API endpoints exist

* prettier

* WIP: trying to reassemble substrate fees

* Basic fee calc works

* prettier

* Remove dead code

* Prefer const over let 🙈

* Validate substrate tips properly (burned)

* Remove console.log()

* Use well-defined constant

* Fix merge conflict 👀

* Remove as any

* Reflect substrate tips being handled now 🎉

* prettier

* Explain the length fee calculation

* Use newly defined constant
  • Loading branch information
notlesh authored and timbrinded committed Jun 2, 2023
1 parent 4aa5d8f commit 6ff68bc
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 6 deletions.
42 changes: 41 additions & 1 deletion tests/tests/test-fees/test-fee-multiplier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
} from "../../util/xcm";
import { expectOk } from "../../util/expect";
import { KeyringPair } from "@substrate/txwrapper-core";
import { TARGET_FILL_AMOUNT } from "../../util/constants";
import { GLMR, TARGET_FILL_AMOUNT, WEIGHT_FEE } from "../../util/constants";
import { verifyLatestBlockFees } from "../../util/block";

// Note on the values from 'transactionPayment.nextFeeMultiplier': this storage item is actually a
// FixedU128, which is basically a u128 with an implicit denominator of 10^18. However, this
Expand Down Expand Up @@ -425,3 +426,42 @@ describeDevMoonbeam("Fee Multiplier - XCM Executions", (context) => {
expect(initialValue.eq(postValue), "Fee Multiplier has changed between blocks").to.be.true;
});
});

describeDevMoonbeam("TransactionPayment Runtime Queries", (context) => {
it("should be able to query length fee", async function () {
// this test is really meant to show that `queryLengthToFee()` works, but for the inquisitive,
// this is how our length fee is calculated:
// fee = N**3 + N * 1_000_000_000 (where N: size_in_bytes):
const numBytes = 1n;
const coefficient = 1_000_000_000n;
const exponent = 3n;
const expected = numBytes ** exponent + numBytes * coefficient;

const adjusted_length_fee =
await context.polkadotApi.call.transactionPaymentApi.queryLengthToFee(numBytes);
expect(adjusted_length_fee.toBigInt()).to.eq(expected);
});

it("should be able to query weight fee", async function () {
const adjusted_weight_fee =
await context.polkadotApi.call.transactionPaymentApi.queryWeightToFee({
refTime: 1,
proofSize: 1,
});
expect(adjusted_weight_fee.toBigInt()).to.eq(WEIGHT_FEE);
});

it("should be able to calculate entire fee", async function () {
const tx = await context.polkadotApi.tx.balances.transfer(alith.address, GLMR).signAsync(alith);
const result = await context.createBlock(tx);
await verifyLatestBlockFees(context);
});

it("should be able to calculate entire fee including tip", async function () {
const tx = await context.polkadotApi.tx.balances
.transfer(alith.address, GLMR)
.signAsync(alith, { tip: 123 });
const result = await context.createBlock(tx);
await verifyLatestBlockFees(context);
});
});
44 changes: 39 additions & 5 deletions tests/util/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
import { FrameSystemEventRecord, SpWeightsWeightV2Weight } from "@polkadot/types/lookup";
import { u32, u64, u128, Option } from "@polkadot/types";
import { expect } from "chai";
import { WEIGHT_PER_GAS } from "./constants";

import { EXTRINSIC_BASE_WEIGHT, WEIGHT_PER_GAS } from "./constants";
import { DevTestContext } from "./setup-dev-tests";
import { rateLimiter } from "./common";
import type { Block, AccountId20 } from "@polkadot/types/interfaces/runtime/types";
Expand Down Expand Up @@ -138,7 +139,9 @@ export const verifyBlockFees = async (
let blockBurnt = 0n;

// iterate over every extrinsic
for (const { events, extrinsic, fee } of blockDetails.txWithEvents) {
for (const txWithEvents of blockDetails.txWithEvents) {
let { events, extrinsic, fee } = txWithEvents;

// This hash will only exist if the transaction was executed through ethereum.
let ethereumAddress = "";

Expand Down Expand Up @@ -217,9 +220,40 @@ export const verifyBlockFees = async (
txBurnt += tipFeePortions.burnt;
} else {
// For a regular substrate tx, we use the partialFee
let feePortions = calculateFeePortions(fee.partialFee.toBigInt());
txFees = fee.partialFee.toBigInt();
txBurnt += feePortions.burnt;
const feePortions = calculateFeePortions(fee.partialFee.toBigInt());
const tipPortions = calculateFeePortions(extrinsic.tip.toBigInt());
txFees += fee.partialFee.toBigInt() + extrinsic.tip.toBigInt();
txBurnt += feePortions.burnt + tipPortions.burnt;

// verify entire substrate txn fee
const apiAt = await context.polkadotApi.at(previousBlockHash);
const lengthFee = (
(await apiAt.call.transactionPaymentApi.queryLengthToFee(
extrinsic.encodedLength
)) as any
).toBigInt();

const unadjustedWeightFee = (
(await apiAt.call.transactionPaymentApi.queryWeightToFee({
refTime: fee.weight,
proofSize: 0n,
})) as any
).toBigInt();
const multiplier = await apiAt.query.transactionPayment.nextFeeMultiplier();
const denominator = 1_000_000_000_000_000_000n;
const weightFee = (unadjustedWeightFee * multiplier.toBigInt()) / denominator;

const baseFee = (
(await apiAt.call.transactionPaymentApi.queryWeightToFee({
refTime: EXTRINSIC_BASE_WEIGHT,
proofSize: 0n,
})) as any
).toBigInt();

const tip = extrinsic.tip.toBigInt();
const expectedPartialFee = lengthFee + weightFee + baseFee;

expect(expectedPartialFee).to.eq(fee.partialFee.toBigInt());
}

blockFees += txFees;
Expand Down

0 comments on commit 6ff68bc

Please sign in to comment.