@nomicfoundation/edr 0.12.0-next.9 → 0.12.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.
Files changed (52) hide show
  1. package/coverage.sol +38 -0
  2. package/dist/src/ts/coverage.d.ts +6 -0
  3. package/dist/src/ts/coverage.d.ts.map +1 -0
  4. package/dist/src/ts/coverage.js +51 -0
  5. package/dist/src/ts/coverage.js.map +1 -0
  6. package/index.d.ts +286 -27
  7. package/index.js +6 -2
  8. package/package.json +21 -19
  9. package/src/account.rs +0 -124
  10. package/src/block.rs +0 -28
  11. package/src/call_override.rs +0 -116
  12. package/src/cast.rs +0 -165
  13. package/src/chains/generic.rs +0 -58
  14. package/src/chains/l1.rs +0 -268
  15. package/src/chains/op.rs +0 -424
  16. package/src/chains.rs +0 -7
  17. package/src/config.rs +0 -700
  18. package/src/context.rs +0 -447
  19. package/src/contract_decoder.rs +0 -57
  20. package/src/debug_trace.rs +0 -40
  21. package/src/gas_report.rs +0 -92
  22. package/src/instrument.rs +0 -109
  23. package/src/lib.rs +0 -50
  24. package/src/log.rs +0 -28
  25. package/src/logger.rs +0 -120
  26. package/src/mock/time.rs +0 -134
  27. package/src/mock.rs +0 -71
  28. package/src/precompile.rs +0 -50
  29. package/src/provider/factory.rs +0 -22
  30. package/src/provider/response.rs +0 -73
  31. package/src/provider.rs +0 -162
  32. package/src/result.rs +0 -212
  33. package/src/scenarios.rs +0 -53
  34. package/src/serde.rs +0 -57
  35. package/src/solidity_tests/artifact.rs +0 -184
  36. package/src/solidity_tests/config.rs +0 -793
  37. package/src/solidity_tests/factory.rs +0 -22
  38. package/src/solidity_tests/l1.rs +0 -68
  39. package/src/solidity_tests/op.rs +0 -69
  40. package/src/solidity_tests/runner.rs +0 -51
  41. package/src/solidity_tests/test_results.rs +0 -736
  42. package/src/solidity_tests.rs +0 -56
  43. package/src/subscription.rs +0 -32
  44. package/src/trace/debug.rs +0 -61
  45. package/src/trace/exit.rs +0 -89
  46. package/src/trace/library_utils.rs +0 -11
  47. package/src/trace/model.rs +0 -59
  48. package/src/trace/return_data.rs +0 -96
  49. package/src/trace/solidity_stack_trace.rs +0 -869
  50. package/src/trace.rs +0 -199
  51. package/src/ts/solidity_tests.ts +0 -46
  52. package/src/withdrawal.rs +0 -49
