hardhat-gas-reporter
Version:
Gas Analytics plugin for Hardhat
133 lines (109 loc) • 4.36 kB
text/typescript
import { HardhatPluginError } from "hardhat/plugins";
import { HardhatRuntimeEnvironment, TaskArguments } from "hardhat/types";
import { TASK_GAS_REPORTER_MERGE_REPORTS } from "../task-names";
import { GasReporterOutput } from "../types";
/**
* Tries to merge several gas reporter output objects into one.
*/
export async function mergeReports(
reports: GasReporterOutput[],
inputFiles: string[]
): Promise<GasReporterOutput> {
const result: any = {
namespace: null,
toolchain: null,
options: null,
data: {
methods: {},
deployments: [],
blockLimit: null,
},
};
const { HardhatGasReporterOutputValidator } = await import("../lib/validators/hardhat");
for (const [index, report] of reports.entries()) {
const Validator = new HardhatGasReporterOutputValidator();
Validator.validateOutputObject(report, inputFiles[index]);
if (result.options === null) result.options = report.options;
if (result.namespace === null) result.namespace = report.namespace;
if (result.toolchain === null) result.toolchain = report.toolchain;
// Merge data.methods objects
Object.entries(report.data!.methods).forEach(([key, value]) => {
Validator.validateMethodDataItem(value, inputFiles[index]);
if (result.data.methods[key] === undefined) {
result.data.methods[key] = value;
return;
}
result.data.methods[key].gasData = [
...result.data!.methods[key].gasData,
...report.data!.methods[key].gasData,
].sort((a, b) => a - b);
result.data.methods[key].callData = [
...result.data!.methods[key].callData,
...report.data!.methods[key].callData,
].sort((a, b) => a - b);
result.data.methods[key].numberOfCalls +=
report.data!.methods[key].numberOfCalls;
});
// Merge data.deployments objects
report.data!.deployments.forEach((deployment) => {
const current = result.data.deployments.find(
(d: any) => d.name === deployment.name
);
if (current !== undefined) {
current.gasData = [...current.gasData, ...deployment.gasData].sort(
(a, b) => a - b
);
current.callData = [...current.callData, ...deployment.callData].sort(
(a, b) => a - b
);
} else {
result.data.deployments.push(deployment);
}
});
}
return result;
}
/**
* Task for merging multiple gasReporterOutput.json files generated by the plugin
* This task is necessary when we want to generate different parts of the reports
* parallelized on different jobs.
*/
export async function subtaskMergeReportsImplementation(
{ inputFiles }: { inputFiles: string[] }
): Promise<GasReporterOutput> {
const fs = await import("fs");
const reports = inputFiles.map((input) => JSON.parse(fs.readFileSync(input, "utf-8")));
return mergeReports(reports, inputFiles);
};
export async function taskMergeImplementation(
taskArguments: TaskArguments,
hre: HardhatRuntimeEnvironment
): Promise<void> {
const path = await import("path");
const { globSync } = await import("glob");
const { uniq } = await import("lodash");
const { reportMerge } = await import("../utils/ui");
const { GasData } = await import("../lib/gasData");
const { setGasAndPriceRates } = await import("../utils/prices");
const { generateJSONData } = await import("../lib/render/json");
const output = path.resolve(process.cwd(), taskArguments.output);
// Parse input files and calculate glob patterns
const taskArgs = uniq(taskArguments.input.map((input: string) => globSync(input)).flat());
const files = taskArgs.map((file) => path.resolve(file as string))
if (files.length === 0) {
throw new HardhatPluginError(
`hardhat-gas-reporter`,
`No files found for the given input: ${taskArguments.input.join(" ")}`
);
}
reportMerge(files, output);
const result = await hre.run(TASK_GAS_REPORTER_MERGE_REPORTS, { inputFiles: files });
const warnings = await setGasAndPriceRates(result.options);
const data = new GasData(result.data.methods, result.data.deployments);
await data.runAnalysis(hre, result.options);
// Write warnings
for (const warning of warnings) console.log(warning);
// Write json
result.options.outputJSONFile = output;
generateJSONData(data, result.options);
};