Skip to content

Commit 8caf898

Browse files
committed
refactor: Prune StackTraceEntry.message to make it clonable
1 parent 0cc20ca commit 8caf898

File tree

5 files changed

+34
-178
lines changed

5 files changed

+34
-178
lines changed

packages/hardhat-core/src/internal/hardhat-network/stack-traces/debug.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { bytesToHex as bufferToHex } from "@nomicfoundation/ethereumjs-util";
22
import chalk from "chalk";
33

4-
import { stackTraceEntryTypeToString } from "@nomicfoundation/edr";
4+
import { ReturnData, stackTraceEntryTypeToString } from "@nomicfoundation/edr";
55
import {
66
CallMessageTrace,
77
CreateMessageTrace,
@@ -152,7 +152,9 @@ function traceSteps(
152152
: "";
153153

154154
console.log(
155-
`${margin} ${pc} ${opcodeToString(inst.opcode)} ${jump}`.padEnd(50),
155+
`${margin} ${pc} ${opcodeToString(inst.opcode)} ${jump}`.padEnd(
156+
50
157+
),
156158
location
157159
);
158160
} else if (isPush(inst.opcode)) {
@@ -191,7 +193,7 @@ function flattenSourceReference(sourceReference?: SourceReference) {
191193
export function printStackTrace(trace: SolidityStackTrace) {
192194
const withDecodedMessages = trace.map((entry) =>
193195
entry.type === StackTraceEntryType.REVERT_ERROR
194-
? { ...entry, message: entry.message.decodeError() }
196+
? { ...entry, message: new ReturnData(entry.returnData).decodeError() }
195197
: entry
196198
);
197199

packages/hardhat-core/src/internal/hardhat-network/stack-traces/mapped-inlined-internal-functions-heuristics.ts

+4-143
Original file line numberDiff line numberDiff line change
@@ -18,146 +18,7 @@
1818
* more meaningful errors.
1919
*/
2020

21-
import semver from "semver";
22-
23-
import {
24-
DecodedEvmMessageTrace,
25-
isDecodedCallTrace,
26-
isDecodedCreateTrace,
27-
isEvmStep,
28-
} from "./message-trace";
29-
import { Opcode } from "./opcodes";
30-
import {
31-
SolidityStackTrace,
32-
StackTraceEntryType,
33-
} from "./solidity-stack-trace";
34-
35-
const FIRST_SOLC_VERSION_WITH_MAPPED_SMALL_INTERNAL_FUNCTIONS = "0.6.9";
36-
37-
export function stackTraceMayRequireAdjustments(
38-
stackTrace: SolidityStackTrace,
39-
decodedTrace: DecodedEvmMessageTrace
40-
): boolean {
41-
if (stackTrace.length === 0) {
42-
return false;
43-
}
44-
45-
const lastFrame = stackTrace[stackTrace.length - 1];
46-
47-
return (
48-
lastFrame.type === StackTraceEntryType.REVERT_ERROR &&
49-
!lastFrame.isInvalidOpcodeError &&
50-
lastFrame.message.isEmpty() &&
51-
semver.gte(
52-
decodedTrace.bytecode.compilerVersion,
53-
FIRST_SOLC_VERSION_WITH_MAPPED_SMALL_INTERNAL_FUNCTIONS
54-
)
55-
);
56-
}
57-
58-
export function adjustStackTrace(
59-
stackTrace: SolidityStackTrace,
60-
decodedTrace: DecodedEvmMessageTrace
61-
): SolidityStackTrace {
62-
const start = stackTrace.slice(0, -1);
63-
const [revert] = stackTrace.slice(-1);
64-
65-
if (isNonContractAccountCalledError(decodedTrace)) {
66-
return [
67-
...start,
68-
{
69-
type: StackTraceEntryType.NONCONTRACT_ACCOUNT_CALLED_ERROR,
70-
sourceReference: revert.sourceReference!,
71-
},
72-
];
73-
}
74-
75-
if (isConstructorInvalidParamsError(decodedTrace)) {
76-
return [
77-
...start,
78-
{
79-
type: StackTraceEntryType.INVALID_PARAMS_ERROR,
80-
sourceReference: revert.sourceReference!,
81-
},
82-
];
83-
}
84-
85-
if (isCallInvalidParamsError(decodedTrace)) {
86-
return [
87-
...start,
88-
{
89-
type: StackTraceEntryType.INVALID_PARAMS_ERROR,
90-
sourceReference: revert.sourceReference!,
91-
},
92-
];
93-
}
94-
95-
return stackTrace;
96-
}
97-
98-
function isNonContractAccountCalledError(
99-
decodedTrace: DecodedEvmMessageTrace
100-
): boolean {
101-
return matchOpcodes(decodedTrace, -9, [
102-
Opcode.EXTCODESIZE,
103-
Opcode.ISZERO,
104-
Opcode.DUP1,
105-
Opcode.ISZERO,
106-
]);
107-
}
108-
109-
function isConstructorInvalidParamsError(decodedTrace: DecodedEvmMessageTrace) {
110-
if (!isDecodedCreateTrace(decodedTrace)) {
111-
return false;
112-
}
113-
114-
return (
115-
matchOpcodes(decodedTrace, -20, [Opcode.CODESIZE]) &&
116-
matchOpcodes(decodedTrace, -15, [Opcode.CODECOPY]) &&
117-
matchOpcodes(decodedTrace, -7, [Opcode.LT, Opcode.ISZERO])
118-
);
119-
}
120-
121-
function isCallInvalidParamsError(decodedTrace: DecodedEvmMessageTrace) {
122-
if (!isDecodedCallTrace(decodedTrace)) {
123-
return false;
124-
}
125-
126-
return (
127-
matchOpcodes(decodedTrace, -11, [Opcode.CALLDATASIZE]) &&
128-
matchOpcodes(decodedTrace, -7, [Opcode.LT, Opcode.ISZERO])
129-
);
130-
}
131-
132-
function matchOpcode(
133-
decodedTrace: DecodedEvmMessageTrace,
134-
stepIndex: number,
135-
opcode: Opcode
136-
): boolean {
137-
const [step] = decodedTrace.steps.slice(stepIndex, stepIndex + 1);
138-
139-
if (step === undefined || !isEvmStep(step)) {
140-
return false;
141-
}
142-
143-
const instruction = decodedTrace.bytecode.getInstruction(step.pc);
144-
145-
return instruction.opcode === opcode;
146-
}
147-
148-
function matchOpcodes(
149-
decodedTrace: DecodedEvmMessageTrace,
150-
firstStepIndex: number,
151-
opcodes: Opcode[]
152-
): boolean {
153-
let index = firstStepIndex;
154-
for (const opcode of opcodes) {
155-
if (!matchOpcode(decodedTrace, index, opcode)) {
156-
return false;
157-
}
158-
159-
index += 1;
160-
}
161-
162-
return true;
163-
}
21+
export {
22+
stackTraceMayRequireAdjustments,
23+
adjustStackTrace,
24+
} from "@nomicfoundation/edr";

packages/hardhat-core/src/internal/hardhat-network/stack-traces/solidity-errors.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { bytesToHex as bufferToHex } from "@nomicfoundation/ethereumjs-util";
22

3+
import { ReturnData } from "../provider/return-data";
34
import { panicErrorCodeToMessage } from "./panic-errors";
45
import {
56
CONSTRUCTOR_FUNCTION_NAME,
@@ -259,23 +260,22 @@ function getMessageFromLastStackTraceEntry(
259260

260261
case StackTraceEntryType.UNRECOGNIZED_CREATE_ERROR:
261262
case StackTraceEntryType.UNRECOGNIZED_CONTRACT_ERROR:
262-
if (stackTraceEntry.message.isErrorReturnData()) {
263-
return `VM Exception while processing transaction: reverted with reason string '${stackTraceEntry.message.decodeError()}'`;
263+
let returnData = new ReturnData(stackTraceEntry.returnData);
264+
if (returnData.isErrorReturnData()) {
265+
return `VM Exception while processing transaction: reverted with reason string '${new ReturnData(
266+
stackTraceEntry.returnData
267+
).decodeError()}'`;
264268
}
265269

266-
if (stackTraceEntry.message.isPanicReturnData()) {
267-
const message = panicErrorCodeToMessage(
268-
stackTraceEntry.message.decodePanic()
269-
);
270+
if (returnData.isPanicReturnData()) {
271+
const message = panicErrorCodeToMessage(returnData.decodePanic());
270272
return `VM Exception while processing transaction: ${message}`;
271273
}
272274

273-
if (!stackTraceEntry.message.isEmpty()) {
274-
const returnData = Buffer.from(stackTraceEntry.message.value).toString(
275-
"hex"
276-
);
275+
if (!returnData.isEmpty()) {
276+
const buffer = Buffer.from(returnData.value).toString("hex");
277277

278-
return `VM Exception while processing transaction: reverted with an unrecognized custom error (return data: 0x${returnData})`;
278+
return `VM Exception while processing transaction: reverted with an unrecognized custom error (return data: 0x${buffer})`;
279279
}
280280

281281
if (stackTraceEntry.isInvalidOpcodeError) {
@@ -285,8 +285,9 @@ function getMessageFromLastStackTraceEntry(
285285
return "Transaction reverted without a reason string";
286286

287287
case StackTraceEntryType.REVERT_ERROR:
288-
if (stackTraceEntry.message.isErrorReturnData()) {
289-
return `VM Exception while processing transaction: reverted with reason string '${stackTraceEntry.message.decodeError()}'`;
288+
returnData = new ReturnData(stackTraceEntry.returnData);
289+
if (returnData.isErrorReturnData()) {
290+
return `VM Exception while processing transaction: reverted with reason string '${returnData.decodeError()}'`;
290291
}
291292

292293
if (stackTraceEntry.isInvalidOpcodeError) {

packages/hardhat-core/src/internal/hardhat-network/stack-traces/solidityTracer.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { equalsBytes } from "@nomicfoundation/ethereumjs-util";
22

33
import { SolidityTracer as SolidityTracerRs } from "@nomicfoundation/edr";
4-
import { ReturnData } from "../provider/return-data";
54
import { ExitCode } from "../provider/vm/exit";
65

76
import {
@@ -117,7 +116,7 @@ export class SolidityTracer {
117116
return [
118117
{
119118
type: StackTraceEntryType.UNRECOGNIZED_CREATE_ERROR,
120-
message: new ReturnData(trace.returnData),
119+
returnData: trace.returnData,
121120
isInvalidOpcodeError,
122121
},
123122
];
@@ -127,7 +126,7 @@ export class SolidityTracer {
127126
{
128127
type: StackTraceEntryType.UNRECOGNIZED_CONTRACT_ERROR,
129128
address: trace.address,
130-
message: new ReturnData(trace.returnData),
129+
returnData: trace.returnData,
131130
isInvalidOpcodeError,
132131
},
133132
];

packages/hardhat-core/test/internal/hardhat-network/stack-traces/test.ts

+9-16
Original file line numberDiff line numberDiff line change
@@ -336,22 +336,15 @@ function compareStackTraces(
336336
`Stack trace of tx ${txIndex} entry ${i} type is incorrect: expected ${expectedErrorType}, got ${actualErrorType}`
337337
);
338338

339-
const actualMessage = (actual as any).message as
340-
| ReturnData
341-
| string
342-
| undefined;
343-
344-
// actual.message is a ReturnData in revert errors, but a string
345-
// in custom errors
346-
let decodedMessage = "";
347-
if (typeof actualMessage === "string") {
348-
decodedMessage = actualMessage;
349-
} else if (
350-
actualMessage instanceof ReturnData &&
351-
actualMessage.isErrorReturnData()
352-
) {
353-
decodedMessage = actualMessage.decodeError();
354-
}
339+
// actual.message is a ReturnData in revert errors but in custom errors
340+
// we need to decode it
341+
const decodedMessage =
342+
"message" in actual
343+
? actual.message
344+
: "returnData" in actual &&
345+
new ReturnData(actual.returnData).isErrorReturnData()
346+
? new ReturnData(actual.returnData).decodeError()
347+
: "";
355348

356349
if (expected.message !== undefined) {
357350
assert.equal(

0 commit comments

Comments
 (0)