UNPKG

@moonsong-labs/moonwall-cli

Version:

Testing framework for the Moon family of projects

118 lines (115 loc) 4.36 kB
import { extractError } from "./chunk-IINDK553.js"; // src/internal/devModeHelpers.ts import { customWeb3Request, alith, createAndFinalizeBlock } from "@moonsong-labs/moonwall-util"; import Debug from "debug"; import { setTimeout } from "timers/promises"; import { assert } from "vitest"; import chalk from "chalk"; var debug = Debug("DevTest"); async function devForkToFinalizedHead(context) { const api = context.providers.find(({ type }) => type == "moon").api; const finalizedHead = context.genesis; await api.rpc.engine.createBlock(true, true, finalizedHead); while (true) { const newHead = (await api.rpc.chain.getFinalizedHead()).toString(); if (newHead == finalizedHead) { await setTimeout(100); } else { context.genesis = newHead; break; } } } async function createDevBlock(context, transactions, options = { allowFailures: true }) { const results = []; const api = context.getSubstrateApi(); const txs = transactions == void 0 ? [] : Array.isArray(transactions) ? transactions : [transactions]; for await (const call of txs) { if (typeof call == "string") { results.push({ type: "eth", hash: (await customWeb3Request(context.web3(), "eth_sendRawTransaction", [call])).result }); } else if (call.isSigned) { const tx = api.tx(call); debug( `- Signed: ${tx.method.section}.${tx.method.method}(${tx.args.map((d) => d.toHuman()).join("; ")}) [ nonce: ${tx.nonce}]` ); results.push({ type: "sub", hash: (await call.send()).toString() }); } else { const tx = api.tx(call); debug( `- Unsigned: ${tx.method.section}.${tx.method.method}(${tx.args.map((d) => d.toHuman()).join("; ")}) [ nonce: ${tx.nonce}]` ); results.push({ type: "sub", hash: (await call.signAndSend(alith)).toString() }); } } const { parentHash, finalize } = options; const blockResult = await createAndFinalizeBlock(api, parentHash, finalize); if (results.length == 0) { return { block: blockResult, result: null }; } const allRecords = await (await api.at(blockResult.hash)).query.system.events(); const blockData = await api.rpc.chain.getBlock(blockResult.hash); const result = results.map((result2) => { const extrinsicIndex = result2.type == "eth" ? allRecords.find( ({ phase, event: { section, method, data } }) => phase.isApplyExtrinsic && section == "ethereum" && method == "Executed" && data[2].toString() == result2.hash )?.phase?.asApplyExtrinsic?.toNumber() : blockData.block.extrinsics.findIndex((ext) => ext.hash.toHex() == result2.hash); const events = allRecords.filter( ({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.toNumber() === extrinsicIndex ); const failure = extractError(events); return { extrinsic: extrinsicIndex >= 0 ? blockData.block.extrinsics[extrinsicIndex] : null, events, error: failure && (failure.isModule && api.registry.findMetaError(failure.asModule) || { name: failure.toString() }), successful: extrinsicIndex !== void 0 && !failure, hash: result2.hash }; }); if (results.find((r) => r.type == "eth")) { await setTimeout(2); } const actualEvents = result.flatMap((resp) => resp.events); if (options.expectEvents && options.expectEvents.length > 0) { const match = options.expectEvents.every((eEvt) => { const found = actualEvents.map((aEvt) => eEvt.is(aEvt.event)).reduce((acc, curr) => acc || curr, false); if (!found) { options.logger ? options.logger( `Event ${chalk.bgWhiteBright.blackBright(eEvt.meta.name)} not present in block` ) : console.error( `Event ${chalk.bgWhiteBright.blackBright(eEvt.meta.name)} not present in block` ); } return found; }); assert(match, "Expected events not present in block"); } if (!options.allowFailures) { actualEvents.forEach((event) => { assert( !api.events.system.ExtrinsicFailed.is(event.event), "ExtrinsicFailed event detected, enable 'allowFailures' if this is expected." ); }); } return { block: blockResult, result: Array.isArray(transactions) ? result : result[0] }; } export { devForkToFinalizedHead, createDevBlock };