Skip to content

Commit 0c7b68e

Browse files
authored
Merge pull request #5195 from NomicFoundation/hardhat-tracer-support
`hardhat-tracer` support
2 parents d2ce024 + b45eb94 commit 0c7b68e

File tree

8 files changed

+750
-658
lines changed

8 files changed

+750
-658
lines changed

.changeset/tall-coins-sin.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"hardhat": patch
3+
---
4+
5+
Made internal changes to allow `hardhat-tracer` to work with Hardhat again

packages/hardhat-core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
"dependencies": {
103103
"@ethersproject/abi": "^5.1.2",
104104
"@metamask/eth-sig-util": "^4.0.0",
105-
"@nomicfoundation/edr": "^0.3.8",
105+
"@nomicfoundation/edr": "^0.4.0",
106106
"@nomicfoundation/ethereumjs-common": "4.0.4",
107107
"@nomicfoundation/ethereumjs-tx": "5.0.4",
108108
"@nomicfoundation/ethereumjs-util": "9.0.4",

packages/hardhat-core/src/internal/hardhat-network/provider/provider.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ export class EdrProviderWrapper
370370

371371
const needsTraces =
372372
this._node._vm.evm.events.eventNames().length > 0 ||
373+
this._node._vm.events.eventNames().length > 0 ||
373374
this._rawTraceCallbacks.onStep !== undefined ||
374375
this._rawTraceCallbacks.onAfterMessage !== undefined ||
375376
this._rawTraceCallbacks.onBeforeMessage !== undefined;
@@ -378,7 +379,14 @@ export class EdrProviderWrapper
378379
const rawTraces = responseObject.traces;
379380
for (const rawTrace of rawTraces) {
380381
const trace = rawTrace.trace();
382+
383+
// beforeTx event
384+
if (this._node._vm.events.listenerCount("beforeTx") > 0) {
385+
this._node._vm.events.emit("beforeTx");
386+
}
387+
381388
for (const traceItem of trace) {
389+
// step event
382390
if ("pc" in traceItem) {
383391
if (this._node._vm.evm.events.listenerCount("step") > 0) {
384392
this._node._vm.evm.events.emit(
@@ -389,7 +397,9 @@ export class EdrProviderWrapper
389397
if (this._rawTraceCallbacks.onStep !== undefined) {
390398
await this._rawTraceCallbacks.onStep(traceItem);
391399
}
392-
} else if ("executionResult" in traceItem) {
400+
}
401+
// afterMessage event
402+
else if ("executionResult" in traceItem) {
393403
if (this._node._vm.evm.events.listenerCount("afterMessage") > 0) {
394404
this._node._vm.evm.events.emit(
395405
"afterMessage",
@@ -401,7 +411,9 @@ export class EdrProviderWrapper
401411
traceItem.executionResult
402412
);
403413
}
404-
} else {
414+
}
415+
// beforeMessage event
416+
else {
405417
if (this._node._vm.evm.events.listenerCount("beforeMessage") > 0) {
406418
this._node._vm.evm.events.emit(
407419
"beforeMessage",
@@ -413,6 +425,11 @@ export class EdrProviderWrapper
413425
}
414426
}
415427
}
428+
429+
// afterTx event
430+
if (this._node._vm.events.listenerCount("afterTx") > 0) {
431+
this._node._vm.events.emit("afterTx");
432+
}
416433
}
417434
}
418435

@@ -478,6 +495,10 @@ export class EdrProviderWrapper
478495
);
479496
}
480497

498+
private _setVerboseTracing(enabled: boolean) {
499+
this._provider.setVerboseTracing(enabled);
500+
}
501+
481502
private _ethEventListener(event: SubscriptionEvent) {
482503
const subscription = `0x${event.filterId.toString(16)}`;
483504
const results = Array.isArray(event.result) ? event.result : [event.result];

packages/hardhat-core/src/internal/hardhat-network/provider/utils/convertToEdr.ts

+36-4
Original file line numberDiff line numberDiff line change
@@ -208,24 +208,55 @@ export function edrRpcDebugTraceToHardhat(
208208
export function edrTracingStepToMinimalInterpreterStep(
209209
step: TracingStep
210210
): MinimalInterpreterStep {
211-
return {
211+
const minimalInterpreterStep: MinimalInterpreterStep = {
212212
pc: Number(step.pc),
213213
depth: step.depth,
214214
opcode: {
215215
name: step.opcode,
216216
},
217-
stack: step.stackTop !== undefined ? [step.stackTop] : [],
217+
stack: step.stack,
218218
};
219+
220+
if (step.memory !== undefined) {
221+
minimalInterpreterStep.memory = step.memory;
222+
}
223+
224+
return minimalInterpreterStep;
219225
}
220226

221227
export function edrTracingMessageResultToMinimalEVMResult(
222228
tracingMessageResult: TracingMessageResult
223229
): MinimalEVMResult {
224-
return {
230+
const { result, contractAddress } = tracingMessageResult.executionResult;
231+
232+
// only SuccessResult has logs
233+
const success = "logs" in result;
234+
235+
const minimalEVMResult: MinimalEVMResult = {
225236
execResult: {
226-
executionGasUsed: tracingMessageResult.executionResult.result.gasUsed,
237+
executionGasUsed: result.gasUsed,
238+
success,
227239
},
228240
};
241+
242+
// only success and exceptional halt have reason
243+
if ("reason" in result) {
244+
minimalEVMResult.execResult.reason = result.reason;
245+
}
246+
if ("output" in result) {
247+
const { output } = result;
248+
if (Buffer.isBuffer(output)) {
249+
minimalEVMResult.execResult.output = output;
250+
} else {
251+
minimalEVMResult.execResult.output = output.returnValue;
252+
}
253+
}
254+
255+
if (contractAddress !== undefined) {
256+
minimalEVMResult.execResult.contractAddress = new Address(contractAddress);
257+
}
258+
259+
return minimalEVMResult;
229260
}
230261

231262
export function edrTracingMessageToMinimalMessage(
@@ -241,5 +272,6 @@ export function edrTracingMessageToMinimalMessage(
241272
value: message.value,
242273
caller: new Address(message.caller),
243274
gasLimit: message.gasLimit,
275+
isStaticCall: message.isStaticCall,
244276
};
245277
}

packages/hardhat-core/src/internal/hardhat-network/provider/vm/minimal-vm.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import { AsyncEventEmitter } from "@nomicfoundation/ethereumjs-util";
1313
* interface only has the things used by those plugins.
1414
*/
1515
export interface MinimalEthereumJsVm {
16+
events: AsyncEventEmitter<MinimalEthereumJsVmEvents>;
1617
evm: {
17-
events: AsyncEventEmitter<MinimalEthereumJsVmEvents>;
18+
events: AsyncEventEmitter<MinimalEthereumJsEvmEvents>;
1819
};
1920
stateManager: {
2021
putContractCode: (address: Address, code: Buffer) => Promise<void>;
@@ -27,10 +28,18 @@ export interface MinimalEthereumJsVm {
2728
};
2829
}
2930

30-
// we need to use a type instead of an interface to satisfy the type constarint
31+
// we need to use a type instead of an interface to satisfy the type constraint
3132
// of the AsyncEventEmitter type param
3233
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
3334
type MinimalEthereumJsVmEvents = {
35+
beforeTx: () => void;
36+
afterTx: () => void;
37+
};
38+
39+
// we need to use a type instead of an interface to satisfy the type constraint
40+
// of the AsyncEventEmitter type param
41+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
42+
type MinimalEthereumJsEvmEvents = {
3443
beforeMessage: (
3544
data: MinimalMessage,
3645
resolve?: (result?: any) => void
@@ -46,13 +55,15 @@ type MinimalEthereumJsVmEvents = {
4655
};
4756

4857
export class MinimalEthereumJsVmEventEmitter extends AsyncEventEmitter<MinimalEthereumJsVmEvents> {}
58+
export class MinimalEthereumJsEvmEventEmitter extends AsyncEventEmitter<MinimalEthereumJsEvmEvents> {}
4959

5060
export function getMinimalEthereumJsVm(
5161
provider: EdrProviderT
5262
): MinimalEthereumJsVm {
5363
const minimalEthereumJsVm: MinimalEthereumJsVm = {
64+
events: new MinimalEthereumJsVmEventEmitter(),
5465
evm: {
55-
events: new MinimalEthereumJsVmEventEmitter(),
66+
events: new MinimalEthereumJsEvmEventEmitter(),
5667
},
5768
stateManager: {
5869
putContractCode: async (address: Address, code: Buffer) => {

packages/hardhat-core/src/internal/hardhat-network/provider/vm/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ExceptionalHalt, SuccessReason } from "@nomicfoundation/edr";
12
import type { Address } from "@nomicfoundation/ethereumjs-util";
23

34
/**
@@ -12,10 +13,15 @@ export interface MinimalInterpreterStep {
1213
name: string;
1314
};
1415
stack: bigint[];
16+
memory?: Uint8Array;
1517
}
1618

1719
export interface MinimalExecResult {
20+
success: boolean;
1821
executionGasUsed: bigint;
22+
contractAddress?: Address;
23+
reason?: SuccessReason | ExceptionalHalt;
24+
output?: Buffer;
1925
}
2026

2127
export interface MinimalEVMResult {
@@ -29,4 +35,5 @@ export interface MinimalMessage {
2935
data: Uint8Array;
3036
caller: Address;
3137
gasLimit: bigint;
38+
isStaticCall: boolean;
3239
}

packages/hardhat-truffle5/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@
6262
"rimraf": "^3.0.2",
6363
"ts-node": "^10.8.0",
6464
"typescript": "~5.0.0",
65-
"web3": "^1.0.0-beta.36"
65+
"web3": "^1.0.0-beta.36",
66+
"web3-eth-abi": "1.10.4",
67+
"web3-utils": "1.10.4"
6668
},
6769
"peerDependencies": {
6870
"@nomiclabs/hardhat-web3": "workspace:^2.0.0",

0 commit comments

Comments
 (0)