UNPKG

@nomiclabs/buidler

Version:

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

235 lines 10.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const ansi_escapes_1 = __importDefault(require("ansi-escapes")); const chalk_1 = __importDefault(require("chalk")); const debug_1 = __importDefault(require("debug")); const events_1 = require("events"); const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const semver_1 = __importDefault(require("semver")); const util_1 = __importDefault(require("util")); const constants_1 = require("../../constants"); const solidity_errors_1 = require("../stack-traces/solidity-errors"); const solidityTracer_1 = require("../stack-traces/solidityTracer"); const await_semaphore_1 = require("../vendor/await-semaphore"); const errors_1 = require("./errors"); const buidler_1 = require("./modules/buidler"); const eth_1 = require("./modules/eth"); const evm_1 = require("./modules/evm"); const logger_1 = require("./modules/logger"); const net_1 = require("./modules/net"); const web3_1 = require("./modules/web3"); const node_1 = require("./node"); const log = debug_1.default("buidler:core:buidler-evm:provider"); // Set of methods that are never logged const PRIVATE_RPC_METHODS = new Set(["buidler_getStackTraceFailuresCount"]); // tslint:disable only-buidler-error class BuidlerEVMProvider extends events_1.EventEmitter { constructor(_hardfork, _networkName, _chainId, _networkId, _blockGasLimit, _throwOnTransactionFailures, _throwOnCallFailures, _genesisAccounts = [], _solcVersion, _paths, _loggingEnabled = false, _allowUnlimitedContractSize = false, _initialDate, _experimentalBuidlerEVMMessageTraceHooks = []) { super(); this._hardfork = _hardfork; this._networkName = _networkName; this._chainId = _chainId; this._networkId = _networkId; this._blockGasLimit = _blockGasLimit; this._throwOnTransactionFailures = _throwOnTransactionFailures; this._throwOnCallFailures = _throwOnCallFailures; this._genesisAccounts = _genesisAccounts; this._solcVersion = _solcVersion; this._paths = _paths; this._loggingEnabled = _loggingEnabled; this._allowUnlimitedContractSize = _allowUnlimitedContractSize; this._initialDate = _initialDate; this._experimentalBuidlerEVMMessageTraceHooks = _experimentalBuidlerEVMMessageTraceHooks; this._mutex = new await_semaphore_1.Mutex(); this._logger = new logger_1.ModulesLogger(); this._methodCollapsedCount = 0; } async send(method, params = []) { const release = await this._mutex.acquire(); try { if (this._loggingEnabled && !PRIVATE_RPC_METHODS.has(method)) { return await this._sendWithLogging(method, params); } return await this._send(method, params); } finally { release(); } } async _sendWithLogging(method, params = []) { this._logger.clearLogs(); try { const result = await this._send(method, params); // We log after running the method, because we want to use different // colors depending on whether it failed or not // TODO: If an eth_call, eth_sendTransaction, or eth_sendRawTransaction // fails without throwing, this will be displayed in green. It's unclear // if this is correct. See Eth module's TODOs for more info. if (this._shouldCollapseMethod(method)) { this._logCollapsedMethod(method); } else { this._startCollapsingMethod(method); this._log(method, false, chalk_1.default.green); } const loggedSomething = this._logModuleMessages(); if (loggedSomething) { this._stopCollapsingMethod(); this._log(""); } return result; } catch (err) { this._stopCollapsingMethod(); if (err instanceof errors_1.MethodNotFoundError || err instanceof errors_1.MethodNotSupportedError) { this._log(`${method} - Method not supported`, false, chalk_1.default.red); throw err; } this._log(method, false, chalk_1.default.red); const loggedSomething = this._logModuleMessages(); if (loggedSomething) { this._log(""); } if (err instanceof solidity_errors_1.SolidityError) { this._logError(err); } else if (err instanceof errors_1.BuidlerEVMProviderError) { this._log(err.message, true); } else { this._logError(err, true); this._log(""); this._log("If you think this is a bug in Buidler, please report it here: https://buidler.dev/reportbug", true); } this._log(""); throw err; } } _logCollapsedMethod(method) { this._methodCollapsedCount += 1; process.stdout.write( // tslint:disable-next-line:prefer-template ansi_escapes_1.default.cursorHide + ansi_escapes_1.default.cursorPrevLine + chalk_1.default.green(`${method} (${this._methodCollapsedCount})`) + "\n" + ansi_escapes_1.default.eraseEndLine + ansi_escapes_1.default.cursorShow); } _startCollapsingMethod(method) { this._methodBeingCollapsed = method; this._methodCollapsedCount = 1; } _stopCollapsingMethod() { this._methodBeingCollapsed = undefined; this._methodCollapsedCount = 0; } _shouldCollapseMethod(method) { return (method === this._methodBeingCollapsed && !this._logger.hasLogs() && this._methodCollapsedCount > 0); } async _send(method, params = []) { await this._init(); if (method.startsWith("eth_")) { return this._ethModule.processRequest(method, params); } if (method.startsWith("net_")) { return this._netModule.processRequest(method, params); } if (method.startsWith("web3_")) { return this._web3Module.processRequest(method, params); } if (method.startsWith("evm_")) { return this._evmModule.processRequest(method, params); } if (method.startsWith("buidler_")) { return this._buidlerModule.processRequest(method, params); } throw new errors_1.MethodNotFoundError(`Method ${method} not found`); } async _init() { if (this._node !== undefined) { return; } let compilerInput; let compilerOutput; if (this._solcVersion !== undefined && this._paths !== undefined) { if (semver_1.default.lt(this._solcVersion, solidityTracer_1.FIRST_SOLC_VERSION_SUPPORTED)) { console.warn(chalk_1.default.yellow(`Solidity stack traces only work with Solidity version ${solidityTracer_1.FIRST_SOLC_VERSION_SUPPORTED} or higher.`)); } else { let hasCompiledContracts = false; if (await fs_extra_1.default.pathExists(this._paths.artifacts)) { const artifactsDir = await fs_extra_1.default.readdir(this._paths.artifacts); hasCompiledContracts = artifactsDir.some((f) => f.endsWith(".json")); } if (hasCompiledContracts) { try { const solcInputPath = path_1.default.join(this._paths.cache, constants_1.SOLC_INPUT_FILENAME); const solcOutputPath = path_1.default.join(this._paths.cache, constants_1.SOLC_OUTPUT_FILENAME); compilerInput = await fs_extra_1.default.readJSON(solcInputPath, { encoding: "utf8", }); compilerOutput = await fs_extra_1.default.readJSON(solcOutputPath, { encoding: "utf8", }); } catch (error) { console.warn(chalk_1.default.yellow("Stack traces engine could not be initialized. Run Buidler with --verbose to learn more.")); log("Solidity stack traces disabled: Failed to read solc's input and output files. Please report this to help us improve Buidler.\n", error); } } } } const [common, node] = await node_1.BuidlerNode.create(this._hardfork, this._networkName, this._chainId, this._networkId, this._blockGasLimit, this._genesisAccounts, this._solcVersion, this._allowUnlimitedContractSize, this._initialDate, compilerInput, compilerOutput); this._common = common; this._node = node; this._ethModule = new eth_1.EthModule(common, node, this._throwOnTransactionFailures, this._throwOnCallFailures, this._loggingEnabled ? this._logger : undefined, this._experimentalBuidlerEVMMessageTraceHooks); this._netModule = new net_1.NetModule(common); this._web3Module = new web3_1.Web3Module(); this._evmModule = new evm_1.EvmModule(node); this._buidlerModule = new buidler_1.BuidlerModule(node); const listener = (payload) => { this.emit("notifications", { subscription: `0x${payload.filterId.toString(16)}`, result: payload.result, }); }; // Handle eth_subscribe events and proxy them to handler this._node.addListener("ethEvent", listener); } _logModuleMessages() { const logs = this._logger.getLogs(); if (logs.length === 0) { return false; } for (const msg of logs) { this._log(msg, true); } return true; } _logError(err, logInRed = false) { this._log(util_1.default.inspect(err), true, logInRed ? chalk_1.default.red : undefined); } _log(msg, indent = false, color) { if (indent) { msg = msg .split("\n") .map((line) => ` ${line}`) .join("\n"); } if (color !== undefined) { console.log(color(msg)); return; } console.log(msg); } } exports.BuidlerEVMProvider = BuidlerEVMProvider; //# sourceMappingURL=provider.js.map