@moonsong-labs/moonwall-util
Version:
Testing framework for the Moon family of projects
136 lines (134 loc) • 4.71 kB
JavaScript
// src/functions/block.ts
import "@moonbeam-network/api-augment/moonbase";
import Bottleneck from "bottleneck";
import Debug from "debug";
var debug = Debug("test:blocks");
async function createAndFinalizeBlock(api, parentHash, finalize = false) {
const startTime = Date.now();
const block = parentHash ? await api.rpc.engine.createBlock(true, finalize, parentHash) : await api.rpc.engine.createBlock(true, finalize);
return {
duration: Date.now() - startTime,
hash: block.toJSON().hash
// toString doesn't work for block hashes
};
}
function calculateFeePortions(amount) {
const burnt = amount * 80n / 100n;
return { burnt, treasury: amount - burnt };
}
var getBlockExtrinsic = async (api, blockHash, section, method) => {
const apiAt = await api.at(blockHash);
const [{ block }, records] = await Promise.all([
api.rpc.chain.getBlock(blockHash),
apiAt.query.system.events()
]);
const extIndex = block.extrinsics.findIndex(
(ext) => ext.method.section == section && ext.method.method == method
);
const extrinsic = extIndex > -1 ? block.extrinsics[extIndex] : null;
const events = records.filter(({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(extIndex)).map(({ event }) => event);
const resultEvent = events.find(
(event) => event.section === "system" && (event.method === "ExtrinsicSuccess" || event.method === "ExtrinsicFailed")
);
return { block, extrinsic, events, resultEvent };
};
var getBlockTime = (signedBlock) => signedBlock.block.extrinsics.find((item) => item.method.section == "timestamp").method.args[0].toNumber();
var checkBlockFinalized = async (api, number) => {
return {
number,
finalized: (await api.rpc.moon.isBlockFinalized(await api.rpc.chain.getBlockHash(number))).isTrue
};
};
var fetchBlockTime = async (api, blockNum) => {
const hash = await api.rpc.chain.getBlockHash(blockNum);
const block = await api.rpc.chain.getBlock(hash);
return getBlockTime(block);
};
var fetchHistoricBlockNum = async (api, blockNumber, targetTime) => {
if (blockNumber <= 1) {
return 1;
}
const time = await fetchBlockTime(api, blockNumber);
if (time <= targetTime) {
return blockNumber;
}
return fetchHistoricBlockNum(
api,
blockNumber - Math.ceil((time - targetTime) / 3e4),
targetTime
);
};
var getBlockArray = async (api, timePeriod, limiter) => {
if (limiter == null) {
limiter = new Bottleneck({ maxConcurrent: 10, minTime: 100 });
}
const finalizedHead = await limiter.schedule(() => api.rpc.chain.getFinalizedHead());
const signedBlock = await limiter.schedule(() => api.rpc.chain.getBlock(finalizedHead));
const lastBlockNumber = signedBlock.block.header.number.toNumber();
const lastBlockTime = getBlockTime(signedBlock);
const firstBlockTime = lastBlockTime - timePeriod;
debug(`Searching for the block at: ${new Date(firstBlockTime)}`);
const firstBlockNumber = await limiter.wrap(fetchHistoricBlockNum)(
api,
lastBlockNumber,
firstBlockTime
);
const length = lastBlockNumber - firstBlockNumber;
return Array.from({ length }, (_, i) => firstBlockNumber + i);
};
function extractWeight(weightV1OrV2) {
if ("isSome" in weightV1OrV2) {
const weight = weightV1OrV2.unwrap();
if ("refTime" in weight) {
return weight.refTime.unwrap();
}
return weight;
}
if ("refTime" in weightV1OrV2) {
return weightV1OrV2.refTime.unwrap();
}
return weightV1OrV2;
}
function extractPreimageDeposit(request) {
const deposit = "deposit" in request ? request.deposit : request;
if ("isSome" in deposit) {
return {
accountId: deposit.unwrap()[0].toHex(),
amount: deposit.unwrap()[1]
};
}
return {
accountId: deposit[0].toHex(),
amount: deposit[1]
};
}
function mapExtrinsics(extrinsics, records, fees) {
return extrinsics.map((extrinsic, index) => {
let dispatchError;
let dispatchInfo;
const events = records.filter(({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index)).map(({ event }) => {
if (event.section === "system") {
if (event.method === "ExtrinsicSuccess") {
dispatchInfo = event.data[0];
} else if (event.method === "ExtrinsicFailed") {
dispatchError = event.data[0];
dispatchInfo = event.data[1];
}
}
return event;
});
return { dispatchError, dispatchInfo, events, extrinsic, fee: fees ? fees[index] : void 0 };
});
}
export {
createAndFinalizeBlock,
calculateFeePortions,
getBlockExtrinsic,
getBlockTime,
checkBlockFinalized,
fetchHistoricBlockNum,
getBlockArray,
extractWeight,
extractPreimageDeposit,
mapExtrinsics
};