sol-dbg 0.3.7 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifacts/helpers.d.ts +2 -3
- package/dist/artifacts/helpers.d.ts.map +1 -1
- package/dist/artifacts/helpers.js +45 -14
- package/dist/artifacts/helpers.js.map +1 -1
- package/dist/debug/abi.d.ts +10 -4
- package/dist/debug/abi.d.ts.map +1 -1
- package/dist/debug/abi.js +41 -11
- package/dist/debug/abi.js.map +1 -1
- package/dist/debug/artifact_manager.d.ts +9 -10
- package/dist/debug/artifact_manager.d.ts.map +1 -1
- package/dist/debug/artifact_manager.js +7 -6
- package/dist/debug/artifact_manager.js.map +1 -1
- package/dist/debug/decoding/calldata.d.ts.map +1 -1
- package/dist/debug/decoding/calldata.js +5 -6
- package/dist/debug/decoding/calldata.js.map +1 -1
- package/dist/debug/decoding/general.js +2 -3
- package/dist/debug/decoding/general.js.map +1 -1
- package/dist/debug/decoding/memory.d.ts.map +1 -1
- package/dist/debug/decoding/memory.js +4 -5
- package/dist/debug/decoding/memory.js.map +1 -1
- package/dist/debug/decoding/stack.js +2 -3
- package/dist/debug/decoding/stack.js.map +1 -1
- package/dist/debug/decoding/storage.d.ts.map +1 -1
- package/dist/debug/decoding/storage.js +9 -9
- package/dist/debug/decoding/storage.js.map +1 -1
- package/dist/debug/foundry_cheatcodes.d.ts +31 -30
- package/dist/debug/foundry_cheatcodes.d.ts.map +1 -1
- package/dist/debug/foundry_cheatcodes.js +127 -143
- package/dist/debug/foundry_cheatcodes.js.map +1 -1
- package/dist/debug/opcode_interposing.d.ts +2 -1
- package/dist/debug/opcode_interposing.d.ts.map +1 -1
- package/dist/debug/opcode_interposing.js +28 -30
- package/dist/debug/opcode_interposing.js.map +1 -1
- package/dist/debug/opcodes.js +6 -6
- package/dist/debug/opcodes.js.map +1 -1
- package/dist/debug/sol_debugger.d.ts +10 -165
- package/dist/debug/sol_debugger.d.ts.map +1 -1
- package/dist/debug/sol_debugger.js +74 -102
- package/dist/debug/sol_debugger.js.map +1 -1
- package/dist/debug/types.d.ts +157 -0
- package/dist/debug/types.d.ts.map +1 -1
- package/dist/debug/types.js +14 -0
- package/dist/debug/types.js.map +1 -1
- package/dist/utils/ethereumjs_internal/exceptions.d.ts +44 -0
- package/dist/utils/ethereumjs_internal/exceptions.d.ts.map +1 -0
- package/dist/utils/ethereumjs_internal/exceptions.js +59 -0
- package/dist/utils/ethereumjs_internal/exceptions.js.map +1 -0
- package/dist/utils/ethereumjs_internal/index.d.ts +3 -0
- package/dist/utils/ethereumjs_internal/index.d.ts.map +1 -0
- package/dist/utils/ethereumjs_internal/index.js +19 -0
- package/dist/utils/ethereumjs_internal/index.js.map +1 -0
- package/dist/utils/ethereumjs_internal/opcodes.d.ts +33 -0
- package/dist/utils/ethereumjs_internal/opcodes.d.ts.map +1 -0
- package/dist/utils/ethereumjs_internal/opcodes.js +79 -0
- package/dist/utils/ethereumjs_internal/opcodes.js.map +1 -0
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/misc.d.ts +12 -20
- package/dist/utils/misc.d.ts.map +1 -1
- package/dist/utils/misc.js +39 -83
- package/dist/utils/misc.js.map +1 -1
- package/dist/utils/pp.d.ts.map +1 -1
- package/dist/utils/pp.js +10 -10
- package/dist/utils/pp.js.map +1 -1
- package/dist/utils/srcmap.js +2 -3
- package/dist/utils/srcmap.js.map +1 -1
- package/dist/utils/test_runner.d.ts +6 -6
- package/dist/utils/test_runner.d.ts.map +1 -1
- package/dist/utils/test_runner.js +11 -9
- package/dist/utils/test_runner.js.map +1 -1
- package/package.json +14 -12
|
@@ -1,166 +1,12 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import { Block } from "@ethereumjs/block";
|
|
3
|
-
import {
|
|
2
|
+
import { EVMStateManagerInterface } from "@ethereumjs/common";
|
|
4
3
|
import { InterpreterStep } from "@ethereumjs/evm";
|
|
5
|
-
import {
|
|
4
|
+
import { TypedTransaction } from "@ethereumjs/tx";
|
|
6
5
|
import { RunTxResult, VM } from "@ethereumjs/vm";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { DecodedBytecodeSourceMapEntry, HexString, ImmMap } from "..";
|
|
6
|
+
import { ASTNode } from "solc-typed-ast";
|
|
7
|
+
import { DecodedBytecodeSourceMapEntry } from "..";
|
|
10
8
|
import { ContractInfo, IArtifactManager } from "./artifact_manager";
|
|
11
|
-
import {
|
|
12
|
-
export declare enum FrameKind {
|
|
13
|
-
Call = "call",
|
|
14
|
-
Creation = "creation",
|
|
15
|
-
InternalCall = "internal_call"
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Base interface for Stack frames maintained by the debugger
|
|
19
|
-
*/
|
|
20
|
-
interface BaseFrame {
|
|
21
|
-
readonly kind: FrameKind;
|
|
22
|
-
/**
|
|
23
|
-
* AST node causing the call. Note that this is not always a FunctionCall. For example this could be:
|
|
24
|
-
* 1. A contract public state var VariableDeclaration
|
|
25
|
-
* 2. Any checked arithmetic operation in sol > 0.8.0 (these are implemented as internal functions)
|
|
26
|
-
* 3. Some other random non-call AST node, that is implemented as a compiler generated function
|
|
27
|
-
*/
|
|
28
|
-
readonly callee: ASTNode | undefined;
|
|
29
|
-
/**
|
|
30
|
-
* If we have a `callee` try and infer where the arguments are placed in the VM state. Some arguments may not
|
|
31
|
-
* exist in the case of msg.data generated from a fuzzer for example.
|
|
32
|
-
*/
|
|
33
|
-
readonly arguments: Array<[string, DataView | undefined]> | undefined;
|
|
34
|
-
readonly startStep: number;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Base class for a stack frame corresponding to an external call.
|
|
38
|
-
*/
|
|
39
|
-
interface BaseExternalFrame extends BaseFrame {
|
|
40
|
-
readonly sender: HexString;
|
|
41
|
-
readonly msgData: Buffer;
|
|
42
|
-
readonly address: Address;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Stack frame corresponding to an external call
|
|
46
|
-
*/
|
|
47
|
-
interface CallFrame extends BaseExternalFrame {
|
|
48
|
-
readonly kind: FrameKind.Call;
|
|
49
|
-
readonly receiver: HexString;
|
|
50
|
-
readonly code: Buffer;
|
|
51
|
-
readonly info?: ContractInfo;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Stack frame corresponding to a contract creation call
|
|
55
|
-
*/
|
|
56
|
-
interface CreationFrame extends BaseExternalFrame {
|
|
57
|
-
readonly kind: FrameKind.Creation;
|
|
58
|
-
readonly creationCode: Buffer;
|
|
59
|
-
readonly info?: ContractInfo;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Stack frame corresponding to an internal function call
|
|
63
|
-
*/
|
|
64
|
-
interface InternalCallFrame extends BaseFrame {
|
|
65
|
-
readonly kind: FrameKind.InternalCall;
|
|
66
|
-
readonly nearestExtFrame: CallFrame | CreationFrame;
|
|
67
|
-
readonly offset: number;
|
|
68
|
-
}
|
|
69
|
-
export type ExternalFrame = CallFrame | CreationFrame;
|
|
70
|
-
export type Frame = ExternalFrame | InternalCallFrame;
|
|
71
|
-
export type DbgStack = Frame[];
|
|
72
|
-
export declare enum DataLocationKind {
|
|
73
|
-
Stack = "stack",
|
|
74
|
-
Memory = "memory",
|
|
75
|
-
Storage = "storage",
|
|
76
|
-
CallData = "calldata"
|
|
77
|
-
}
|
|
78
|
-
export type MemoryLocationKind = DataLocationKind.Memory | DataLocationKind.CallData | DataLocationKind.Storage;
|
|
79
|
-
export interface BaseDataLocation {
|
|
80
|
-
kind: DataLocationKind;
|
|
81
|
-
}
|
|
82
|
-
export interface StackLocation extends BaseDataLocation {
|
|
83
|
-
kind: DataLocationKind.Stack;
|
|
84
|
-
offsetFromTop: number;
|
|
85
|
-
}
|
|
86
|
-
export interface BaseMemoryLocation extends BaseDataLocation {
|
|
87
|
-
address: bigint;
|
|
88
|
-
}
|
|
89
|
-
export interface CalldataLocation extends BaseMemoryLocation {
|
|
90
|
-
kind: DataLocationKind.CallData;
|
|
91
|
-
}
|
|
92
|
-
export interface LinearMemoryLocation extends BaseMemoryLocation {
|
|
93
|
-
kind: DataLocationKind.Memory;
|
|
94
|
-
}
|
|
95
|
-
export interface StorageLocation extends BaseMemoryLocation {
|
|
96
|
-
kind: DataLocationKind.Storage;
|
|
97
|
-
endOffsetInWord: number;
|
|
98
|
-
}
|
|
99
|
-
export type ByteAddressableMemoryLocation = CalldataLocation | LinearMemoryLocation;
|
|
100
|
-
export type MemoryLocation = ByteAddressableMemoryLocation | StorageLocation;
|
|
101
|
-
export type DataLocation = StackLocation | MemoryLocation;
|
|
102
|
-
export interface DataView {
|
|
103
|
-
type: TypeNode;
|
|
104
|
-
abiType?: TypeNode;
|
|
105
|
-
loc: DataLocation;
|
|
106
|
-
}
|
|
107
|
-
export type Memory = Buffer;
|
|
108
|
-
export type Stack = Buffer[];
|
|
109
|
-
export type Storage = ImmMap<bigint, Buffer>;
|
|
110
|
-
export interface EventDesc {
|
|
111
|
-
payload: Buffer;
|
|
112
|
-
topics: bigint[];
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* TODO(dimo): Make memory and storage be computed only for instructions that change them, and for all other
|
|
116
|
-
* instructions alias the previous steps' memory/storage
|
|
117
|
-
*
|
|
118
|
-
* Low-level machine state at a given trace step. It directly mirrors the state reported from Web3
|
|
119
|
-
* and doesn't include any higher-level information that requires debug info.
|
|
120
|
-
*/
|
|
121
|
-
export interface StepVMState {
|
|
122
|
-
evmStack: Stack;
|
|
123
|
-
memory: Memory;
|
|
124
|
-
storage: Storage;
|
|
125
|
-
op: EVMOpInfo;
|
|
126
|
-
pc: number;
|
|
127
|
-
gasCost: bigint;
|
|
128
|
-
dynamicGasCost: bigint;
|
|
129
|
-
gas: bigint;
|
|
130
|
-
depth: number;
|
|
131
|
-
address: Address;
|
|
132
|
-
codeAddress: Address;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* State that the debugger maintains for each trace step.
|
|
136
|
-
* It includes the basic VM state (`StepVmState`) and optionally (if we have debug info for this contract)
|
|
137
|
-
* includes the decoded source location, any AST nodes that are mapped to this instruction and any events
|
|
138
|
-
* that may be emitted on this step.
|
|
139
|
-
*/
|
|
140
|
-
export interface StepState extends StepVMState {
|
|
141
|
-
code: Buffer;
|
|
142
|
-
codeMdHash: HexString | undefined;
|
|
143
|
-
stack: DbgStack;
|
|
144
|
-
src: DecodedBytecodeSourceMapEntry | undefined;
|
|
145
|
-
astNode: ASTNode | undefined;
|
|
146
|
-
emittedEvent: EventDesc | undefined;
|
|
147
|
-
contractInfo: ContractInfo | undefined;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Trace step struct contained in the array returned by web3.debug.traceTransaction().
|
|
151
|
-
* We translate this into `StepVmState`.
|
|
152
|
-
*/
|
|
153
|
-
export interface Web3DbgState {
|
|
154
|
-
stack: HexString[];
|
|
155
|
-
memory: HexString[];
|
|
156
|
-
storage?: any;
|
|
157
|
-
op: string;
|
|
158
|
-
pc: number;
|
|
159
|
-
gasCost: string;
|
|
160
|
-
gas: string;
|
|
161
|
-
depth: number;
|
|
162
|
-
error?: any;
|
|
163
|
-
}
|
|
9
|
+
import { DbgStack, ExternalFrame, Frame, StepState } from "./types";
|
|
164
10
|
/**
|
|
165
11
|
* Give a stack or a stack frame, find the last **external** stack frame under it (include itself).
|
|
166
12
|
*/
|
|
@@ -219,7 +65,7 @@ export declare class SolTxDebugger {
|
|
|
219
65
|
* @param trace - trace up to the current state
|
|
220
66
|
*/
|
|
221
67
|
private getCodeAndMdHash;
|
|
222
|
-
processRawTraceStep(vm: VM, stateManager:
|
|
68
|
+
processRawTraceStep(vm: VM, stateManager: EVMStateManagerInterface, step: InterpreterStep, trace: StepState[], stack: Frame[]): Promise<StepState>;
|
|
223
69
|
private static getEVM;
|
|
224
70
|
/**
|
|
225
71
|
* Releases references to the EVM stored inside VM from the
|
|
@@ -229,10 +75,10 @@ export declare class SolTxDebugger {
|
|
|
229
75
|
* used.
|
|
230
76
|
*/
|
|
231
77
|
static releaseVM(vm: VM): void;
|
|
232
|
-
static createVm(stateManager:
|
|
233
|
-
debugTx(tx:
|
|
78
|
+
static createVm(stateManager: EVMStateManagerInterface | undefined, foundryCheatcodes: boolean): Promise<VM>;
|
|
79
|
+
debugTx(tx: TypedTransaction, block: Block | undefined, stateManager: EVMStateManagerInterface): Promise<[StepState[], RunTxResult]>;
|
|
234
80
|
/**
|
|
235
|
-
* Build a `CreationFrame` from the given `sender` address, `data` `
|
|
81
|
+
* Build a `CreationFrame` from the given `sender` address, `data` `Uint8Array`(msg.data) and the current trace step number.
|
|
236
82
|
*/
|
|
237
83
|
private makeCreationFrame;
|
|
238
84
|
/**
|
|
@@ -243,7 +89,7 @@ export declare class SolTxDebugger {
|
|
|
243
89
|
*/
|
|
244
90
|
private findEntryPoint;
|
|
245
91
|
/**
|
|
246
|
-
* Build a `CallFrame` from the given `sender` address, `receiver` address, `data` `
|
|
92
|
+
* Build a `CallFrame` from the given `sender` address, `receiver` address, `data` `Uint8Array`, (msg.data) and the current trace step number.
|
|
247
93
|
*/
|
|
248
94
|
private makeCallFrame;
|
|
249
95
|
/**
|
|
@@ -264,5 +110,4 @@ export declare class SolTxDebugger {
|
|
|
264
110
|
*/
|
|
265
111
|
private decodeFunArgs;
|
|
266
112
|
}
|
|
267
|
-
export {};
|
|
268
113
|
//# sourceMappingURL=sol_debugger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sol_debugger.d.ts","sourceRoot":"","sources":["../../src/debug/sol_debugger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sol_debugger.d.ts","sourceRoot":"","sources":["../../src/debug/sol_debugger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAiB,wBAAwB,EAAY,MAAM,oBAAoB,CAAC;AACvF,OAAO,EAAO,eAAe,EAAmB,MAAM,iBAAiB,CAAC;AAGxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,OAAO,EAA6D,MAAM,gBAAgB,CAAC;AACpG,OAAO,EACH,6BAA6B,EAQhC,MAAM,IAAI,CAAC;AAIZ,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAgB,MAAM,oBAAoB,CAAC;AASlF,OAAO,EAKH,QAAQ,EAGR,aAAa,EACb,KAAK,EAKL,SAAS,EAGZ,MAAM,SAAS,CAAC;AAIjB;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,KAAK,GAAG,QAAQ,GAAG,aAAa,CAItE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,KAAK,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAI/E;AAiBD,MAAM,WAAW,iBAAiB;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAQD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAa;IAEtB,SAAgB,eAAe,EAAE,gBAAgB,CAAC;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAU;gBAEhC,eAAe,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,iBAAiB;IAgBvE;;;;;;;;OAQG;YACW,gBAAgB;IA2K9B;;;;;;;;;;;;OAYG;YACW,gBAAgB;IA8CxB,mBAAmB,CACrB,EAAE,EAAE,EAAE,EACN,YAAY,EAAE,wBAAwB,EACtC,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,SAAS,EAAE,EAClB,KAAK,EAAE,KAAK,EAAE,GACf,OAAO,CAAC,SAAS,CAAC;mBAoFA,MAAM;IA8B3B;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI;WAUjB,QAAQ,CACjB,YAAY,EAAE,wBAAwB,GAAG,SAAS,EAClD,iBAAiB,EAAE,OAAO,GAC3B,OAAO,CAAC,EAAE,CAAC;IA0BR,OAAO,CACT,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,YAAY,EAAE,wBAAwB,GACvC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,WAAW,CAAC,CAAC;IA2DtC;;OAEG;YACW,iBAAiB;IA0B/B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;YACW,aAAa;IAqD3B;;;;;;;;;OASG;IACH,eAAe,CACX,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,aAAa,GACnB,CAAC,6BAA6B,GAAG,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC;IAiBnE;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAoDxB"}
|
|
@@ -1,57 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SolTxDebugger =
|
|
3
|
+
exports.SolTxDebugger = void 0;
|
|
4
|
+
exports.lastExternalFrame = lastExternalFrame;
|
|
5
|
+
exports.getContractInfo = getContractInfo;
|
|
4
6
|
const blockchain_1 = require("@ethereumjs/blockchain");
|
|
5
7
|
const common_1 = require("@ethereumjs/common");
|
|
6
|
-
const evm_1 = require("@ethereumjs/evm
|
|
8
|
+
const evm_1 = require("@ethereumjs/evm");
|
|
9
|
+
const rlp_1 = require("@ethereumjs/rlp");
|
|
7
10
|
const statemanager_1 = require("@ethereumjs/statemanager");
|
|
11
|
+
const util_1 = require("@ethereumjs/util");
|
|
8
12
|
const vm_1 = require("@ethereumjs/vm");
|
|
9
|
-
const
|
|
13
|
+
const utils_1 = require("ethereum-cryptography/utils");
|
|
10
14
|
const solc_typed_ast_1 = require("solc-typed-ast");
|
|
11
15
|
const __1 = require("..");
|
|
12
16
|
const artifacts_1 = require("../artifacts");
|
|
17
|
+
const utils_2 = require("../utils");
|
|
13
18
|
const abi_1 = require("./abi");
|
|
14
|
-
const utils_1 = require("../utils");
|
|
15
19
|
const artifact_manager_1 = require("./artifact_manager");
|
|
16
20
|
const decoding_1 = require("./decoding");
|
|
17
21
|
const foundry_cheatcodes_1 = require("./foundry_cheatcodes");
|
|
18
|
-
const opcodes_1 = require("@ethereumjs/evm/dist/opcodes");
|
|
19
22
|
const opcode_interposing_1 = require("./opcode_interposing");
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
var FrameKind;
|
|
23
|
-
(function (FrameKind) {
|
|
24
|
-
FrameKind["Call"] = "call";
|
|
25
|
-
FrameKind["Creation"] = "creation";
|
|
26
|
-
FrameKind["InternalCall"] = "internal_call";
|
|
27
|
-
})(FrameKind || (exports.FrameKind = FrameKind = {}));
|
|
28
|
-
var DataLocationKind;
|
|
29
|
-
(function (DataLocationKind) {
|
|
30
|
-
DataLocationKind["Stack"] = "stack";
|
|
31
|
-
DataLocationKind["Memory"] = "memory";
|
|
32
|
-
DataLocationKind["Storage"] = "storage";
|
|
33
|
-
DataLocationKind["CallData"] = "calldata";
|
|
34
|
-
})(DataLocationKind || (exports.DataLocationKind = DataLocationKind = {}));
|
|
23
|
+
const opcodes_1 = require("./opcodes");
|
|
24
|
+
const types_1 = require("./types");
|
|
35
25
|
// Helper functions
|
|
36
26
|
/**
|
|
37
27
|
* Give a stack or a stack frame, find the last **external** stack frame under it (include itself).
|
|
38
28
|
*/
|
|
39
29
|
function lastExternalFrame(arg) {
|
|
40
30
|
const frame = arg instanceof Array ? arg[arg.length - 1] : arg;
|
|
41
|
-
return frame.kind === FrameKind.InternalCall ? frame.nearestExtFrame : frame;
|
|
31
|
+
return frame.kind === types_1.FrameKind.InternalCall ? frame.nearestExtFrame : frame;
|
|
42
32
|
}
|
|
43
|
-
exports.lastExternalFrame = lastExternalFrame;
|
|
44
33
|
function getContractInfo(arg) {
|
|
45
34
|
const frame = lastExternalFrame(arg);
|
|
46
35
|
return frame.info;
|
|
47
36
|
}
|
|
48
|
-
exports.getContractInfo = getContractInfo;
|
|
49
37
|
async function getStorage(manager, addr) {
|
|
50
38
|
const rawStorage = await manager.dumpStorage(addr);
|
|
51
39
|
const storageEntries = [];
|
|
52
40
|
for (const [keyStr, valStr] of Object.entries(rawStorage)) {
|
|
53
|
-
const
|
|
54
|
-
|
|
41
|
+
const decoded = rlp_1.RLP.decode((0, utils_1.hexToBytes)(valStr));
|
|
42
|
+
(0, solc_typed_ast_1.assert)(decoded instanceof Uint8Array, "");
|
|
43
|
+
const valBuf = (0, util_1.setLengthLeft)(decoded, 32);
|
|
44
|
+
storageEntries.push([BigInt(keyStr), valBuf]);
|
|
55
45
|
}
|
|
56
46
|
return __1.ImmMap.fromEntries(storageEntries);
|
|
57
47
|
}
|
|
@@ -114,23 +104,23 @@ class SolTxDebugger {
|
|
|
114
104
|
if (lastStep.depth !== state.depth) {
|
|
115
105
|
const lastStackTop = lastStep.evmStack.length - 1;
|
|
116
106
|
if (state.depth > lastStep.depth) {
|
|
117
|
-
(0, solc_typed_ast_1.assert)((0,
|
|
118
|
-
if ((0,
|
|
107
|
+
(0, solc_typed_ast_1.assert)((0, opcodes_1.increasesDepth)(lastOp), `Unexpected depth increase on op ${lastOp.mnemonic}`);
|
|
108
|
+
if ((0, opcodes_1.createsContract)(lastOp)) {
|
|
119
109
|
// Contract creation call
|
|
120
|
-
const off = (0,
|
|
121
|
-
const size = (0,
|
|
110
|
+
const off = (0, utils_2.bigEndianBufToNumber)(lastStep.evmStack[lastStackTop - 1]);
|
|
111
|
+
const size = (0, utils_2.bigEndianBufToNumber)(lastStep.evmStack[lastStackTop - 2]);
|
|
122
112
|
const creationBytecode = lastStep.memory.slice(off, off + size);
|
|
123
113
|
const curFrame = await this.makeCreationFrame(lastExtFrame.address.toString(), creationBytecode, trace.length);
|
|
124
114
|
stack.push(curFrame);
|
|
125
115
|
}
|
|
126
116
|
else {
|
|
127
117
|
// External call
|
|
128
|
-
const argStackOff = lastOp.opcode ===
|
|
118
|
+
const argStackOff = lastOp.opcode === opcodes_1.OPCODES.CALL || lastOp.opcode === opcodes_1.OPCODES.CALLCODE
|
|
129
119
|
? 3
|
|
130
120
|
: 2;
|
|
131
121
|
const argSizeStackOff = argStackOff + 1;
|
|
132
|
-
const argOff = (0,
|
|
133
|
-
const argSize = (0,
|
|
122
|
+
const argOff = (0, utils_2.bigEndianBufToNumber)(lastStep.evmStack[lastStackTop - argStackOff]);
|
|
123
|
+
const argSize = (0, utils_2.bigEndianBufToNumber)(lastStep.evmStack[lastStackTop - argSizeStackOff]);
|
|
134
124
|
const receiver = (0, __1.wordToAddress)(lastStep.evmStack[lastStackTop - 1]);
|
|
135
125
|
const msgData = lastStep.memory.slice(argOff, argOff + argSize);
|
|
136
126
|
const newFrame = await this.makeCallFrame(lastExtFrame.address.toString(), receiver, msgData, code, codeHash, trace.length);
|
|
@@ -144,7 +134,7 @@ class SolTxDebugger {
|
|
|
144
134
|
// depth reported by web3. We need the loop since we don't count the internal frames as decreasing depth
|
|
145
135
|
while (nFramesPopped > 0 && stack.length > 0) {
|
|
146
136
|
const topFrame = stack[stack.length - 1];
|
|
147
|
-
if (topFrame.kind === FrameKind.Creation || topFrame.kind === FrameKind.Call) {
|
|
137
|
+
if (topFrame.kind === types_1.FrameKind.Creation || topFrame.kind === types_1.FrameKind.Call) {
|
|
148
138
|
nFramesPopped--;
|
|
149
139
|
}
|
|
150
140
|
stack.pop();
|
|
@@ -186,7 +176,7 @@ class SolTxDebugger {
|
|
|
186
176
|
args = this.decodeFunArgs(ast, state.evmStack, curExtFrame.info);
|
|
187
177
|
}
|
|
188
178
|
const newFrame = {
|
|
189
|
-
kind: FrameKind.InternalCall,
|
|
179
|
+
kind: types_1.FrameKind.InternalCall,
|
|
190
180
|
nearestExtFrame: lastExtFrame,
|
|
191
181
|
callee: ast,
|
|
192
182
|
offset: state.pc,
|
|
@@ -200,11 +190,11 @@ class SolTxDebugger {
|
|
|
200
190
|
if (state.op.mnemonic === "JUMP" && src.jump === "o") {
|
|
201
191
|
const topFrame = stack[stack.length - 1];
|
|
202
192
|
if (this.strict) {
|
|
203
|
-
(0, solc_typed_ast_1.assert)(topFrame.kind === FrameKind.InternalCall, `Mismatched internal return from frame `, topFrame.kind);
|
|
193
|
+
(0, solc_typed_ast_1.assert)(topFrame.kind === types_1.FrameKind.InternalCall, `Mismatched internal return from frame `, topFrame.kind);
|
|
204
194
|
stack.pop();
|
|
205
195
|
}
|
|
206
196
|
else {
|
|
207
|
-
if (topFrame.kind === FrameKind.InternalCall) {
|
|
197
|
+
if (topFrame.kind === types_1.FrameKind.InternalCall) {
|
|
208
198
|
stack.pop();
|
|
209
199
|
}
|
|
210
200
|
// @todo log an error somewhere
|
|
@@ -228,36 +218,43 @@ class SolTxDebugger {
|
|
|
228
218
|
const lastStep = trace.length > 0 ? trace[trace.length - 1] : undefined;
|
|
229
219
|
let code;
|
|
230
220
|
let codeMdHash;
|
|
231
|
-
|
|
221
|
+
const getCodeAddress = (s) => s.codeAddress !== undefined ? s.codeAddress : s.address;
|
|
222
|
+
// Case 1: First step in the trace
|
|
223
|
+
if (lastStep === undefined) {
|
|
224
|
+
const code = await vm.stateManager.getContractCode(getCodeAddress(step));
|
|
225
|
+
const codeMdHash = (0, artifacts_1.getCodeHash)(code);
|
|
226
|
+
return [code, codeMdHash];
|
|
227
|
+
}
|
|
228
|
+
// Case 2: Just entering a constructor from another contract
|
|
229
|
+
if ((0, opcodes_1.createsContract)(lastStep.op)) {
|
|
232
230
|
const lastStackTop = lastStep.evmStack.length - 1;
|
|
233
|
-
const off = (0,
|
|
234
|
-
const size = (0,
|
|
235
|
-
code = lastStep.memory.slice(off, off + size);
|
|
236
|
-
codeMdHash = (0, artifacts_1.getCreationCodeHash)(code);
|
|
231
|
+
const off = (0, utils_2.bigEndianBufToNumber)(lastStep.evmStack[lastStackTop - 1]);
|
|
232
|
+
const size = (0, utils_2.bigEndianBufToNumber)(lastStep.evmStack[lastStackTop - 2]);
|
|
233
|
+
const code = lastStep.memory.slice(off, off + size);
|
|
234
|
+
const codeMdHash = (0, artifacts_1.getCreationCodeHash)(code);
|
|
235
|
+
return [code, codeMdHash];
|
|
237
236
|
}
|
|
238
|
-
|
|
239
|
-
|
|
237
|
+
// Case 3: The code changed - either we are in a different contract or a delegate call context
|
|
238
|
+
if (!getCodeAddress(lastStep).equals(getCodeAddress(step))) {
|
|
239
|
+
// Case 3: We are changing the code address
|
|
240
|
+
code = await vm.stateManager.getContractCode(getCodeAddress(step));
|
|
240
241
|
codeMdHash = (0, artifacts_1.getCodeHash)(code);
|
|
242
|
+
return [code, codeMdHash];
|
|
241
243
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
244
|
+
// Case 4: We are still in the same contract
|
|
245
|
+
code = lastStep.code;
|
|
246
|
+
codeMdHash = lastStep.codeMdHash;
|
|
246
247
|
return [code, codeMdHash];
|
|
247
248
|
}
|
|
248
249
|
async processRawTraceStep(vm, stateManager, step, trace, stack) {
|
|
249
|
-
const evmStack = step.stack.map((word) => (0,
|
|
250
|
+
const evmStack = step.stack.map((word) => (0, utils_2.bigIntToBuf)(word, 32, "big"));
|
|
250
251
|
const lastStep = trace.length > 0 ? trace[trace.length - 1] : undefined;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
else {
|
|
256
|
-
memory = lastStep.memory;
|
|
257
|
-
}
|
|
258
|
-
const op = (0, opcodes_2.getOpInfo)(step.opcode.name);
|
|
252
|
+
const memory = lastStep === undefined || (0, opcodes_1.changesMemory)(lastStep.op)
|
|
253
|
+
? new Uint8Array(step.memory)
|
|
254
|
+
: lastStep.memory;
|
|
255
|
+
const op = (0, opcodes_1.getOpInfo)(step.opcode.name);
|
|
259
256
|
let storage;
|
|
260
|
-
if (lastStep === undefined || lastStep.op.opcode ===
|
|
257
|
+
if (lastStep === undefined || lastStep.op.opcode === opcodes_1.OPCODES.SSTORE) {
|
|
261
258
|
storage = await getStorage(stateManager, step.address);
|
|
262
259
|
}
|
|
263
260
|
else {
|
|
@@ -293,8 +290,8 @@ class SolTxDebugger {
|
|
|
293
290
|
let emittedEvent = undefined;
|
|
294
291
|
// Finally check if an event is being emitted for this step
|
|
295
292
|
if (step.opcode.name.startsWith("LOG")) {
|
|
296
|
-
const off = (0,
|
|
297
|
-
const size = (0,
|
|
293
|
+
const off = (0, utils_2.bigEndianBufToNumber)(evmStack[evmStack.length - 1]);
|
|
294
|
+
const size = (0, utils_2.bigEndianBufToNumber)(evmStack[evmStack.length - 2]);
|
|
298
295
|
const nTopics = step.opcode.name[3] - "0";
|
|
299
296
|
const payload = memory.slice(off, off + size);
|
|
300
297
|
emittedEvent = {
|
|
@@ -321,7 +318,7 @@ class SolTxDebugger {
|
|
|
321
318
|
if (!foundryCheatcodes) {
|
|
322
319
|
return tmpEvm;
|
|
323
320
|
}
|
|
324
|
-
const opcodes = (0,
|
|
321
|
+
const opcodes = (0, evm_1.getOpcodesForHF)(tmpEvm.common);
|
|
325
322
|
const [precompile, foundryCtx] = (0, foundry_cheatcodes_1.makeFoundryCheatcodePrecompile)();
|
|
326
323
|
const optsCopy = {
|
|
327
324
|
...opts,
|
|
@@ -338,11 +335,7 @@ class SolTxDebugger {
|
|
|
338
335
|
]
|
|
339
336
|
};
|
|
340
337
|
const res = await evm_1.EVM.create(optsCopy);
|
|
341
|
-
|
|
342
|
-
emitter.on("beforeInterpRun", foundryCtx.beforeInterpRunCB.bind(foundryCtx));
|
|
343
|
-
emitter.on("afterInterpRun", foundryCtx.afterInterpRunCB.bind(foundryCtx));
|
|
344
|
-
foundry_cheatcodes_1.interpRunListeners.set(res, emitter);
|
|
345
|
-
(0, foundry_cheatcodes_1.setFoundryCtx)(res, foundryCtx);
|
|
338
|
+
foundry_cheatcodes_1.foundryCtxMap.set(res, foundryCtx);
|
|
346
339
|
return res;
|
|
347
340
|
}
|
|
348
341
|
/**
|
|
@@ -355,7 +348,7 @@ class SolTxDebugger {
|
|
|
355
348
|
static releaseVM(vm) {
|
|
356
349
|
const evm = vmToEVMMap.get(vm);
|
|
357
350
|
if (evm) {
|
|
358
|
-
foundry_cheatcodes_1.
|
|
351
|
+
foundry_cheatcodes_1.foundryCtxMap.delete(evm);
|
|
359
352
|
}
|
|
360
353
|
vmToEVMMap.delete(vm);
|
|
361
354
|
}
|
|
@@ -365,8 +358,7 @@ class SolTxDebugger {
|
|
|
365
358
|
if (!stateManager) {
|
|
366
359
|
stateManager = new statemanager_1.DefaultStateManager();
|
|
367
360
|
}
|
|
368
|
-
const
|
|
369
|
-
const evm = await SolTxDebugger.getEVM({ common, eei, allowUnlimitedContractSize: true }, foundryCheatcodes);
|
|
361
|
+
const evm = await SolTxDebugger.getEVM({ common, blockchain, stateManager, allowUnlimitedContractSize: true }, foundryCheatcodes);
|
|
370
362
|
const vm = await vm_1.VM.create({
|
|
371
363
|
common,
|
|
372
364
|
blockchain,
|
|
@@ -378,7 +370,7 @@ class SolTxDebugger {
|
|
|
378
370
|
return vm;
|
|
379
371
|
}
|
|
380
372
|
async debugTx(tx, block, stateManager) {
|
|
381
|
-
const vm = await SolTxDebugger.createVm(stateManager, this.foundryCheatcodes);
|
|
373
|
+
const vm = await SolTxDebugger.createVm(stateManager.shallowCopy(true), this.foundryCheatcodes);
|
|
382
374
|
const sender = tx.getSenderAddress().toString();
|
|
383
375
|
const receiver = tx.to === undefined ? __1.ZERO_ADDRESS_STRING : tx.to.toString();
|
|
384
376
|
const isCreation = receiver === __1.ZERO_ADDRESS_STRING;
|
|
@@ -388,7 +380,7 @@ class SolTxDebugger {
|
|
|
388
380
|
curFrame = await this.makeCreationFrame(sender, tx.data, 0);
|
|
389
381
|
}
|
|
390
382
|
else {
|
|
391
|
-
(0, solc_typed_ast_1.assert)(tx.to !== undefined, 'Expected "to" of tx {0} to be defined, got undefined instead', tx.hash()
|
|
383
|
+
(0, solc_typed_ast_1.assert)(tx.to !== undefined, 'Expected "to" of tx {0} to be defined, got undefined instead', (0, utils_1.bytesToHex)(tx.hash()));
|
|
392
384
|
const code = await vm.stateManager.getContractCode(tx.to);
|
|
393
385
|
/// @todo remove - arbitrary restriction, only good for debugging
|
|
394
386
|
(0, solc_typed_ast_1.assert)(code.length > 0, "Missing code for address {0}", tx.to.toString());
|
|
@@ -414,7 +406,7 @@ class SolTxDebugger {
|
|
|
414
406
|
return [trace, txRes];
|
|
415
407
|
}
|
|
416
408
|
/**
|
|
417
|
-
* Build a `CreationFrame` from the given `sender` address, `data` `
|
|
409
|
+
* Build a `CreationFrame` from the given `sender` address, `data` `Uint8Array`(msg.data) and the current trace step number.
|
|
418
410
|
*/
|
|
419
411
|
async makeCreationFrame(sender, data, step) {
|
|
420
412
|
const contractInfo = await this.artifactManager.getContractFromCreationBytecode(data);
|
|
@@ -424,7 +416,7 @@ class SolTxDebugger {
|
|
|
424
416
|
// TODO: Try and find the arguments inside the creation code and decode them
|
|
425
417
|
}
|
|
426
418
|
return {
|
|
427
|
-
kind: FrameKind.Creation,
|
|
419
|
+
kind: types_1.FrameKind.Creation,
|
|
428
420
|
sender,
|
|
429
421
|
msgData: data,
|
|
430
422
|
creationCode: data,
|
|
@@ -447,38 +439,16 @@ class SolTxDebugger {
|
|
|
447
439
|
}
|
|
448
440
|
const contract = info.ast;
|
|
449
441
|
const infer = this.artifactManager.infer(info.artifact.compilerVersion);
|
|
450
|
-
|
|
451
|
-
// Need to be defensive here, as in some cases with partial AST information the base may be missing
|
|
452
|
-
if (base === undefined) {
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
const matchingFuns = base.vFunctions.filter((fun) => (0, __1.getFunctionSelector)(fun, infer) === selector);
|
|
456
|
-
if (matchingFuns.length === 1) {
|
|
457
|
-
return matchingFuns[0];
|
|
458
|
-
}
|
|
459
|
-
const matchingGetters = base.vStateVariables.filter((vDef) => {
|
|
460
|
-
try {
|
|
461
|
-
return (vDef.visibility === solc_typed_ast_1.StateVariableVisibility.Public &&
|
|
462
|
-
infer.signatureHash(vDef));
|
|
463
|
-
}
|
|
464
|
-
catch (e) {
|
|
465
|
-
return false;
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
if (matchingGetters.length === 1) {
|
|
469
|
-
return matchingGetters[0];
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
return undefined;
|
|
442
|
+
return (0, abi_1.findMethodBySelector)(selector, contract, infer);
|
|
473
443
|
}
|
|
474
444
|
/**
|
|
475
|
-
* Build a `CallFrame` from the given `sender` address, `receiver` address, `data` `
|
|
445
|
+
* Build a `CallFrame` from the given `sender` address, `receiver` address, `data` `Uint8Array`, (msg.data) and the current trace step number.
|
|
476
446
|
*/
|
|
477
447
|
async makeCallFrame(sender, receiver, data, receiverCode, codeHash, step) {
|
|
478
448
|
const contractInfo = codeHash === undefined
|
|
479
449
|
? codeHash
|
|
480
450
|
: this.artifactManager.getContractFromMDHash(codeHash);
|
|
481
|
-
const selector = data.slice(0, 4)
|
|
451
|
+
const selector = (0, utils_1.bytesToHex)(data.slice(0, 4));
|
|
482
452
|
let callee;
|
|
483
453
|
let args;
|
|
484
454
|
if (contractInfo && contractInfo.ast) {
|
|
@@ -487,7 +457,7 @@ class SolTxDebugger {
|
|
|
487
457
|
callee = this.findEntryPoint(contractInfo, selector);
|
|
488
458
|
if (callee !== undefined) {
|
|
489
459
|
try {
|
|
490
|
-
args = (0, abi_1.buildMsgDataViews)(callee, data, DataLocationKind.CallData, infer, abiVersion);
|
|
460
|
+
args = (0, abi_1.buildMsgDataViews)(callee, data, types_1.DataLocationKind.CallData, infer, abiVersion);
|
|
491
461
|
}
|
|
492
462
|
catch (e) {
|
|
493
463
|
args = undefined;
|
|
@@ -495,7 +465,7 @@ class SolTxDebugger {
|
|
|
495
465
|
}
|
|
496
466
|
}
|
|
497
467
|
return {
|
|
498
|
-
kind: FrameKind.Call,
|
|
468
|
+
kind: types_1.FrameKind.Call,
|
|
499
469
|
sender,
|
|
500
470
|
msgData: data,
|
|
501
471
|
receiver: receiver.toString(),
|
|
@@ -521,7 +491,7 @@ class SolTxDebugger {
|
|
|
521
491
|
if (!ctx.info) {
|
|
522
492
|
return [undefined, undefined];
|
|
523
493
|
}
|
|
524
|
-
const bytecodeInfo = ctx.kind === FrameKind.Creation ? ctx.info.bytecode : ctx.info.deployedBytecode;
|
|
494
|
+
const bytecodeInfo = ctx.kind === types_1.FrameKind.Creation ? ctx.info.bytecode : ctx.info.deployedBytecode;
|
|
525
495
|
const src = (0, artifact_manager_1.getOffsetSrc)(instrOffset, bytecodeInfo);
|
|
526
496
|
const astNode = ctx.info.artifact.srcMap.get(`${src.start}:${src.length}:${src.sourceIndex}`);
|
|
527
497
|
return [src, astNode];
|
|
@@ -542,7 +512,9 @@ class SolTxDebugger {
|
|
|
542
512
|
argDef.name,
|
|
543
513
|
infer.variableDeclarationToTypeNode(argDef)
|
|
544
514
|
])
|
|
545
|
-
: infer
|
|
515
|
+
: infer
|
|
516
|
+
.getterArgsAndReturn(callee)[0]
|
|
517
|
+
.map((typ, i) => [`ARG_${i}`, typ]);
|
|
546
518
|
}
|
|
547
519
|
catch (e) {
|
|
548
520
|
// `variableDeclarationToTypeNode` may fail when referencing structs/contracts that are defined
|
|
@@ -563,7 +535,7 @@ class SolTxDebugger {
|
|
|
563
535
|
{
|
|
564
536
|
type: typ,
|
|
565
537
|
loc: {
|
|
566
|
-
kind: DataLocationKind.Stack,
|
|
538
|
+
kind: types_1.DataLocationKind.Stack,
|
|
567
539
|
offsetFromTop
|
|
568
540
|
}
|
|
569
541
|
}
|