UNPKG

@moonsong-labs/moonwall-util

Version:

Testing framework for the Moon family of projects

136 lines (134 loc) 4.71 kB
// 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 };