UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

317 lines 14.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Environment = void 0; const debug_1 = __importDefault(require("debug")); const artifacts_1 = require("../artifacts"); const packageInfo_1 = require("../util/packageInfo"); const config_loading_1 = require("./config/config-loading"); const errors_1 = require("./errors"); const errors_list_1 = require("./errors-list"); const construction_1 = require("./providers/construction"); const lazy_initialization_1 = require("./providers/lazy-initialization"); const task_definitions_1 = require("./tasks/task-definitions"); const task_profiling_1 = require("./task-profiling"); const util_1 = require("./tasks/util"); const log = (0, debug_1.default)("hardhat:core:hre"); class Environment { /** * Initializes the Hardhat Runtime Environment and the given * extender functions. * * @remarks The extenders' execution order is given by the order * of the requires in the hardhat's config file and its plugins. * * @param config The hardhat's config object. * @param hardhatArguments The parsed hardhat's arguments. * @param tasks A map of tasks. * @param scopes A map of scopes. * @param environmentExtenders A list of environment extenders. * @param providerExtenders A list of provider extenders. */ constructor(config, hardhatArguments, tasks, scopes, environmentExtenders = [], userConfig = {}, providerExtenders = []) { this.config = config; this.hardhatArguments = hardhatArguments; this.tasks = tasks; this.scopes = scopes; this.userConfig = userConfig; this.version = (0, packageInfo_1.getHardhatVersion)(); /** * Executes the task with the given name. * * @param taskIdentifier The task or scoped task to be executed. * @param taskArguments A map of task's arguments. * @param subtaskArguments A map of subtasks to their arguments. * * @throws a HH303 if there aren't any defined tasks with the given name. * @returns a promise with the task's execution result. */ this.run = async (taskIdentifier, taskArguments = {}, subtaskArguments = {}, callerTaskProfile) => { const { scope, task } = (0, util_1.parseTaskIdentifier)(taskIdentifier); let taskDefinition; if (scope === undefined) { taskDefinition = this.tasks[task]; log("Running task %s", task); } else { const scopeDefinition = this.scopes[scope]; if (scopeDefinition === undefined) { throw new errors_1.HardhatError(errors_list_1.ERRORS.ARGUMENTS.UNRECOGNIZED_SCOPE, { scope, }); } taskDefinition = scopeDefinition.tasks?.[task]; log("Running scoped task %s %s", scope, task); } if (taskDefinition === undefined) { if (scope !== undefined) { throw new errors_1.HardhatError(errors_list_1.ERRORS.ARGUMENTS.UNRECOGNIZED_SCOPED_TASK, { scope, task, }); } throw new errors_1.HardhatError(errors_list_1.ERRORS.ARGUMENTS.UNRECOGNIZED_TASK, { task, }); } const resolvedTaskArguments = this._resolveValidTaskArguments(taskDefinition, taskArguments, subtaskArguments); let taskProfile; if (this.hardhatArguments.flamegraph === true) { taskProfile = (0, task_profiling_1.createTaskProfile)(task); if (callerTaskProfile !== undefined) { callerTaskProfile.children.push(taskProfile); } else { this.entryTaskProfile = taskProfile; } } try { return await this._runTaskDefinition(taskDefinition, resolvedTaskArguments, subtaskArguments, taskProfile); } catch (e) { (0, config_loading_1.analyzeModuleNotFoundError)(e, this.config.paths.configFile); // eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error throw e; } finally { if (taskProfile !== undefined) { (0, task_profiling_1.completeTaskProfile)(taskProfile); } } }; log("Creating HardhatRuntimeEnvironment"); const networkName = hardhatArguments.network !== undefined ? hardhatArguments.network : config.defaultNetwork; const networkConfig = config.networks[networkName]; if (networkConfig === undefined) { throw new errors_1.HardhatError(errors_list_1.ERRORS.NETWORK.CONFIG_NOT_FOUND, { network: networkName, }); } this.artifacts = new artifacts_1.Artifacts(config.paths.artifacts); const provider = new lazy_initialization_1.LazyInitializationProviderAdapter(async () => { log(`Creating provider for network ${networkName}`); return (0, construction_1.createProvider)(config, networkName, this.artifacts, providerExtenders); }); this.network = { name: networkName, config: networkConfig, provider, }; this._environmentExtenders = environmentExtenders; environmentExtenders.forEach((extender) => extender(this)); } /** * Injects the properties of `this` (the Hardhat Runtime Environment) into the global scope. * * @param blacklist a list of property names that won't be injected. * * @returns a function that restores the previous environment. */ injectToGlobal(blacklist = Environment._BLACKLISTED_PROPERTIES) { const globalAsAny = global; const previousValues = {}; const previousHre = globalAsAny.hre; globalAsAny.hre = this; for (const [key, value] of Object.entries(this)) { if (blacklist.includes(key)) { continue; } previousValues[key] = globalAsAny[key]; globalAsAny[key] = value; } return () => { for (const [key, _] of Object.entries(this)) { if (blacklist.includes(key)) { continue; } globalAsAny.hre = previousHre; globalAsAny[key] = previousValues[key]; } }; } /** * @param taskProfile Undefined if we aren't computing task profiles * @private */ async _runTaskDefinition(taskDefinition, taskArguments, subtaskArguments, taskProfile) { let runSuperFunction; if (taskDefinition instanceof task_definitions_1.OverriddenTaskDefinition) { runSuperFunction = async (_taskArguments = taskArguments, _subtaskArguments = subtaskArguments) => { log("Running %s's super", taskDefinition.name); if (taskProfile === undefined) { return this._runTaskDefinition(taskDefinition.parentTaskDefinition, _taskArguments, _subtaskArguments); } const parentTaskProfile = (0, task_profiling_1.createParentTaskProfile)(taskProfile); taskProfile.children.push(parentTaskProfile); try { return await this._runTaskDefinition(taskDefinition.parentTaskDefinition, _taskArguments, _subtaskArguments, parentTaskProfile); } finally { (0, task_profiling_1.completeTaskProfile)(parentTaskProfile); } }; runSuperFunction.isDefined = true; } else { runSuperFunction = async () => { throw new errors_1.HardhatError(errors_list_1.ERRORS.TASK_DEFINITIONS.RUNSUPER_NOT_AVAILABLE, { taskName: taskDefinition.name, }); }; runSuperFunction.isDefined = false; } const runSuper = runSuperFunction; const globalAsAny = global; const previousRunSuper = globalAsAny.runSuper; globalAsAny.runSuper = runSuper; // We create a proxied version of `this`, as we want to keep track of the // `subtaskArguments` and `taskProfile` through `run` invocations. This // way we keep track of callers's data, even when tasks are run in parallel. const proxiedHre = new Proxy(this, { get(target, p, receiver) { if (p === "run") { return (_name, _taskArguments, _subtaskArguments) => target.run(_name, _taskArguments, { ..._subtaskArguments, ...subtaskArguments }, // parent subtask args take precedence taskProfile); } return Reflect.get(target, p, receiver); }, }); if (this.hardhatArguments.flamegraph === true) { // We modify the `this` again to add a few utility methods. proxiedHre.adhocProfile = async (_name, f) => { const adhocProfile = (0, task_profiling_1.createTaskProfile)(_name); taskProfile.children.push(adhocProfile); try { return await f(); } finally { (0, task_profiling_1.completeTaskProfile)(adhocProfile); } }; proxiedHre.adhocProfileSync = (_name, f) => { const adhocProfile = (0, task_profiling_1.createTaskProfile)(_name); taskProfile.children.push(adhocProfile); try { return f(); } finally { (0, task_profiling_1.completeTaskProfile)(adhocProfile); } }; } const uninjectFromGlobal = proxiedHre.injectToGlobal(); try { return await taskDefinition.action(taskArguments, proxiedHre, runSuper); } finally { uninjectFromGlobal(); globalAsAny.runSuper = previousRunSuper; } } /** * Check that task arguments are within TaskDefinition defined params constraints. * Also, populate missing, non-mandatory arguments with default param values (if any). * * @private * @throws HardhatError if any of the following are true: * > a required argument is missing * > an argument's value's type doesn't match the defined param type * * @param taskDefinition * @param taskArguments * @returns resolvedTaskArguments */ _resolveValidTaskArguments(taskDefinition, taskArguments, subtaskArguments) { const { name: taskName, paramDefinitions, positionalParamDefinitions, } = taskDefinition; const nonPositionalParamDefinitions = Object.values(paramDefinitions); // gather all task param definitions const allTaskParamDefinitions = [ ...nonPositionalParamDefinitions, ...positionalParamDefinitions, ]; const resolvedArguments = {}; for (const paramDefinition of allTaskParamDefinitions) { const paramName = paramDefinition.name; const argumentValue = subtaskArguments[taskName]?.[paramName] ?? taskArguments[paramName]; const resolvedArgumentValue = this._resolveArgument(paramDefinition, argumentValue, taskDefinition.name); if (resolvedArgumentValue !== undefined) { resolvedArguments[paramName] = resolvedArgumentValue; } } // We keep the args in taskArguments that were not resolved return { ...taskArguments, ...resolvedArguments }; } /** * Resolves an argument according to a ParamDefinition rules. * * @param paramDefinition * @param argumentValue * @private */ _resolveArgument(paramDefinition, argumentValue, taskName) { const { name, isOptional, defaultValue } = paramDefinition; if (argumentValue === undefined) { if (isOptional) { // undefined & optional argument -> return defaultValue return defaultValue; } // undefined & mandatory argument -> error throw new errors_1.HardhatError(errors_list_1.ERRORS.ARGUMENTS.MISSING_TASK_ARGUMENT, { param: name, task: taskName, }); } // arg was present -> validate type, if applicable this._checkTypeValidation(paramDefinition, argumentValue); return argumentValue; } /** * Checks if value is valid for the specified param definition. * * @param paramDefinition {ParamDefinition} - the param definition for validation * @param argumentValue - the value to be validated * @private * @throws HH301 if value is not valid for the param type */ _checkTypeValidation(paramDefinition, argumentValue) { const { name: paramName, type, isVariadic } = paramDefinition; // in case of variadic param, argValue is an array and the type validation must pass for all values. // otherwise, it's a single value that is to be validated const argumentValueContainer = isVariadic ? argumentValue : [argumentValue]; for (const value of argumentValueContainer) { type.validate(paramName, value); } } } Environment._BLACKLISTED_PROPERTIES = [ "injectToGlobal", "entryTaskProfile", "_runTaskDefinition", "_extenders", ]; exports.Environment = Environment; //# sourceMappingURL=runtime-environment.js.map