@nomicfoundation/edr 0.6.5 → 0.7.0
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/index.d.ts +21 -90
- package/index.js +4 -9
- package/package.json +8 -8
- package/src/logger.rs +34 -67
- package/src/provider.rs +68 -15
- package/src/trace/debug.rs +2 -262
- package/src/trace/exit.rs +3 -3
- package/src/trace/model.rs +5 -5
- package/src/trace/solidity_stack_trace.rs +220 -76
- package/src/trace.rs +11 -11
- package/src/trace/compiler.rs +0 -27
- package/src/trace/error_inferrer.rs +0 -2255
- package/src/trace/mapped_inlined_internal_functions_heuristics.rs +0 -180
- package/src/trace/message_trace.rs +0 -179
- package/src/trace/solidity_tracer.rs +0 -315
- package/src/trace/vm_trace_decoder.rs +0 -234
- package/src/trace/vm_tracer.rs +0 -71
package/src/trace/debug.rs
CHANGED
|
@@ -1,271 +1,11 @@
|
|
|
1
1
|
//! Port of `hardhat-network/stack-traces/debug.ts` from Hardhat.
|
|
2
2
|
|
|
3
|
-
use
|
|
4
|
-
use edr_evm::{hex, interpreter::OpCode};
|
|
5
|
-
use edr_solidity::build_model::JumpType;
|
|
6
|
-
use napi::{
|
|
7
|
-
bindgen_prelude::{Either24, Either3, Either4},
|
|
8
|
-
Either, Env,
|
|
9
|
-
};
|
|
3
|
+
use napi::bindgen_prelude::Either24;
|
|
10
4
|
use napi_derive::napi;
|
|
11
5
|
|
|
12
|
-
use super::{
|
|
13
|
-
message_trace::{CallMessageTrace, CreateMessageTrace, PrecompileMessageTrace},
|
|
14
|
-
solidity_stack_trace::{RevertErrorStackTraceEntry, SolidityStackTrace},
|
|
15
|
-
};
|
|
6
|
+
use super::solidity_stack_trace::{RevertErrorStackTraceEntry, SolidityStackTrace};
|
|
16
7
|
use crate::trace::return_data::ReturnData;
|
|
17
8
|
|
|
18
|
-
const MARGIN_SPACE: usize = 6;
|
|
19
|
-
|
|
20
|
-
#[napi]
|
|
21
|
-
fn print_message_trace(
|
|
22
|
-
trace: Either3<PrecompileMessageTrace, CallMessageTrace, CreateMessageTrace>,
|
|
23
|
-
depth: Option<u32>,
|
|
24
|
-
env: Env,
|
|
25
|
-
) -> napi::Result<()> {
|
|
26
|
-
let trace = match &trace {
|
|
27
|
-
Either3::A(precompile) => Either3::A(precompile),
|
|
28
|
-
Either3::B(call) => Either3::B(call),
|
|
29
|
-
Either3::C(create) => Either3::C(create),
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
let depth = depth.unwrap_or(0);
|
|
33
|
-
|
|
34
|
-
print_message_trace_inner(trace, depth, env)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
fn print_message_trace_inner(
|
|
38
|
-
trace: Either3<&PrecompileMessageTrace, &CallMessageTrace, &CreateMessageTrace>,
|
|
39
|
-
depth: u32,
|
|
40
|
-
env: Env,
|
|
41
|
-
) -> napi::Result<()> {
|
|
42
|
-
println!();
|
|
43
|
-
|
|
44
|
-
match trace {
|
|
45
|
-
Either3::A(precompile) => print_precompile_trace(precompile, depth),
|
|
46
|
-
Either3::B(call) => print_call_trace(call, depth, env)?,
|
|
47
|
-
Either3::C(create) => print_create_trace(create, depth, env)?,
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
println!();
|
|
51
|
-
|
|
52
|
-
Ok(())
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
fn print_precompile_trace(trace: &PrecompileMessageTrace, depth: u32) {
|
|
56
|
-
let margin = " ".repeat(depth as usize * MARGIN_SPACE);
|
|
57
|
-
|
|
58
|
-
let value = U256::from_limbs_slice(&trace.value.words);
|
|
59
|
-
|
|
60
|
-
println!("{margin}Precompile trace");
|
|
61
|
-
|
|
62
|
-
println!("{margin} precompile number: {}", trace.precompile);
|
|
63
|
-
println!("{margin} value: {value}");
|
|
64
|
-
println!(
|
|
65
|
-
"{margin} calldata: {}",
|
|
66
|
-
hex::encode_prefixed(&*trace.calldata)
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
if trace.exit.is_error() {
|
|
70
|
-
println!("{margin} error: {}", trace.exit.get_reason());
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
println!(
|
|
74
|
-
"{margin} returnData: {}",
|
|
75
|
-
hex::encode_prefixed(&*trace.return_data)
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
fn print_call_trace(trace: &CallMessageTrace, depth: u32, env: Env) -> napi::Result<()> {
|
|
80
|
-
let margin = " ".repeat(depth as usize * MARGIN_SPACE);
|
|
81
|
-
|
|
82
|
-
println!("{margin}Call trace");
|
|
83
|
-
|
|
84
|
-
if let Some(bytecode) = &trace.bytecode {
|
|
85
|
-
let contract = bytecode.contract.borrow();
|
|
86
|
-
let file = contract.location.file();
|
|
87
|
-
let file = file.borrow();
|
|
88
|
-
|
|
89
|
-
println!(
|
|
90
|
-
"{margin} calling contract: {}:{}",
|
|
91
|
-
file.source_name, contract.name
|
|
92
|
-
);
|
|
93
|
-
} else {
|
|
94
|
-
println!(
|
|
95
|
-
"{margin} unrecognized contract code: {:?}",
|
|
96
|
-
hex::encode_prefixed(&*trace.code)
|
|
97
|
-
);
|
|
98
|
-
println!(
|
|
99
|
-
"{margin} contract: {}",
|
|
100
|
-
hex::encode_prefixed(&*trace.address)
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
println!(
|
|
105
|
-
"{margin} value: {}",
|
|
106
|
-
U256::from_limbs_slice(&trace.value.words)
|
|
107
|
-
);
|
|
108
|
-
println!(
|
|
109
|
-
"{margin} calldata: {}",
|
|
110
|
-
hex::encode_prefixed(&*trace.calldata)
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
if trace.exit.is_error() {
|
|
114
|
-
println!("{margin} error: {}", trace.exit.get_reason());
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
println!(
|
|
118
|
-
"{margin} returnData: {}",
|
|
119
|
-
hex::encode_prefixed(&*trace.return_data)
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
trace_steps(Either::A(trace), depth, env)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
fn print_create_trace(trace: &CreateMessageTrace, depth: u32, env: Env) -> napi::Result<()> {
|
|
126
|
-
let margin = " ".repeat(depth as usize * MARGIN_SPACE);
|
|
127
|
-
|
|
128
|
-
println!("{margin}Create trace");
|
|
129
|
-
|
|
130
|
-
if let Some(bytecode) = &trace.bytecode {
|
|
131
|
-
let contract = bytecode.contract.borrow();
|
|
132
|
-
|
|
133
|
-
println!("{margin} deploying contract: {}", contract.name);
|
|
134
|
-
println!("{margin} code: {}", hex::encode_prefixed(&*trace.code));
|
|
135
|
-
} else {
|
|
136
|
-
println!(
|
|
137
|
-
"{margin} unrecognized deployment code: {}",
|
|
138
|
-
hex::encode_prefixed(&*trace.code)
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
println!(
|
|
143
|
-
"{margin} value: {}",
|
|
144
|
-
U256::from_limbs_slice(&trace.value.words)
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
if let Some(Either::A(deployed_contract)) = &trace.deployed_contract {
|
|
148
|
-
println!(
|
|
149
|
-
"{margin} contract address: {}",
|
|
150
|
-
hex::encode_prefixed(deployed_contract)
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if trace.exit.is_error() {
|
|
155
|
-
println!("{margin} error: {}", trace.exit.get_reason());
|
|
156
|
-
// The return data is the deployed-bytecode if there was no error, so we don't
|
|
157
|
-
// show it
|
|
158
|
-
println!(
|
|
159
|
-
"{margin} returnData: {}",
|
|
160
|
-
hex::encode_prefixed(&*trace.return_data)
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
trace_steps(Either::B(trace), depth, env)?;
|
|
165
|
-
|
|
166
|
-
Ok(())
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
fn trace_steps(
|
|
170
|
-
trace: Either<&CallMessageTrace, &CreateMessageTrace>,
|
|
171
|
-
depth: u32,
|
|
172
|
-
env: Env,
|
|
173
|
-
) -> napi::Result<()> {
|
|
174
|
-
let margin = " ".repeat(depth as usize * MARGIN_SPACE);
|
|
175
|
-
|
|
176
|
-
println!("{margin} steps:");
|
|
177
|
-
println!();
|
|
178
|
-
|
|
179
|
-
let (bytecode, steps) = match &trace {
|
|
180
|
-
Either::A(call) => (&call.bytecode, &call.steps),
|
|
181
|
-
Either::B(create) => (&create.bytecode, &create.steps),
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
for step in steps {
|
|
185
|
-
let step = match step {
|
|
186
|
-
Either4::A(step) => step,
|
|
187
|
-
trace @ (Either4::B(..) | Either4::C(..) | Either4::D(..)) => {
|
|
188
|
-
let trace = match trace {
|
|
189
|
-
Either4::A(..) => unreachable!(),
|
|
190
|
-
Either4::B(precompile) => Either3::A(precompile),
|
|
191
|
-
Either4::C(call) => Either3::B(call),
|
|
192
|
-
Either4::D(create) => Either3::C(create),
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
print_message_trace_inner(trace, depth + 1, env)?;
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
let pc = format!("{:>5}", format!("{:03}", step.pc));
|
|
201
|
-
|
|
202
|
-
if let Some(bytecode) = bytecode {
|
|
203
|
-
let inst = bytecode.get_instruction(step.pc)?;
|
|
204
|
-
|
|
205
|
-
let location = inst
|
|
206
|
-
.location
|
|
207
|
-
.as_ref()
|
|
208
|
-
.map(|inst_location| {
|
|
209
|
-
let inst_location = &inst_location;
|
|
210
|
-
let file = inst_location.file();
|
|
211
|
-
let file = file.borrow();
|
|
212
|
-
|
|
213
|
-
let mut location_str = file.source_name.clone();
|
|
214
|
-
|
|
215
|
-
if let Some(func) = inst_location.get_containing_function() {
|
|
216
|
-
let file = func.location.file();
|
|
217
|
-
let file = file.borrow();
|
|
218
|
-
|
|
219
|
-
let source_name = func
|
|
220
|
-
.contract_name
|
|
221
|
-
.as_ref()
|
|
222
|
-
.unwrap_or_else(|| &file.source_name);
|
|
223
|
-
|
|
224
|
-
location_str += &format!(":{source_name}:{}", func.name);
|
|
225
|
-
}
|
|
226
|
-
location_str +=
|
|
227
|
-
&format!(" - {}:{}", inst_location.offset, inst_location.length);
|
|
228
|
-
|
|
229
|
-
napi::Result::Ok(location_str)
|
|
230
|
-
})
|
|
231
|
-
.transpose()?
|
|
232
|
-
.unwrap_or_default();
|
|
233
|
-
|
|
234
|
-
if matches!(inst.opcode, OpCode::JUMP | OpCode::JUMPI) {
|
|
235
|
-
let jump = if inst.jump_type == JumpType::NotJump {
|
|
236
|
-
"".to_string()
|
|
237
|
-
} else {
|
|
238
|
-
format!("({})", inst.jump_type)
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
let entry = format!("{margin} {pc} {opcode} {jump}", opcode = inst.opcode);
|
|
242
|
-
|
|
243
|
-
println!("{entry:<50}{location}");
|
|
244
|
-
} else if inst.opcode.is_push() {
|
|
245
|
-
let entry = format!(
|
|
246
|
-
"{margin} {pc} {opcode} {push_data}",
|
|
247
|
-
opcode = inst.opcode,
|
|
248
|
-
push_data = inst
|
|
249
|
-
.push_data
|
|
250
|
-
.as_deref()
|
|
251
|
-
.map(hex::encode_prefixed)
|
|
252
|
-
.unwrap_or_default()
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
println!("{entry:<50}{location}");
|
|
256
|
-
} else {
|
|
257
|
-
let entry = format!("{margin} {pc} {opcode}", opcode = inst.opcode);
|
|
258
|
-
|
|
259
|
-
println!("{entry:<50}{location}");
|
|
260
|
-
}
|
|
261
|
-
} else {
|
|
262
|
-
println!("{margin} {pc}");
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
Ok(())
|
|
267
|
-
}
|
|
268
|
-
|
|
269
9
|
#[napi]
|
|
270
10
|
fn print_stack_trace(trace: SolidityStackTrace) -> napi::Result<()> {
|
|
271
11
|
let entry_values = trace
|
package/src/trace/exit.rs
CHANGED
|
@@ -51,9 +51,9 @@ impl fmt::Display for ExitCode {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
#[allow(clippy::fallible_impl_from)] // naively ported for now
|
|
54
|
-
impl From<edr_solidity::
|
|
55
|
-
fn from(code: edr_solidity::
|
|
56
|
-
use edr_solidity::
|
|
54
|
+
impl From<edr_solidity::exit_code::ExitCode> for ExitCode {
|
|
55
|
+
fn from(code: edr_solidity::exit_code::ExitCode) -> Self {
|
|
56
|
+
use edr_solidity::exit_code::ExitCode;
|
|
57
57
|
|
|
58
58
|
match code {
|
|
59
59
|
ExitCode::Success => Self::SUCCESS,
|
package/src/trace/model.rs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use std::rc::Rc;
|
|
2
2
|
|
|
3
|
-
use edr_solidity::build_model::
|
|
3
|
+
use edr_solidity::build_model::ContractMetadata;
|
|
4
4
|
use napi_derive::napi;
|
|
5
5
|
use serde::Serialize;
|
|
6
6
|
|
|
@@ -9,20 +9,20 @@ use serde::Serialize;
|
|
|
9
9
|
// NOTE: Needed, because we store the resolved `Bytecode` in the MessageTrace
|
|
10
10
|
// JS plain objects and those need a dedicated (class) type.
|
|
11
11
|
#[napi]
|
|
12
|
-
pub struct BytecodeWrapper(pub(crate) Rc<
|
|
12
|
+
pub struct BytecodeWrapper(pub(crate) Rc<ContractMetadata>);
|
|
13
13
|
|
|
14
14
|
impl BytecodeWrapper {
|
|
15
|
-
pub fn new(bytecode: Rc<
|
|
15
|
+
pub fn new(bytecode: Rc<ContractMetadata>) -> Self {
|
|
16
16
|
Self(bytecode)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
pub fn inner(&self) -> &Rc<
|
|
19
|
+
pub fn inner(&self) -> &Rc<ContractMetadata> {
|
|
20
20
|
&self.0
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
impl std::ops::Deref for BytecodeWrapper {
|
|
25
|
-
type Target =
|
|
25
|
+
type Target = ContractMetadata;
|
|
26
26
|
|
|
27
27
|
fn deref(&self) -> &Self::Target {
|
|
28
28
|
&self.0
|
|
@@ -8,6 +8,7 @@ use napi_derive::napi;
|
|
|
8
8
|
use serde::{Serialize, Serializer};
|
|
9
9
|
|
|
10
10
|
use super::model::ContractFunctionType;
|
|
11
|
+
use crate::{cast::TryCast, trace::u256_to_bigint};
|
|
11
12
|
|
|
12
13
|
#[napi]
|
|
13
14
|
#[repr(u8)]
|
|
@@ -77,6 +78,20 @@ pub struct SourceReference {
|
|
|
77
78
|
pub range: Vec<u32>,
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
impl From<edr_solidity::solidity_stack_trace::SourceReference> for SourceReference {
|
|
82
|
+
fn from(value: edr_solidity::solidity_stack_trace::SourceReference) -> Self {
|
|
83
|
+
let (range_start, range_end) = value.range;
|
|
84
|
+
Self {
|
|
85
|
+
source_name: value.source_name,
|
|
86
|
+
source_content: value.source_content,
|
|
87
|
+
contract: value.contract,
|
|
88
|
+
function: value.function,
|
|
89
|
+
line: value.line,
|
|
90
|
+
range: vec![range_start, range_end],
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
80
95
|
/// A [`StackTraceEntryType`] constant that is convertible to/from a
|
|
81
96
|
/// `napi_value`.
|
|
82
97
|
///
|
|
@@ -113,16 +128,6 @@ impl<const ENTRY_TYPE: u8> ToNapiValue for StackTraceEntryTypeConst<ENTRY_TYPE>
|
|
|
113
128
|
}
|
|
114
129
|
}
|
|
115
130
|
|
|
116
|
-
impl<const ENTRY_TYPE: u8> StackTraceEntryTypeConst<ENTRY_TYPE> {
|
|
117
|
-
#[allow(clippy::unused_self)] // less verbose than <value as ...>::as_value()
|
|
118
|
-
const fn as_value(&self) -> StackTraceEntryType {
|
|
119
|
-
match StackTraceEntryType::from_repr(ENTRY_TYPE) {
|
|
120
|
-
Some(val) => val,
|
|
121
|
-
None => panic!("Invalid StackTraceEntryType value"),
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
131
|
impl<const ENTRY_TYPE: u8> Serialize for StackTraceEntryTypeConst<ENTRY_TYPE> {
|
|
127
132
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
128
133
|
where
|
|
@@ -599,76 +604,215 @@ pub type SolidityStackTraceEntry = Either24<
|
|
|
599
604
|
ContractCallRunOutOfGasError,
|
|
600
605
|
>;
|
|
601
606
|
|
|
607
|
+
impl TryCast<SolidityStackTraceEntry> for edr_solidity::solidity_stack_trace::StackTraceEntry {
|
|
608
|
+
type Error = napi::Error;
|
|
609
|
+
|
|
610
|
+
fn try_cast(self) -> Result<SolidityStackTraceEntry, Self::Error> {
|
|
611
|
+
use edr_solidity::solidity_stack_trace::StackTraceEntry;
|
|
612
|
+
let result = match self {
|
|
613
|
+
StackTraceEntry::CallstackEntry {
|
|
614
|
+
source_reference,
|
|
615
|
+
function_type,
|
|
616
|
+
} => CallstackEntryStackTraceEntry {
|
|
617
|
+
type_: StackTraceEntryTypeConst,
|
|
618
|
+
source_reference: source_reference.into(),
|
|
619
|
+
function_type: function_type.into(),
|
|
620
|
+
}
|
|
621
|
+
.into(),
|
|
622
|
+
StackTraceEntry::UnrecognizedCreateCallstackEntry => {
|
|
623
|
+
UnrecognizedCreateCallstackEntryStackTraceEntry {
|
|
624
|
+
type_: StackTraceEntryTypeConst,
|
|
625
|
+
source_reference: None,
|
|
626
|
+
}
|
|
627
|
+
.into()
|
|
628
|
+
}
|
|
629
|
+
StackTraceEntry::UnrecognizedContractCallstackEntry { address } => {
|
|
630
|
+
UnrecognizedContractCallstackEntryStackTraceEntry {
|
|
631
|
+
type_: StackTraceEntryTypeConst,
|
|
632
|
+
address: Uint8Array::from(address.as_slice()),
|
|
633
|
+
source_reference: None,
|
|
634
|
+
}
|
|
635
|
+
.into()
|
|
636
|
+
}
|
|
637
|
+
StackTraceEntry::PrecompileError { precompile } => PrecompileErrorStackTraceEntry {
|
|
638
|
+
type_: StackTraceEntryTypeConst,
|
|
639
|
+
precompile,
|
|
640
|
+
source_reference: None,
|
|
641
|
+
}
|
|
642
|
+
.into(),
|
|
643
|
+
StackTraceEntry::RevertError {
|
|
644
|
+
return_data,
|
|
645
|
+
source_reference,
|
|
646
|
+
is_invalid_opcode_error,
|
|
647
|
+
} => RevertErrorStackTraceEntry {
|
|
648
|
+
type_: StackTraceEntryTypeConst,
|
|
649
|
+
return_data: return_data.into(),
|
|
650
|
+
source_reference: source_reference.into(),
|
|
651
|
+
is_invalid_opcode_error,
|
|
652
|
+
}
|
|
653
|
+
.into(),
|
|
654
|
+
StackTraceEntry::PanicError {
|
|
655
|
+
error_code,
|
|
656
|
+
source_reference,
|
|
657
|
+
} => PanicErrorStackTraceEntry {
|
|
658
|
+
type_: StackTraceEntryTypeConst,
|
|
659
|
+
error_code: u256_to_bigint(&error_code),
|
|
660
|
+
source_reference: source_reference.map(std::convert::Into::into),
|
|
661
|
+
}
|
|
662
|
+
.into(),
|
|
663
|
+
StackTraceEntry::CustomError {
|
|
664
|
+
message,
|
|
665
|
+
source_reference,
|
|
666
|
+
} => CustomErrorStackTraceEntry {
|
|
667
|
+
type_: StackTraceEntryTypeConst,
|
|
668
|
+
message,
|
|
669
|
+
source_reference: source_reference.into(),
|
|
670
|
+
}
|
|
671
|
+
.into(),
|
|
672
|
+
StackTraceEntry::FunctionNotPayableError {
|
|
673
|
+
value,
|
|
674
|
+
source_reference,
|
|
675
|
+
} => FunctionNotPayableErrorStackTraceEntry {
|
|
676
|
+
type_: StackTraceEntryTypeConst,
|
|
677
|
+
value: u256_to_bigint(&value),
|
|
678
|
+
source_reference: source_reference.into(),
|
|
679
|
+
}
|
|
680
|
+
.into(),
|
|
681
|
+
StackTraceEntry::InvalidParamsError { source_reference } => {
|
|
682
|
+
InvalidParamsErrorStackTraceEntry {
|
|
683
|
+
type_: StackTraceEntryTypeConst,
|
|
684
|
+
source_reference: source_reference.into(),
|
|
685
|
+
}
|
|
686
|
+
.into()
|
|
687
|
+
}
|
|
688
|
+
StackTraceEntry::FallbackNotPayableError {
|
|
689
|
+
value,
|
|
690
|
+
source_reference,
|
|
691
|
+
} => FallbackNotPayableErrorStackTraceEntry {
|
|
692
|
+
type_: StackTraceEntryTypeConst,
|
|
693
|
+
value: u256_to_bigint(&value),
|
|
694
|
+
source_reference: source_reference.into(),
|
|
695
|
+
}
|
|
696
|
+
.into(),
|
|
697
|
+
StackTraceEntry::FallbackNotPayableAndNoReceiveError {
|
|
698
|
+
value,
|
|
699
|
+
source_reference,
|
|
700
|
+
} => FallbackNotPayableAndNoReceiveErrorStackTraceEntry {
|
|
701
|
+
type_: StackTraceEntryTypeConst,
|
|
702
|
+
value: u256_to_bigint(&value),
|
|
703
|
+
source_reference: source_reference.into(),
|
|
704
|
+
}
|
|
705
|
+
.into(),
|
|
706
|
+
StackTraceEntry::UnrecognizedFunctionWithoutFallbackError { source_reference } => {
|
|
707
|
+
UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry {
|
|
708
|
+
type_: StackTraceEntryTypeConst,
|
|
709
|
+
source_reference: source_reference.into(),
|
|
710
|
+
}
|
|
711
|
+
.into()
|
|
712
|
+
}
|
|
713
|
+
StackTraceEntry::MissingFallbackOrReceiveError { source_reference } => {
|
|
714
|
+
MissingFallbackOrReceiveErrorStackTraceEntry {
|
|
715
|
+
type_: StackTraceEntryTypeConst,
|
|
716
|
+
source_reference: source_reference.into(),
|
|
717
|
+
}
|
|
718
|
+
.into()
|
|
719
|
+
}
|
|
720
|
+
StackTraceEntry::ReturndataSizeError { source_reference } => {
|
|
721
|
+
ReturndataSizeErrorStackTraceEntry {
|
|
722
|
+
type_: StackTraceEntryTypeConst,
|
|
723
|
+
source_reference: source_reference.into(),
|
|
724
|
+
}
|
|
725
|
+
.into()
|
|
726
|
+
}
|
|
727
|
+
StackTraceEntry::NoncontractAccountCalledError { source_reference } => {
|
|
728
|
+
NonContractAccountCalledErrorStackTraceEntry {
|
|
729
|
+
type_: StackTraceEntryTypeConst,
|
|
730
|
+
source_reference: source_reference.into(),
|
|
731
|
+
}
|
|
732
|
+
.into()
|
|
733
|
+
}
|
|
734
|
+
StackTraceEntry::CallFailedError { source_reference } => {
|
|
735
|
+
CallFailedErrorStackTraceEntry {
|
|
736
|
+
type_: StackTraceEntryTypeConst,
|
|
737
|
+
source_reference: source_reference.into(),
|
|
738
|
+
}
|
|
739
|
+
.into()
|
|
740
|
+
}
|
|
741
|
+
StackTraceEntry::DirectLibraryCallError { source_reference } => {
|
|
742
|
+
DirectLibraryCallErrorStackTraceEntry {
|
|
743
|
+
type_: StackTraceEntryTypeConst,
|
|
744
|
+
source_reference: source_reference.into(),
|
|
745
|
+
}
|
|
746
|
+
.into()
|
|
747
|
+
}
|
|
748
|
+
StackTraceEntry::UnrecognizedCreateError {
|
|
749
|
+
return_data,
|
|
750
|
+
is_invalid_opcode_error,
|
|
751
|
+
} => UnrecognizedCreateErrorStackTraceEntry {
|
|
752
|
+
type_: StackTraceEntryTypeConst,
|
|
753
|
+
return_data: return_data.into(),
|
|
754
|
+
is_invalid_opcode_error,
|
|
755
|
+
source_reference: None,
|
|
756
|
+
}
|
|
757
|
+
.into(),
|
|
758
|
+
StackTraceEntry::UnrecognizedContractError {
|
|
759
|
+
address,
|
|
760
|
+
return_data,
|
|
761
|
+
is_invalid_opcode_error,
|
|
762
|
+
} => UnrecognizedContractErrorStackTraceEntry {
|
|
763
|
+
type_: StackTraceEntryTypeConst,
|
|
764
|
+
address: Uint8Array::from(address.as_slice()),
|
|
765
|
+
return_data: return_data.into(),
|
|
766
|
+
is_invalid_opcode_error,
|
|
767
|
+
source_reference: None,
|
|
768
|
+
}
|
|
769
|
+
.into(),
|
|
770
|
+
StackTraceEntry::OtherExecutionError { source_reference } => {
|
|
771
|
+
OtherExecutionErrorStackTraceEntry {
|
|
772
|
+
type_: StackTraceEntryTypeConst,
|
|
773
|
+
source_reference: source_reference.map(std::convert::Into::into),
|
|
774
|
+
}
|
|
775
|
+
.into()
|
|
776
|
+
}
|
|
777
|
+
StackTraceEntry::UnmappedSolc0_6_3RevertError { source_reference } => {
|
|
778
|
+
UnmappedSolc063RevertErrorStackTraceEntry {
|
|
779
|
+
type_: StackTraceEntryTypeConst,
|
|
780
|
+
source_reference: source_reference.map(std::convert::Into::into),
|
|
781
|
+
}
|
|
782
|
+
.into()
|
|
783
|
+
}
|
|
784
|
+
StackTraceEntry::ContractTooLargeError { source_reference } => {
|
|
785
|
+
ContractTooLargeErrorStackTraceEntry {
|
|
786
|
+
type_: StackTraceEntryTypeConst,
|
|
787
|
+
source_reference: source_reference.map(std::convert::Into::into),
|
|
788
|
+
}
|
|
789
|
+
.into()
|
|
790
|
+
}
|
|
791
|
+
StackTraceEntry::InternalFunctionCallstackEntry {
|
|
792
|
+
pc,
|
|
793
|
+
source_reference,
|
|
794
|
+
} => InternalFunctionCallStackEntry {
|
|
795
|
+
type_: StackTraceEntryTypeConst,
|
|
796
|
+
pc,
|
|
797
|
+
source_reference: source_reference.into(),
|
|
798
|
+
}
|
|
799
|
+
.into(),
|
|
800
|
+
StackTraceEntry::ContractCallRunOutOfGasError { source_reference } => {
|
|
801
|
+
ContractCallRunOutOfGasError {
|
|
802
|
+
type_: StackTraceEntryTypeConst,
|
|
803
|
+
source_reference: source_reference.map(std::convert::Into::into),
|
|
804
|
+
}
|
|
805
|
+
.into()
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
Ok(result)
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
602
812
|
#[allow(dead_code)]
|
|
603
813
|
// Same as above, but for the `SolidityStackTrace` type.
|
|
604
814
|
pub type SolidityStackTrace = Vec<SolidityStackTraceEntry>;
|
|
605
815
|
|
|
606
|
-
pub trait SolidityStackTraceEntryExt {
|
|
607
|
-
fn type_(&self) -> StackTraceEntryType;
|
|
608
|
-
fn source_reference(&self) -> Option<&SourceReference>;
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
impl SolidityStackTraceEntryExt for SolidityStackTraceEntry {
|
|
612
|
-
fn type_(&self) -> StackTraceEntryType {
|
|
613
|
-
match self {
|
|
614
|
-
Either24::A(entry) => entry.type_.as_value(),
|
|
615
|
-
Either24::B(entry) => entry.type_.as_value(),
|
|
616
|
-
Either24::C(entry) => entry.type_.as_value(),
|
|
617
|
-
Either24::D(entry) => entry.type_.as_value(),
|
|
618
|
-
Either24::E(entry) => entry.type_.as_value(),
|
|
619
|
-
Either24::F(entry) => entry.type_.as_value(),
|
|
620
|
-
Either24::G(entry) => entry.type_.as_value(),
|
|
621
|
-
Either24::H(entry) => entry.type_.as_value(),
|
|
622
|
-
Either24::I(entry) => entry.type_.as_value(),
|
|
623
|
-
Either24::J(entry) => entry.type_.as_value(),
|
|
624
|
-
Either24::K(entry) => entry.type_.as_value(),
|
|
625
|
-
Either24::L(entry) => entry.type_.as_value(),
|
|
626
|
-
Either24::M(entry) => entry.type_.as_value(),
|
|
627
|
-
Either24::N(entry) => entry.type_.as_value(),
|
|
628
|
-
Either24::O(entry) => entry.type_.as_value(),
|
|
629
|
-
Either24::P(entry) => entry.type_.as_value(),
|
|
630
|
-
Either24::Q(entry) => entry.type_.as_value(),
|
|
631
|
-
Either24::R(entry) => entry.type_.as_value(),
|
|
632
|
-
Either24::S(entry) => entry.type_.as_value(),
|
|
633
|
-
Either24::T(entry) => entry.type_.as_value(),
|
|
634
|
-
Either24::U(entry) => entry.type_.as_value(),
|
|
635
|
-
Either24::V(entry) => entry.type_.as_value(),
|
|
636
|
-
Either24::W(entry) => entry.type_.as_value(),
|
|
637
|
-
Either24::X(entry) => entry.type_.as_value(),
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
#[allow(clippy::unnecessary_lazy_evaluations)] // guards against potential variant reordering
|
|
642
|
-
fn source_reference(&self) -> Option<&SourceReference> {
|
|
643
|
-
match self {
|
|
644
|
-
Either24::A(entry) => Some(&entry.source_reference),
|
|
645
|
-
Either24::B(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
646
|
-
Either24::C(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
647
|
-
Either24::D(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
648
|
-
Either24::E(entry) => Some(&entry.source_reference),
|
|
649
|
-
Either24::F(entry) => entry.source_reference.as_ref(),
|
|
650
|
-
Either24::G(entry) => Some(&entry.source_reference),
|
|
651
|
-
Either24::H(entry) => Some(&entry.source_reference),
|
|
652
|
-
Either24::I(entry) => Some(&entry.source_reference),
|
|
653
|
-
Either24::J(entry) => Some(&entry.source_reference),
|
|
654
|
-
Either24::K(entry) => Some(&entry.source_reference),
|
|
655
|
-
Either24::L(entry) => Some(&entry.source_reference),
|
|
656
|
-
Either24::M(entry) => Some(&entry.source_reference),
|
|
657
|
-
Either24::N(entry) => Some(&entry.source_reference),
|
|
658
|
-
Either24::O(entry) => Some(&entry.source_reference),
|
|
659
|
-
Either24::P(entry) => Some(&entry.source_reference),
|
|
660
|
-
Either24::Q(entry) => Some(&entry.source_reference),
|
|
661
|
-
Either24::R(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
662
|
-
Either24::S(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
663
|
-
Either24::T(entry) => entry.source_reference.as_ref(),
|
|
664
|
-
Either24::U(entry) => entry.source_reference.as_ref(),
|
|
665
|
-
Either24::V(entry) => entry.source_reference.as_ref(),
|
|
666
|
-
Either24::W(entry) => Some(&entry.source_reference),
|
|
667
|
-
Either24::X(entry) => entry.source_reference.as_ref(),
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
816
|
const _: () = {
|
|
673
817
|
const fn assert_to_from_napi_value<T: FromNapiValue + ToNapiValue>() {}
|
|
674
818
|
assert_to_from_napi_value::<SolidityStackTraceEntry>();
|
package/src/trace.rs
CHANGED
|
@@ -16,20 +16,13 @@ use napi_derive::napi;
|
|
|
16
16
|
|
|
17
17
|
use crate::result::ExecutionResult;
|
|
18
18
|
|
|
19
|
-
mod compiler;
|
|
20
19
|
mod library_utils;
|
|
21
|
-
mod model;
|
|
22
20
|
|
|
23
21
|
mod debug;
|
|
24
|
-
mod error_inferrer;
|
|
25
22
|
mod exit;
|
|
26
|
-
mod
|
|
27
|
-
mod message_trace;
|
|
23
|
+
mod model;
|
|
28
24
|
mod return_data;
|
|
29
|
-
mod solidity_stack_trace;
|
|
30
|
-
mod solidity_tracer;
|
|
31
|
-
mod vm_trace_decoder;
|
|
32
|
-
mod vm_tracer;
|
|
25
|
+
pub mod solidity_stack_trace;
|
|
33
26
|
|
|
34
27
|
#[napi(object)]
|
|
35
28
|
pub struct TracingMessage {
|
|
@@ -149,7 +142,7 @@ impl TracingStep {
|
|
|
149
142
|
|
|
150
143
|
Self {
|
|
151
144
|
depth: step.depth as u8,
|
|
152
|
-
pc: BigInt::from(step.pc),
|
|
145
|
+
pc: BigInt::from(u64::from(step.pc)),
|
|
153
146
|
opcode: OpCode::name_by_op(step.opcode).to_string(),
|
|
154
147
|
stack,
|
|
155
148
|
memory,
|
|
@@ -157,7 +150,7 @@ impl TracingStep {
|
|
|
157
150
|
}
|
|
158
151
|
}
|
|
159
152
|
|
|
160
|
-
fn u256_to_bigint(v: &edr_evm::U256) -> BigInt {
|
|
153
|
+
pub(crate) fn u256_to_bigint(v: &edr_evm::U256) -> BigInt {
|
|
161
154
|
BigInt {
|
|
162
155
|
sign_bit: false,
|
|
163
156
|
words: v.into_limbs().to_vec(),
|
|
@@ -203,3 +196,10 @@ impl RawTrace {
|
|
|
203
196
|
.collect::<napi::Result<_>>()
|
|
204
197
|
}
|
|
205
198
|
}
|
|
199
|
+
|
|
200
|
+
#[napi]
|
|
201
|
+
/// Returns the latest version of solc that EDR officially
|
|
202
|
+
/// supports and is tested against.
|
|
203
|
+
pub fn get_latest_supported_solc_version() -> String {
|
|
204
|
+
"0.8.28".to_string()
|
|
205
|
+
}
|