@@ -1,736 +0,0 @@
1
- use std::{
2
- borrow::Cow,
3
- convert::Infallible,
4
- fmt::{Debug, Formatter},
5
- sync::Arc,
6
- };
7
-
8
- use edr_solidity_tests::{
9
- constants::CHEATCODE_ADDRESS,
10
- executors::stack_trace::StackTraceResult,
11
- traces::{self, CallTraceArena, SparsedTraceArena},
12
- };
13
- use napi::{
14
- bindgen_prelude::{BigInt, Either3, Either4, Uint8Array},
15
- Either,
16
- };
17
- use napi_derive::napi;
18
-
19
- use crate::{
20
- cast::TryCast,
21
- gas_report::GasReport,
22
- solidity_tests::{artifact::ArtifactId, config::IncludeTraces},
23
- trace::{solidity_stack_trace::SolidityStackTraceEntry, u256_to_bigint},
24
- };
25
-
26
- /// A grouping of value snapshot entries for a test.
27
- #[napi(object)]
28
- #[derive(Clone, Debug)]
29
- pub struct ValueSnapshotGroup {
30
- /// The group name.
31
- pub name: String,
32
- /// The entries in the group.
33
- pub entries: Vec<ValueSnapshotEntry>,
34
- }
35
-
36
- /// An entry in a value snapshot group.
37
- #[napi(object)]
38
- #[derive(Clone, Debug)]
39
- pub struct ValueSnapshotEntry {
40
- /// The name of the entry.
41
- pub name: String,
42
- /// The value of the entry.
43
- pub value: String,
44
- }
45
-
46
- /// See [`edr_solidity_tests::result::SuiteResult`]
47
- #[napi]
48
- #[derive(Clone, Debug)]
49
- pub struct SuiteResult {
50
- /// The artifact id can be used to match input to result in the progress
51
- /// callback
52
- #[napi(readonly)]
53
- pub id: ArtifactId,
54
- /// See [`edr_solidity_tests::result::SuiteResult::duration`]
55
- #[napi(readonly)]
56
- pub duration_ns: BigInt,
57
- /// See [`edr_solidity_tests::result::SuiteResult::test_results`]
58
- #[napi(readonly)]
59
- pub test_results: Vec<TestResult>,
60
- /// See [`edr_solidity_tests::result::SuiteResult::warnings`]
61
- #[napi(readonly)]
62
- pub warnings: Vec<String>,
63
- }
64
-
65
- impl SuiteResult {
66
- pub fn new(
67
- id: edr_solidity::artifacts::ArtifactId,
68
- suite_result: edr_solidity_tests::result::SuiteResult<String>,
69
- include_traces: IncludeTraces,
70
- ) -> Self {
71
- Self {
72
- id: id.into(),
73
- duration_ns: BigInt::from(suite_result.duration.as_nanos()),
74
- test_results: suite_result
75
- .test_results
76
- .into_iter()
77
- .map(|(name, test_result)| TestResult::new(name, test_result, include_traces))
78
- .collect(),
79
- warnings: suite_result.warnings,
80
- }
81
- }
82
- }
83
-
84
- /// See [`edr_solidity_tests::result::TestResult`]
85
- #[napi]
86
- #[derive(Clone, Debug)]
87
- pub struct TestResult {
88
- /// The name of the test.
89
- #[napi(readonly)]
90
- pub name: String,
91
- /// See [`edr_solidity_tests::result::TestResult::status`]
92
- #[napi(readonly)]
93
- pub status: TestStatus,
94
- /// See [`edr_solidity_tests::result::TestResult::reason`]
95
- #[napi(readonly)]
96
- pub reason: Option<String>,
97
- /// See [`edr_solidity_tests::result::TestResult::counterexample`]
98
- #[napi(readonly)]
99
- pub counterexample: Option<Either<BaseCounterExample, CounterExampleSequence>>,
100
- /// See [`edr_solidity_tests::result::TestResult::decoded_logs`]
101
- #[napi(readonly)]
102
- pub decoded_logs: Vec<String>,
103
- /// See [`edr_solidity_tests::result::TestResult::kind`]
104
- #[napi(readonly)]
105
- pub kind: Either3<StandardTestKind, FuzzTestKind, InvariantTestKind>,
106
- /// See [`edr_solidity_tests::result::TestResult::duration`]
107
- #[napi(readonly)]
108
- pub duration_ns: BigInt,
109
- /// Groups of value snapshot entries (incl. gas).
110
- ///
111
- /// Only present if the test runner collected scoped snapshots. Currently,
112
- /// this is always the case.
113
- #[napi(readonly)]
114
- pub value_snapshot_groups: Option<Vec<ValueSnapshotGroup>>,
115
-
116
- stack_trace_result: Option<Arc<StackTraceResult<String>>>,
117
- call_trace_arenas: Vec<(traces::TraceKind, SparsedTraceArena)>,
118
- }
119
-
120
- /// The stack trace result
121
- #[napi(object)]
122
- pub struct StackTrace {
123
- /// Enum tag for JS.
124
- #[napi(ts_type = "\"StackTrace\"")]
125
- pub kind: &'static str,
126
- /// The stack trace entries
127
- pub entries: Vec<SolidityStackTraceEntry>,
128
- }
129
-
130
- /// We couldn't generate stack traces, because an unexpected error occurred.
131
- #[napi(object)]
132
- pub struct UnexpectedError {
133
- /// Enum tag for JS.
134
- #[napi(ts_type = "\"UnexpectedError\"")]
135
- pub kind: &'static str,
136
- /// The error message from the unexpected error.
137
- pub error_message: String,
138
- }
139
-
140
- /// We couldn't generate stack traces, because the stack trace generation
141
- /// heuristics failed due to an unknown reason.
142
- #[napi(object)]
143
- pub struct HeuristicFailed {
144
- /// Enum tag for JS.
145
- #[napi(ts_type = "\"HeuristicFailed\"")]
146
- pub kind: &'static str,
147
- }
148
-
149
- /// We couldn't generate stack traces, because the test execution is unsafe to
150
- /// replay due to indeterminism. This can be caused by either specifying a fork
151
- /// url without a fork block number in the test runner config or using impure
152
- /// cheatcodes.
153
- #[napi(object)]
154
- pub struct UnsafeToReplay {
155
- /// Enum tag for JS.
156
- #[napi(ts_type = "\"UnsafeToReplay\"")]
157
- pub kind: &'static str,
158
- /// Indeterminism due to specifying a fork url without a fork block number
159
- /// in the test runner config.
160
- pub global_fork_latest: bool,
161
- /// The list of executed impure cheatcode signatures. We collect function
162
- /// signatures instead of function names as whether a cheatcode is impure
163
- /// can depend on the arguments it takes (e.g. `createFork` without a second
164
- /// argument means implicitly fork from “latest”). Example signature:
165
- /// `function createSelectFork(string calldata urlOrAlias) external returns
166
- /// (uint256 forkId);`.
167
- pub impure_cheatcodes: Vec<String>,
168
- }
169
-
170
- #[napi]
171
- impl TestResult {
172
- /// Compute the error stack trace.
173
- /// The result is either the stack trace or the reason why we couldn't
174
- /// generate the stack trace.
175
- /// Returns null if the test status is succeeded or skipped.
176
- /// Cannot throw.
177
- #[napi]
178
- pub fn stack_trace(
179
- &self,
180
- ) -> Option<Either4<StackTrace, UnexpectedError, HeuristicFailed, UnsafeToReplay>> {
181
- self.stack_trace_result.as_ref().map(|stack_trace_result| {
182
- match stack_trace_result.as_ref() {
183
- StackTraceResult::Success(stack_trace) => Either4::A(StackTrace {
184
- kind: "StackTrace",
185
- entries: stack_trace
186
- .iter()
187
- .cloned()
188
- .map(TryCast::try_cast)
189
- .collect::<Result<Vec<_>, Infallible>>()
190
- .expect("infallible"),
191
- }),
192
- StackTraceResult::Error(error) => Either4::B(UnexpectedError {
193
- kind: "UnexpectedError",
194
- error_message: error.to_string(),
195
- }),
196
- StackTraceResult::HeuristicFailed => Either4::C(HeuristicFailed {
197
- kind: "HeuristicFailed",
198
- }),
199
- StackTraceResult::UnsafeToReplay {
200
- global_fork_latest,
201
- impure_cheatcodes,
202
- } => Either4::D(UnsafeToReplay {
203
- kind: "UnsafeToReplay",
204
- global_fork_latest: *global_fork_latest,
205
- // napi-rs would clone `&'static str` under the hood anyway, so no performance
206
- // hit from `Cow::into_owned`.
207
- impure_cheatcodes: impure_cheatcodes
208
- .iter()
209
- .cloned()
210
- .map(Cow::into_owned)
211
- .collect(),
212
- }),
213
- }
214
- })
215
- }
216
-
217
- /// Constructs the execution traces for the test. Returns an empty array if
218
- /// traces for this test were not requested according to
219
- /// [`crate::solidity_tests::config::SolidityTestRunnerConfigArgs::include_traces`]. Otherwise, returns
220
- /// an array of the root calls of the trace, which always includes the test
221
- /// call itself and may also include the setup call if there is one
222
- /// (identified by the function name `setUp`).
223
- #[napi]
224
- pub fn call_traces(&self) -> Vec<CallTrace> {
225
- self.call_trace_arenas
226
- .iter()
227
- .filter(|(k, _)| *k != traces::TraceKind::Deployment)
228
- .map(|(_, a)| CallTrace::from_arena_node(&a.resolve_arena(), 0))
229
- .collect()
230
- }
231
- }
232
-
233
- impl TestResult {
234
- fn new(
235
- name: String,
236
- test_result: edr_solidity_tests::result::TestResult<String>,
237
- include_traces: IncludeTraces,
238
- ) -> Self {
239
- let include_trace = include_traces == IncludeTraces::All
240
- || (include_traces == IncludeTraces::Failing && test_result.status.is_failure());
241
-
242
- Self {
243
- name,
244
- status: test_result.status.into(),
245
- reason: test_result.reason,
246
- counterexample: test_result
247
- .counterexample
248
- .map(|counterexample| match counterexample {
249
- edr_solidity_tests::fuzz::CounterExample::Single(counterexample) => {
250
- Either::A(BaseCounterExample::from(counterexample))
251
- }
252
- edr_solidity_tests::fuzz::CounterExample::Sequence(
253
- original_size,
254
- counterexamples,
255
- ) => Either::B(CounterExampleSequence {
256
- original_sequence_size: u64::try_from(original_size)
257
- .expect("usize fits into u64")
258
- .into(),
259
- sequence: counterexamples
260
- .into_iter()
261
- .map(BaseCounterExample::from)
262
- .collect(),
263
- }),
264
- }),
265
- decoded_logs: test_result.decoded_logs,
266
- kind: match test_result.kind {
267
- edr_solidity_tests::result::TestKind::Standard(gas_consumed) => {
268
- Either3::A(StandardTestKind {
269
- consumed_gas: BigInt::from(gas_consumed),
270
- })
271
- }
272
- edr_solidity_tests::result::TestKind::Fuzz {
273
- runs,
274
- mean_gas,
275
- median_gas,
276
- } => Either3::B(FuzzTestKind {
277
- // usize as u64 is always safe
278
- runs: BigInt::from(runs as u64),
279
- mean_gas: BigInt::from(mean_gas),
280
- median_gas: BigInt::from(median_gas),
281
- }),
282
- edr_solidity_tests::result::TestKind::Invariant {
283
- runs,
284
- calls,
285
- reverts,
286
- } => Either3::C(InvariantTestKind {
287
- // usize as u64 is always safe
288
- runs: BigInt::from(runs as u64),
289
- calls: BigInt::from(calls as u64),
290
- reverts: BigInt::from(reverts as u64),
291
- }),
292
- },
293
- duration_ns: BigInt::from(test_result.duration.as_nanos()),
294
- value_snapshot_groups: Some(
295
- test_result
296
- .value_snapshots
297
- .into_iter()
298
- .map(|(group_name, entries)| ValueSnapshotGroup {
299
- name: group_name,
300
- entries: entries
301
- .into_iter()
302
- .map(|(name, value)| ValueSnapshotEntry { name, value })
303
- .collect(),
304
- })
305
- .collect(),
306
- ),
307
- stack_trace_result: test_result.stack_trace_result.map(Arc::new),
308
- call_trace_arenas: if include_trace {
309
- test_result.traces
310
- } else {
311
- vec![]
312
- },
313
- }
314
- }
315
- }
316
-
317
- #[derive(Debug)]
318
- #[napi(string_enum)]
319
- #[doc = "The result of a test execution."]
320
- pub enum TestStatus {
321
- #[doc = "Test success"]
322
- Success,
323
- #[doc = "Test failure"]
324
- Failure,
325
- #[doc = "Test skipped"]
326
- Skipped,
327
- }
328
-
329
- impl From<edr_solidity_tests::result::TestStatus> for TestStatus {
330
- fn from(value: edr_solidity_tests::result::TestStatus) -> Self {
331
- match value {
332
- edr_solidity_tests::result::TestStatus::Success => Self::Success,
333
- edr_solidity_tests::result::TestStatus::Failure => Self::Failure,
334
- edr_solidity_tests::result::TestStatus::Skipped => Self::Skipped,
335
- }
336
- }
337
- }
338
-
339
- /// See [`edr_solidity_tests::result::TestKind::Standard`]
340
- #[napi(object)]
341
- #[derive(Debug, Clone)]
342
- pub struct StandardTestKind {
343
- /// The gas consumed by the test.
344
- #[napi(readonly)]
345
- pub consumed_gas: BigInt,
346
- }
347
-
348
- /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
349
- #[napi(object)]
350
- #[derive(Debug, Clone)]
351
- pub struct FuzzTestKind {
352
- /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
353
- #[napi(readonly)]
354
- pub runs: BigInt,
355
- /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
356
- #[napi(readonly)]
357
- pub mean_gas: BigInt,
358
- /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
359
- #[napi(readonly)]
360
- pub median_gas: BigInt,
361
- }
362
-
363
- /// See [`edr_solidity_tests::fuzz::FuzzCase`]
364
- #[napi(object)]
365
- #[derive(Clone)]
366
- pub struct FuzzCase {
367
- /// The calldata used for this fuzz test
368
- #[napi(readonly)]
369
- pub calldata: Uint8Array,
370
- /// Consumed gas
371
- #[napi(readonly)]
372
- pub gas: BigInt,
373
- /// The initial gas stipend for the transaction
374
- #[napi(readonly)]
375
- pub stipend: BigInt,
376
- }
377
-
378
- impl Debug for FuzzCase {
379
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
380
- f.debug_struct("FuzzCase")
381
- .field("gas", &self.gas)
382
- .field("stipend", &self.stipend)
383
- .finish()
384
- }
385
- }
386
-
387
- /// See [`edr_solidity_tests::result::TestKind::Invariant`]
388
- #[napi(object)]
389
- #[derive(Debug, Clone)]
390
- pub struct InvariantTestKind {
391
- /// See [`edr_solidity_tests::result::TestKind::Invariant`]
392
- #[napi(readonly)]
393
- pub runs: BigInt,
394
- /// See [`edr_solidity_tests::result::TestKind::Invariant`]
395
- #[napi(readonly)]
396
- pub calls: BigInt,
397
- /// See [`edr_solidity_tests::result::TestKind::Invariant`]
398
- #[napi(readonly)]
399
- pub reverts: BigInt,
400
- }
401
-
402
- /// Original sequence size and sequence of calls used as a counter example
403
- /// for invariant tests.
404
- #[napi(object)]
405
- #[derive(Clone, Debug)]
406
- pub struct CounterExampleSequence {
407
- /// The original sequence size before shrinking.
408
- pub original_sequence_size: BigInt,
409
- /// The shrunk counterexample sequence.
410
- pub sequence: Vec<BaseCounterExample>,
411
- }
412
-
413
- /// See [`edr_solidity_tests::fuzz::BaseCounterExample`]
414
- #[napi(object)]
415
- #[derive(Clone)]
416
- pub struct BaseCounterExample {
417
- /// See [`edr_solidity_tests::fuzz::BaseCounterExample::sender`]
418
- #[napi(readonly)]
419
- pub sender: Option<Uint8Array>,
420
- /// See [`edr_solidity_tests::fuzz::BaseCounterExample::addr`]
421
- #[napi(readonly)]
422
- pub address: Option<Uint8Array>,
423
- /// See [`edr_solidity_tests::fuzz::BaseCounterExample::calldata`]
424
- #[napi(readonly)]
425
- pub calldata: Uint8Array,
426
- /// See [`edr_solidity_tests::fuzz::BaseCounterExample::contract_name`]
427
- #[napi(readonly)]
428
- pub contract_name: Option<String>,
429
- /// See [`edr_solidity_tests::fuzz::BaseCounterExample::signature`]
430
- #[napi(readonly)]
431
- pub signature: Option<String>,
432
- /// See [`edr_solidity_tests::fuzz::BaseCounterExample::args`]
433
- #[napi(readonly)]
434
- pub args: Option<String>,
435
- }
436
-
437
- impl Debug for BaseCounterExample {
438
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
439
- f.debug_struct("BaseCounterExample")
440
- .field("contract_name", &self.contract_name)
441
- .field("signature", &self.signature)
442
- .field("args", &self.args)
443
- .finish()
444
- }
445
- }
446
-
447
- impl From<edr_solidity_tests::fuzz::BaseCounterExample> for BaseCounterExample {
448
- fn from(value: edr_solidity_tests::fuzz::BaseCounterExample) -> Self {
449
- Self {
450
- sender: value.sender.map(Uint8Array::with_data_copied),
451
- address: value.addr.map(Uint8Array::with_data_copied),
452
- calldata: Uint8Array::with_data_copied(value.calldata),
453
- contract_name: value.contract_name,
454
- signature: value.signature,
455
- args: value.args,
456
- }
457
- }
458
- }
459
-
460
- /// Object representing a call in an execution trace, including contract
461
- /// creation.
462
- #[napi(object)]
463
- pub struct CallTrace {
464
- /// The kind of call or contract creation this represents.
465
- pub kind: CallKind,
466
- /// Whether the call succeeded or reverted.
467
- pub success: bool,
468
- /// Whether the call is a cheatcode.
469
- pub is_cheatcode: bool,
470
- /// The amount of gas that was consumed.
471
- pub gas_used: BigInt,
472
- /// The amount of native token that was included with the call.
473
- pub value: BigInt,
474
- /// The target address of the call.
475
- pub address: String,
476
- /// The name of the contract that is the target of the call, if known.
477
- pub contract: Option<String>,
478
- /// The input (calldata) to the call. If it encodes a known function call,
479
- /// it will be decoded into the function name and a list of arguments.
480
- /// For example, `{ name: "ownerOf", arguments: ["1"] }`. Note that the
481
- /// function name may also be any of the special `fallback` and `receive`
482
- /// functions. Otherwise, it will be provided as a raw byte array.
483
- pub inputs: Either<DecodedTraceParameters, Uint8Array>,
484
- /// The output of the call. This will be a decoded human-readable
485
- /// representation of the value if the function is known, otherwise a
486
- /// raw byte array.
487
- pub outputs: Either<String, Uint8Array>,
488
- /// Interleaved subcalls and event logs. Use `kind` to check if each member
489
- /// of the array is a call or log trace.
490
- pub children: Vec<Either<CallTrace, LogTrace>>,
491
- }
492
-
493
- /// Object representing an event log in an execution trace.
494
- #[napi(object)]
495
- pub struct LogTrace {
496
- /// A constant to help discriminate the union `CallTrace | LogTrace`.
497
- pub kind: LogKind,
498
- /// If the log is a known event (based on its first topic), it will be
499
- /// decoded into the event name and list of named parameters. For
500
- /// example, `{ name: "Log", arguments: ["value: 1"] }`. Otherwise, it
501
- /// will be provided as an array where all but the last element are the
502
- /// log topics, and the last element is the log data.
503
- pub parameters: Either<DecodedTraceParameters, Vec<Uint8Array>>,
504
- }
505
-
506
- /// The various kinds of call frames possible in the EVM.
507
- #[napi]
508
- #[derive(Debug)]
509
- pub enum CallKind {
510
- /// Regular call that may change state.
511
- Call = 0,
512
- /// Variant of `DelegateCall` that doesn't preserve sender or value in the
513
- /// frame.
514
- CallCode = 1,
515
- /// Call that executes the code of the target in the context of the caller.
516
- DelegateCall = 2,
517
- /// Regular call that may not change state.
518
- StaticCall = 3,
519
- /// Contract creation.
520
- Create = 4,
521
- }
522
-
523
- /// Kind marker for log traces.
524
- #[napi]
525
- #[derive(Debug)]
526
- pub enum LogKind {
527
- /// Single kind of log.
528
- Log = 5,
529
- // NOTE: The discriminants of LogKind and CallKind must be disjoint.
530
- }
531
-
532
- /// Decoded function call or event.
533
- #[napi(object)]
534
- pub struct DecodedTraceParameters {
535
- /// The name of a function or an event.
536
- pub name: String,
537
- /// The arguments of the function call or the event, in their human-readable
538
- /// representations.
539
- pub arguments: Vec<String>,
540
- }
541
-
542
- impl CallTrace {
543
- /// Instantiates a `CallTrace` with the details from a node and the supplied
544
- /// children.
545
- fn new(node: &traces::CallTraceNode, children: Vec<Either<CallTrace, LogTrace>>) -> Self {
546
- let contract = node.trace.decoded.label.clone();
547
- let address = node.trace.address.to_checksum(None);
548
-
549
- let inputs = match &node.trace.decoded.call_data {
550
- Some(traces::DecodedCallData { signature, args }) => {
551
- let name = signature
552
- .split('(')
553
- .next()
554
- .expect("invalid function signature")
555
- .to_string();
556
- let arguments = args.clone();
557
- Either::A(DecodedTraceParameters { name, arguments })
558
- }
559
- None => Either::B(node.trace.data.as_ref().into()),
560
- };
561
-
562
- let outputs = match &node.trace.decoded.return_data {
563
- Some(outputs) => Either::A(outputs.clone()),
564
- None => {
565
- if node.kind().is_any_create() && node.trace.success {
566
- Either::A(format!("{} bytes of code", node.trace.output.len()))
567
- } else {
568
- Either::B(node.trace.output.as_ref().into())
569
- }
570
- }
571
- };
572
-
573
- Self {
574
- kind: node.kind().into(),
575
- success: node.trace.success,
576
- is_cheatcode: node.trace.address == CHEATCODE_ADDRESS,
577
- gas_used: node.trace.gas_used.into(),
578
- value: u256_to_bigint(&node.trace.value),
579
- contract,
580
- address,
581
- inputs,
582
- outputs,
583
- children,
584
- }
585
- }
586
-
587
- /// Creates a tree of `CallTrace` rooted at some node in a trace arena.
588
- fn from_arena_node(arena: &CallTraceArena, arena_index: usize) -> Self {
589
- struct StackItem {
590
- visited: bool,
591
- parent_stack_index: Option<usize>,
592
- arena_index: usize,
593
- child_traces: Vec<Option<CallTrace>>,
594
- }
595
-
596
- let mut stack = Vec::new();
597
-
598
- stack.push(StackItem {
599
- visited: false,
600
- arena_index,
601
- parent_stack_index: None,
602
- child_traces: Vec::new(),
603
- });
604
-
605
- loop {
606
- // We will break out of the loop before the stack goes empty.
607
- let mut item = stack.pop().unwrap();
608
- let node = arena
609
- .nodes()
610
- .get(item.arena_index)
611
- .expect("Arena index should be valid");
612
-
613
- if item.visited {
614
- let mut logs = node
615
- .logs
616
- .iter()
617
- .map(|log| Some(LogTrace::from(log)))
618
- .collect::<Vec<_>>();
619
-
620
- let children = node
621
- .ordering
622
- .iter()
623
- .filter_map(|ord| match *ord {
624
- traces::TraceMemberOrder::Log(i) => {
625
- let log = logs
626
- .get_mut(i)
627
- .expect("Log index should be valid")
628
- .take()
629
- .unwrap();
630
- Some(Either::B(log))
631
- }
632
- traces::TraceMemberOrder::Call(i) => {
633
- let child_trace = item
634
- .child_traces
635
- .get_mut(i)
636
- .expect("Child trace index should be valid")
637
- .take()
638
- .unwrap();
639
- Some(Either::A(child_trace))
640
- }
641
- traces::TraceMemberOrder::Step(_) => None,
642
- })
643
- .collect();
644
-
645
- let trace = CallTrace::new(node, children);
646
-
647
- if let Some(parent_stack_index) = item.parent_stack_index {
648
- let parent = stack
649
- .get_mut(parent_stack_index)
650
- .expect("Parent stack index should be valid");
651
- parent.child_traces.push(Some(trace));
652
- } else {
653
- return trace;
654
- }
655
- } else {
656
- item.visited = true;
657
- item.child_traces.reserve(node.children.len());
658
-
659
- stack.push(item);
660
-
661
- let top_index = Some(stack.len() - 1);
662
-
663
- // Push children in reverse order to result in linear traversal of the arena for
664
- // cache efficiency, on the assumption that the arena contains a pre-order
665
- // traversal of the trace.
666
- stack.extend(node.children.iter().rev().map(|&arena_index| StackItem {
667
- visited: false,
668
- parent_stack_index: top_index,
669
- arena_index,
670
- child_traces: Vec::new(),
671
- }));
672
- }
673
- }
674
- }
675
- }
676
-
677
- impl From<&traces::CallLog> for LogTrace {
678
- fn from(log: &traces::CallLog) -> Self {
679
- let decoded_log = log.decoded.name.clone().zip(log.decoded.params.as_ref());
680
-
681
- let parameters = decoded_log.map_or_else(
682
- || {
683
- let raw_log = &log.raw_log;
684
- let mut params = Vec::with_capacity(raw_log.topics().len() + 1);
685
- params.extend(raw_log.topics().iter().map(|topic| topic.as_slice().into()));
686
- params.push(log.raw_log.data.as_ref().into());
687
- Either::B(params)
688
- },
689
- |(name, params)| {
690
- let arguments = params
691
- .iter()
692
- .map(|(name, value)| format!("{name}: {value}"))
693
- .collect();
694
- Either::A(DecodedTraceParameters { name, arguments })
695
- },
696
- );
697
-
698
- Self {
699
- kind: LogKind::Log,
700
- parameters,
701
- }
702
- }
703
- }
704
-
705
- impl From<traces::CallKind> for CallKind {
706
- fn from(value: traces::CallKind) -> Self {
707
- match value {
708
- traces::CallKind::Call => CallKind::Call,
709
- traces::CallKind::StaticCall => CallKind::StaticCall,
710
- traces::CallKind::CallCode => CallKind::CallCode,
711
- traces::CallKind::DelegateCall => CallKind::DelegateCall,
712
- traces::CallKind::Create | traces::CallKind::Create2 => CallKind::Create,
713
-
714
- // We do not support these EVM features.
715
- traces::CallKind::AuthCall => {
716
- unreachable!("Unsupported EVM features")
717
- }
718
- }
719
- }
720
- }
721
-
722
- /// The result of a Solidity test run.
723
- #[napi(object)]
724
- pub struct SolidityTestResult {
725
- /// Gas report, if it was generated.
726
- #[napi(readonly)]
727
- pub gas_report: Option<GasReport>,
728
- }
729
-
730
- impl From<edr_solidity_tests::multi_runner::SolidityTestResult> for SolidityTestResult {
731
- fn from(value: edr_solidity_tests::multi_runner::SolidityTestResult) -> Self {
732
- Self {
733
- gas_report: value.gas_report.map(GasReport::from),
734
- }
735
- }
736
- }