diff --git a/packages/hardhat-core/src/internal/hardhat-network/provider/provider.ts b/packages/hardhat-core/src/internal/hardhat-network/provider/provider.ts index 7e4276a5896..c14f1cb43d3 100644 --- a/packages/hardhat-core/src/internal/hardhat-network/provider/provider.ts +++ b/packages/hardhat-core/src/internal/hardhat-network/provider/provider.ts @@ -21,7 +21,11 @@ import type { AccountOverride, } from "@nomicfoundation/edr"; import { privateToAddress } from "@ethereumjs/util"; -import { ContractDecoder, precompileP256Verify } from "@nomicfoundation/edr"; +import { + ContractDecoder, + IncludeTraces, + precompileP256Verify, +} from "@nomicfoundation/edr"; import picocolors from "picocolors"; import debug from "debug"; import { EventEmitter } from "events"; @@ -67,7 +71,6 @@ import { MempoolOrder, } from "./node-types"; import { - edrRpcDebugTraceToHardhat, edrTracingMessageResultToMinimalEVMResult, edrTracingMessageToMinimalMessage, edrTracingStepToMinimalInterpreterStep, @@ -268,7 +271,9 @@ export class EdrProviderWrapper }, }, networkId: BigInt(config.networkId), - observability: {}, + observability: { + includeCallTraces: IncludeTraces.All, + }, ownedAccounts, // Turn off the Osaka EIP-7825 per transaction gas limit for HH2 // when being run from `solidity-coverage`. @@ -392,11 +397,8 @@ export class EdrProviderWrapper this._node._vm.events.eventNames().length > 0; if (needsTraces) { - const rawTraces = responseObject.traces; - for (const rawTrace of rawTraces) { - // For other consumers in JS we need to marshall the entire trace over FFI - const trace = rawTrace.trace; - + const rawTraces = responseObject.traces(); + for (const trace of rawTraces) { // beforeTx event if (this._node._vm.events.listenerCount("beforeTx") > 0) { this._node._vm.events.emit("beforeTx"); @@ -413,7 +415,7 @@ export class EdrProviderWrapper } } // afterMessage event - else if ("executionResult" in traceItem) { + else if ("execResult" in traceItem) { if (this._node._vm.evm.events.listenerCount("afterMessage") > 0) { this._node._vm.evm.events.emit( "afterMessage", @@ -442,20 +444,32 @@ export class EdrProviderWrapper if (isErrorResponse(response)) { let error; - let stackTrace: SolidityStackTrace | null = null; - try { - stackTrace = responseObject.stackTrace(); - } catch (e) { - log("Failed to get stack trace: %O", e); - } + const stackTrace = responseObject.stackTrace(); - if (stackTrace !== null) { - error = encodeSolidityStackTrace(response.error.message, stackTrace); + if (stackTrace?.kind === "StackTrace") { + error = encodeSolidityStackTrace( + response.error.message, + stackTrace.entries + ); // Pass data and transaction hash from the original error (error as any).data = response.error.data?.data ?? undefined; (error as any).transactionHash = response.error.data?.transactionHash ?? undefined; } else { + if (stackTrace !== null) { + switch (stackTrace.kind) { + case "UnexpectedError": + log( + "Failed to get stack trace due to error: %O", + stackTrace.errorMessage + ); + break; + case "HeuristicFailed": + log("Failed to get stack trace due to failing heuristics"); + break; + } + } + if (response.error.code === InvalidArgumentsError.CODE) { error = new InvalidArgumentsError(response.error.message); } else { @@ -479,11 +493,6 @@ export class EdrProviderWrapper // e.g. `HardhatNetwork/2.19.0/@nomicfoundation/edr/0.2.0-dev` if (args.method === "web3_clientVersion") { return clientVersion(response.result); - } else if ( - args.method === "debug_traceTransaction" || - args.method === "debug_traceCall" - ) { - return edrRpcDebugTraceToHardhat(response.result); } else { return response.result; } diff --git a/packages/hardhat-core/src/internal/hardhat-network/provider/utils/convertToEdr.ts b/packages/hardhat-core/src/internal/hardhat-network/provider/utils/convertToEdr.ts index 7fc17b29c04..c6be433f86f 100644 --- a/packages/hardhat-core/src/internal/hardhat-network/provider/utils/convertToEdr.ts +++ b/packages/hardhat-core/src/internal/hardhat-network/provider/utils/convertToEdr.ts @@ -174,113 +174,43 @@ export function ethereumjsMempoolOrderToEdrMineOrdering( } } -export function edrRpcDebugTraceToHardhat( - rpcDebugTrace: DebugTraceResult -): RpcDebugTraceOutput { - const structLogs = rpcDebugTrace.structLogs.map((log) => { - const result: RpcStructLog = { - depth: Number(log.depth), - gas: Number(log.gas), - gasCost: Number(log.gasCost), - op: log.opName, - pc: Number(log.pc), - }; - - if (log.memory !== undefined) { - result.memory = log.memory; - } - - if (log.stack !== undefined) { - // Remove 0x prefix which is required by EIP-3155, but not expected by Hardhat. - result.stack = log.stack?.map((item) => item.slice(2)); - } - - if (log.storage !== undefined) { - result.storage = Object.fromEntries( - Object.entries(log.storage).map(([key, value]) => { - return [key.slice(2), value.slice(2)]; - }) - ); - } - - if (log.error !== undefined) { - result.error = { - message: log.error, - }; - } - - return result; - }); - - // REVM trace adds initial STOP that Hardhat doesn't expect - if (structLogs.length > 0 && structLogs[0].op === "STOP") { - structLogs.shift(); - } - - let returnValue = rpcDebugTrace.output?.toString() ?? ""; - if (returnValue === "0x") { - returnValue = ""; - } - - return { - failed: !rpcDebugTrace.pass, - gas: Number(rpcDebugTrace.gasUsed), - returnValue, - structLogs, - }; -} - export function edrTracingStepToMinimalInterpreterStep( step: TracingStep ): MinimalInterpreterStep { const minimalInterpreterStep: MinimalInterpreterStep = { - pc: Number(step.pc), + pc: step.pc, depth: step.depth, opcode: { - name: step.opcode, + name: step.opcode.name, }, stack: step.stack, + memory: step.memory, }; - if (step.memory !== undefined) { - minimalInterpreterStep.memory = step.memory; - } - return minimalInterpreterStep; } export function edrTracingMessageResultToMinimalEVMResult( tracingMessageResult: TracingMessageResult ): MinimalEVMResult { - const { result, contractAddress } = tracingMessageResult.executionResult; - - // only SuccessResult has logs - const success = "logs" in result; + const execResult = tracingMessageResult.execResult; const minimalEVMResult: MinimalEVMResult = { execResult: { - executionGasUsed: result.gasUsed, - success, + success: execResult.success, + executionGasUsed: execResult.executionGasUsed, + contractAddress: + execResult.contractAddress !== undefined + ? new Address(execResult.contractAddress) + : undefined, + reason: execResult.reason, + output: + execResult.output !== undefined + ? Buffer.from(execResult.output) + : undefined, }, }; - // only success and exceptional halt have reason - if ("reason" in result) { - minimalEVMResult.execResult.reason = result.reason; - } - if ("output" in result) { - const { output } = result; - if (output instanceof Uint8Array) { - minimalEVMResult.execResult.output = Buffer.from(output); - } else { - minimalEVMResult.execResult.output = Buffer.from(output.returnValue); - } - } - - if (contractAddress !== undefined) { - minimalEVMResult.execResult.contractAddress = new Address(contractAddress); - } - return minimalEVMResult; } diff --git a/packages/hardhat-core/test/builtin-tasks/compile.ts b/packages/hardhat-core/test/builtin-tasks/compile.ts index f89635e1237..b27c5eb1b80 100644 --- a/packages/hardhat-core/test/builtin-tasks/compile.ts +++ b/packages/hardhat-core/test/builtin-tasks/compile.ts @@ -1,4 +1,4 @@ -import { getLatestSupportedSolcVersion } from "@nomicfoundation/edr"; +import { latestSupportedSolidityVersion } from "@nomicfoundation/edr"; import { assert, expect } from "chai"; import ci from "ci-info"; import * as fsExtra from "fs-extra"; @@ -57,7 +57,7 @@ describe("compile task", function () { // Test to check that the last version of solc is being tested const userConfigSolcVersion = this.env.userConfig.solidity; - const lastSolcVersion = getLatestSupportedSolcVersion(); + const lastSolcVersion = latestSupportedSolidityVersion(); assert.equal( userConfigSolcVersion, diff --git a/packages/hardhat-core/test/helpers/compilation.ts b/packages/hardhat-core/test/helpers/compilation.ts index 0ec5f3a4b3c..fde07acfd13 100644 --- a/packages/hardhat-core/test/helpers/compilation.ts +++ b/packages/hardhat-core/test/helpers/compilation.ts @@ -1,4 +1,4 @@ -import { getLatestSupportedSolcVersion } from "@nomicfoundation/edr"; +import { latestSupportedSolidityVersion } from "@nomicfoundation/edr"; import semver from "semver"; import { @@ -161,7 +161,7 @@ async function downloadCompiler(solidityVersion: string): Promise { } export const getNextUnsupportedVersion = () => - semver.inc(getLatestSupportedSolcVersion(), "patch")!; + semver.inc(latestSupportedSolidityVersion(), "patch")!; export const getNextNextUnsupportedVersion = () => semver.inc(getNextUnsupportedVersion(), "patch")!;