@nomicfoundation/edr 0.12.0-next.0 → 0.12.0-next.10
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 +217 -64
- package/index.js +4 -1
- package/package.json +26 -21
- package/src/account.rs +6 -5
- package/src/block.rs +1 -1
- package/src/call_override.rs +1 -1
- package/src/cast.rs +1 -1
- package/src/chains/generic.rs +27 -20
- package/src/chains/l1.rs +84 -78
- package/src/chains/op.rs +50 -51
- package/src/config.rs +166 -9
- package/src/context.rs +96 -89
- package/src/contract_decoder.rs +57 -0
- package/src/debug_trace.rs +2 -0
- package/src/gas_report.rs +92 -0
- package/src/lib.rs +4 -1
- package/src/log.rs +2 -2
- package/src/logger.rs +4 -2
- package/src/mock/time.rs +134 -0
- package/src/mock.rs +4 -1
- package/src/precompile.rs +1 -1
- package/src/provider/response.rs +4 -4
- package/src/provider.rs +51 -4
- package/src/result.rs +35 -80
- package/src/serde.rs +1 -1
- package/src/solidity_tests/config.rs +80 -12
- package/src/solidity_tests/l1.rs +7 -7
- package/src/solidity_tests/op.rs +5 -5
- package/src/solidity_tests/runner.rs +1 -1
- package/src/solidity_tests/test_results.rs +109 -41
- package/src/solidity_tests.rs +1 -1
- package/src/trace/debug.rs +29 -26
- package/src/trace/exit.rs +9 -8
- package/src/trace/return_data.rs +19 -7
- package/src/trace/solidity_stack_trace.rs +56 -28
- package/src/trace.rs +6 -5
- package/src/ts/solidity_tests.ts +46 -0
- package/src/withdrawal.rs +5 -5
- package/Cargo.toml +0 -92
- package/build.rs +0 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use std::{collections::HashMap, path::PathBuf};
|
|
2
2
|
|
|
3
3
|
use derive_more::Debug;
|
|
4
|
-
use
|
|
4
|
+
use edr_primitives::hex;
|
|
5
5
|
use edr_solidity_tests::{
|
|
6
6
|
executors::invariant::InvariantConfig,
|
|
7
7
|
fuzz::FuzzConfig,
|
|
@@ -109,7 +109,7 @@ pub struct SolidityTestRunnerConfigArgs {
|
|
|
109
109
|
/// Defaults to false.
|
|
110
110
|
pub disable_block_gas_limit: Option<bool>,
|
|
111
111
|
/// The memory limit of the EVM in bytes.
|
|
112
|
-
/// Defaults to 33_554_432 (2^25 = 32MiB).
|
|
112
|
+
/// Defaults to `33_554_432` (2^25 = 32MiB).
|
|
113
113
|
#[serde(serialize_with = "serialize_optional_bigint_as_struct")]
|
|
114
114
|
pub memory_limit: Option<BigInt>,
|
|
115
115
|
/// The predeploys applied in local mode. Defaults to no predeploys.
|
|
@@ -143,6 +143,8 @@ pub struct SolidityTestRunnerConfigArgs {
|
|
|
143
143
|
/// If an invariant config setting is not set, but a corresponding fuzz
|
|
144
144
|
/// config value is set, then the fuzz config value will be used.
|
|
145
145
|
pub invariant: Option<InvariantConfigArgs>,
|
|
146
|
+
/// Whether to collect stack traces.
|
|
147
|
+
pub collect_stack_traces: Option<CollectStackTraces>,
|
|
146
148
|
/// Controls which test results should include execution traces. Defaults to
|
|
147
149
|
/// None.
|
|
148
150
|
pub include_traces: Option<IncludeTraces>,
|
|
@@ -153,6 +155,11 @@ pub struct SolidityTestRunnerConfigArgs {
|
|
|
153
155
|
/// A regex pattern to filter tests. If provided, only test methods that
|
|
154
156
|
/// match the pattern will be executed and reported as a test result.
|
|
155
157
|
pub test_pattern: Option<String>,
|
|
158
|
+
/// Controls whether to generate a gas report after running the tests.
|
|
159
|
+
/// Enabling this also enables collection of all traces and EVM isolation
|
|
160
|
+
/// mode.
|
|
161
|
+
/// Defaults to false.
|
|
162
|
+
pub generate_gas_report: Option<bool>,
|
|
156
163
|
}
|
|
157
164
|
|
|
158
165
|
impl SolidityTestRunnerConfigArgs {
|
|
@@ -194,9 +201,11 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
194
201
|
prompt_timeout,
|
|
195
202
|
fuzz,
|
|
196
203
|
invariant,
|
|
204
|
+
collect_stack_traces,
|
|
197
205
|
include_traces,
|
|
198
206
|
observability,
|
|
199
207
|
test_pattern,
|
|
208
|
+
generate_gas_report,
|
|
200
209
|
} = self;
|
|
201
210
|
|
|
202
211
|
let test_pattern = TestFilterConfig {
|
|
@@ -296,8 +305,13 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
296
305
|
cheatcode,
|
|
297
306
|
fuzz,
|
|
298
307
|
invariant,
|
|
308
|
+
collect_stack_traces: collect_stack_traces.map_or(
|
|
309
|
+
edr_solidity_tests::CollectStackTraces::OnFailure,
|
|
310
|
+
edr_solidity_tests::CollectStackTraces::from,
|
|
311
|
+
),
|
|
299
312
|
on_collected_coverage_fn,
|
|
300
313
|
test_pattern,
|
|
314
|
+
generate_gas_report,
|
|
301
315
|
};
|
|
302
316
|
|
|
303
317
|
Ok(config)
|
|
@@ -657,24 +671,55 @@ impl From<PathPermission> for foundry_cheatcodes::PathPermission {
|
|
|
657
671
|
}
|
|
658
672
|
}
|
|
659
673
|
|
|
660
|
-
|
|
674
|
+
/**
|
|
675
|
+
* Determines the level of file system access for the given path.
|
|
676
|
+
*
|
|
677
|
+
* Exact path matching is used for file permissions. Prefix matching is used
|
|
678
|
+
* for directory permissions.
|
|
679
|
+
*
|
|
680
|
+
* Giving write access to configuration files, source files or executables
|
|
681
|
+
* in a project is considered dangerous, because it can be used by malicious
|
|
682
|
+
* Solidity dependencies to escape the EVM sandbox. It is therefore
|
|
683
|
+
* recommended to give write access to specific safe files only. If write
|
|
684
|
+
* access to a directory is needed, please make sure that it doesn't contain
|
|
685
|
+
* configuration files, source files or executables neither in the top level
|
|
686
|
+
* directory, nor in any subdirectories.
|
|
687
|
+
*/
|
|
661
688
|
#[napi]
|
|
662
689
|
#[derive(Debug, serde::Serialize)]
|
|
663
690
|
pub enum FsAccessPermission {
|
|
664
|
-
///
|
|
665
|
-
|
|
666
|
-
/// Only reading
|
|
667
|
-
|
|
668
|
-
/// Only writing
|
|
669
|
-
|
|
691
|
+
/// Allows reading and writing the file
|
|
692
|
+
ReadWriteFile,
|
|
693
|
+
/// Only allows reading the file
|
|
694
|
+
ReadFile,
|
|
695
|
+
/// Only allows writing the file
|
|
696
|
+
WriteFile,
|
|
697
|
+
/// Allows reading and writing all files in the directory and its
|
|
698
|
+
/// subdirectories
|
|
699
|
+
DangerouslyReadWriteDirectory,
|
|
700
|
+
/// Allows reading all files in the directory and its subdirectories
|
|
701
|
+
ReadDirectory,
|
|
702
|
+
/// Allows writing all files in the directory and its subdirectories
|
|
703
|
+
DangerouslyWriteDirectory,
|
|
670
704
|
}
|
|
671
705
|
|
|
672
706
|
impl From<FsAccessPermission> for foundry_cheatcodes::FsAccessPermission {
|
|
673
707
|
fn from(value: FsAccessPermission) -> Self {
|
|
674
708
|
match value {
|
|
675
|
-
FsAccessPermission::
|
|
676
|
-
|
|
677
|
-
|
|
709
|
+
FsAccessPermission::ReadWriteFile => {
|
|
710
|
+
foundry_cheatcodes::FsAccessPermission::ReadWriteFile
|
|
711
|
+
}
|
|
712
|
+
FsAccessPermission::ReadFile => foundry_cheatcodes::FsAccessPermission::ReadFile,
|
|
713
|
+
FsAccessPermission::WriteFile => foundry_cheatcodes::FsAccessPermission::WriteFile,
|
|
714
|
+
FsAccessPermission::DangerouslyReadWriteDirectory => {
|
|
715
|
+
foundry_cheatcodes::FsAccessPermission::DangerouslyReadWriteDirectory
|
|
716
|
+
}
|
|
717
|
+
FsAccessPermission::ReadDirectory => {
|
|
718
|
+
foundry_cheatcodes::FsAccessPermission::ReadDirectory
|
|
719
|
+
}
|
|
720
|
+
FsAccessPermission::DangerouslyWriteDirectory => {
|
|
721
|
+
foundry_cheatcodes::FsAccessPermission::DangerouslyWriteDirectory
|
|
722
|
+
}
|
|
678
723
|
}
|
|
679
724
|
}
|
|
680
725
|
}
|
|
@@ -690,6 +735,29 @@ pub struct AddressLabel {
|
|
|
690
735
|
pub label: String,
|
|
691
736
|
}
|
|
692
737
|
|
|
738
|
+
/// A type that controls when stack traces are collected.
|
|
739
|
+
#[napi]
|
|
740
|
+
#[derive(Debug, serde::Serialize)]
|
|
741
|
+
pub enum CollectStackTraces {
|
|
742
|
+
/// Always collects stack traces, adding performance overhead.
|
|
743
|
+
Always,
|
|
744
|
+
/// Only collects stack traces upon failure, re-executing the test. This
|
|
745
|
+
/// minimizes performance overhead.
|
|
746
|
+
///
|
|
747
|
+
/// Not all tests can be re-executed since certain cheatcodes contain
|
|
748
|
+
/// non-deterministic side-effects.
|
|
749
|
+
OnFailure,
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
impl From<CollectStackTraces> for edr_solidity_tests::CollectStackTraces {
|
|
753
|
+
fn from(value: CollectStackTraces) -> Self {
|
|
754
|
+
match value {
|
|
755
|
+
CollectStackTraces::Always => edr_solidity_tests::CollectStackTraces::Always,
|
|
756
|
+
CollectStackTraces::OnFailure => edr_solidity_tests::CollectStackTraces::OnFailure,
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
693
761
|
/// Configuration for [`SolidityTestRunnerConfigArgs::include_traces`] that
|
|
694
762
|
/// controls execution trace decoding and inclusion in test results.
|
|
695
763
|
#[napi]
|
package/src/solidity_tests/l1.rs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
use std::{collections::BTreeMap, sync::Arc};
|
|
2
2
|
|
|
3
|
-
use edr_eth::Bytes;
|
|
4
3
|
use edr_napi_core::solidity::{
|
|
5
4
|
config::{TestRunnerConfig, TracingConfigWithBuffers},
|
|
6
5
|
SyncTestRunner, SyncTestRunnerFactory,
|
|
7
6
|
};
|
|
7
|
+
use edr_primitives::Bytes;
|
|
8
8
|
use edr_solidity::artifacts::ArtifactId;
|
|
9
9
|
use edr_solidity_tests::{
|
|
10
10
|
contracts::ContractsByArtifact, decode::RevertDecoder, evm_context::L1EvmBuilder,
|
|
11
|
-
multi_runner::TestContract,
|
|
11
|
+
multi_runner::TestContract, MultiContractRunner,
|
|
12
12
|
};
|
|
13
13
|
use napi::tokio;
|
|
14
14
|
use napi_derive::napi;
|
|
@@ -33,14 +33,14 @@ impl SyncTestRunnerFactory for L1TestRunnerFactory {
|
|
|
33
33
|
let runner = tokio::task::block_in_place(|| {
|
|
34
34
|
runtime
|
|
35
35
|
.block_on(MultiContractRunner::<
|
|
36
|
-
|
|
36
|
+
edr_chain_l1::BlockEnv,
|
|
37
37
|
(),
|
|
38
38
|
L1EvmBuilder,
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
edr_chain_l1::HaltReason,
|
|
40
|
+
edr_chain_l1::Hardfork,
|
|
41
41
|
_,
|
|
42
|
-
|
|
43
|
-
TxEnv,
|
|
42
|
+
edr_chain_l1::InvalidTransaction,
|
|
43
|
+
edr_chain_l1::TxEnv,
|
|
44
44
|
>::new(
|
|
45
45
|
config.try_into()?,
|
|
46
46
|
contracts,
|
package/src/solidity_tests/op.rs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
use std::{collections::BTreeMap, sync::Arc};
|
|
2
2
|
|
|
3
|
-
use edr_eth::Bytes;
|
|
4
3
|
use edr_napi_core::solidity::{
|
|
5
4
|
config::{TestRunnerConfig, TracingConfigWithBuffers},
|
|
6
5
|
SyncTestRunner, SyncTestRunnerFactory,
|
|
7
6
|
};
|
|
8
7
|
use edr_op::solidity_tests::OpEvmBuilder;
|
|
8
|
+
use edr_primitives::Bytes;
|
|
9
9
|
use edr_solidity::artifacts::ArtifactId;
|
|
10
10
|
use edr_solidity_tests::{
|
|
11
11
|
contracts::ContractsByArtifact, decode::RevertDecoder, multi_runner::TestContract,
|
|
@@ -34,14 +34,14 @@ impl SyncTestRunnerFactory for OpTestRunnerFactory {
|
|
|
34
34
|
let runner = tokio::task::block_in_place(|| {
|
|
35
35
|
runtime
|
|
36
36
|
.block_on(MultiContractRunner::<
|
|
37
|
-
|
|
37
|
+
edr_op::BlockEnv,
|
|
38
38
|
_,
|
|
39
39
|
OpEvmBuilder,
|
|
40
|
-
edr_op::
|
|
41
|
-
edr_op::
|
|
40
|
+
edr_op::HaltReason,
|
|
41
|
+
edr_op::Hardfork,
|
|
42
42
|
_,
|
|
43
43
|
edr_op::transaction::InvalidTransaction,
|
|
44
|
-
edr_op::transaction::OpTxEnv<
|
|
44
|
+
edr_op::transaction::OpTxEnv<edr_chain_l1::TxEnv>,
|
|
45
45
|
>::new(
|
|
46
46
|
config.try_into()?,
|
|
47
47
|
contracts,
|
|
@@ -18,11 +18,32 @@ use napi_derive::napi;
|
|
|
18
18
|
|
|
19
19
|
use crate::{
|
|
20
20
|
cast::TryCast,
|
|
21
|
+
gas_report::GasReport,
|
|
21
22
|
solidity_tests::{artifact::ArtifactId, config::IncludeTraces},
|
|
22
23
|
trace::{solidity_stack_trace::SolidityStackTraceEntry, u256_to_bigint},
|
|
23
24
|
};
|
|
24
25
|
|
|
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`]
|
|
26
47
|
#[napi]
|
|
27
48
|
#[derive(Clone, Debug)]
|
|
28
49
|
pub struct SuiteResult {
|
|
@@ -30,13 +51,13 @@ pub struct SuiteResult {
|
|
|
30
51
|
/// callback
|
|
31
52
|
#[napi(readonly)]
|
|
32
53
|
pub id: ArtifactId,
|
|
33
|
-
/// See [edr_solidity_tests::result::SuiteResult::duration]
|
|
54
|
+
/// See [`edr_solidity_tests::result::SuiteResult::duration`]
|
|
34
55
|
#[napi(readonly)]
|
|
35
56
|
pub duration_ns: BigInt,
|
|
36
|
-
/// See [edr_solidity_tests::result::SuiteResult::test_results]
|
|
57
|
+
/// See [`edr_solidity_tests::result::SuiteResult::test_results`]
|
|
37
58
|
#[napi(readonly)]
|
|
38
59
|
pub test_results: Vec<TestResult>,
|
|
39
|
-
/// See [edr_solidity_tests::result::SuiteResult::warnings]
|
|
60
|
+
/// See [`edr_solidity_tests::result::SuiteResult::warnings`]
|
|
40
61
|
#[napi(readonly)]
|
|
41
62
|
pub warnings: Vec<String>,
|
|
42
63
|
}
|
|
@@ -60,31 +81,37 @@ impl SuiteResult {
|
|
|
60
81
|
}
|
|
61
82
|
}
|
|
62
83
|
|
|
63
|
-
/// See [edr_solidity_tests::result::TestResult]
|
|
84
|
+
/// See [`edr_solidity_tests::result::TestResult`]
|
|
64
85
|
#[napi]
|
|
65
86
|
#[derive(Clone, Debug)]
|
|
66
87
|
pub struct TestResult {
|
|
67
88
|
/// The name of the test.
|
|
68
89
|
#[napi(readonly)]
|
|
69
90
|
pub name: String,
|
|
70
|
-
/// See [edr_solidity_tests::result::TestResult::status]
|
|
91
|
+
/// See [`edr_solidity_tests::result::TestResult::status`]
|
|
71
92
|
#[napi(readonly)]
|
|
72
93
|
pub status: TestStatus,
|
|
73
|
-
/// See [edr_solidity_tests::result::TestResult::reason]
|
|
94
|
+
/// See [`edr_solidity_tests::result::TestResult::reason`]
|
|
74
95
|
#[napi(readonly)]
|
|
75
96
|
pub reason: Option<String>,
|
|
76
|
-
/// See [edr_solidity_tests::result::TestResult::counterexample]
|
|
97
|
+
/// See [`edr_solidity_tests::result::TestResult::counterexample`]
|
|
77
98
|
#[napi(readonly)]
|
|
78
99
|
pub counterexample: Option<Either<BaseCounterExample, CounterExampleSequence>>,
|
|
79
|
-
/// See [edr_solidity_tests::result::TestResult::decoded_logs]
|
|
100
|
+
/// See [`edr_solidity_tests::result::TestResult::decoded_logs`]
|
|
80
101
|
#[napi(readonly)]
|
|
81
102
|
pub decoded_logs: Vec<String>,
|
|
82
|
-
/// See [edr_solidity_tests::result::TestResult::kind]
|
|
103
|
+
/// See [`edr_solidity_tests::result::TestResult::kind`]
|
|
83
104
|
#[napi(readonly)]
|
|
84
105
|
pub kind: Either3<StandardTestKind, FuzzTestKind, InvariantTestKind>,
|
|
85
|
-
/// See [edr_solidity_tests::result::TestResult::duration]
|
|
106
|
+
/// See [`edr_solidity_tests::result::TestResult::duration`]
|
|
86
107
|
#[napi(readonly)]
|
|
87
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>>,
|
|
88
115
|
|
|
89
116
|
stack_trace_result: Option<Arc<StackTraceResult<String>>>,
|
|
90
117
|
call_trace_arenas: Vec<(traces::TraceKind, SparsedTraceArena)>,
|
|
@@ -264,6 +291,19 @@ impl TestResult {
|
|
|
264
291
|
}),
|
|
265
292
|
},
|
|
266
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
|
+
),
|
|
267
307
|
stack_trace_result: test_result.stack_trace_result.map(Arc::new),
|
|
268
308
|
call_trace_arenas: if include_trace {
|
|
269
309
|
test_result.traces
|
|
@@ -296,7 +336,7 @@ impl From<edr_solidity_tests::result::TestStatus> for TestStatus {
|
|
|
296
336
|
}
|
|
297
337
|
}
|
|
298
338
|
|
|
299
|
-
/// See [edr_solidity_tests::result::TestKind::Standard]
|
|
339
|
+
/// See [`edr_solidity_tests::result::TestKind::Standard`]
|
|
300
340
|
#[napi(object)]
|
|
301
341
|
#[derive(Debug, Clone)]
|
|
302
342
|
pub struct StandardTestKind {
|
|
@@ -305,22 +345,22 @@ pub struct StandardTestKind {
|
|
|
305
345
|
pub consumed_gas: BigInt,
|
|
306
346
|
}
|
|
307
347
|
|
|
308
|
-
/// See [edr_solidity_tests::result::TestKind::Fuzz]
|
|
348
|
+
/// See [`edr_solidity_tests::result::TestKind::Fuzz`]
|
|
309
349
|
#[napi(object)]
|
|
310
350
|
#[derive(Debug, Clone)]
|
|
311
351
|
pub struct FuzzTestKind {
|
|
312
|
-
/// See [edr_solidity_tests::result::TestKind::Fuzz]
|
|
352
|
+
/// See [`edr_solidity_tests::result::TestKind::Fuzz`]
|
|
313
353
|
#[napi(readonly)]
|
|
314
354
|
pub runs: BigInt,
|
|
315
|
-
/// See [edr_solidity_tests::result::TestKind::Fuzz]
|
|
355
|
+
/// See [`edr_solidity_tests::result::TestKind::Fuzz`]
|
|
316
356
|
#[napi(readonly)]
|
|
317
357
|
pub mean_gas: BigInt,
|
|
318
|
-
/// See [edr_solidity_tests::result::TestKind::Fuzz]
|
|
358
|
+
/// See [`edr_solidity_tests::result::TestKind::Fuzz`]
|
|
319
359
|
#[napi(readonly)]
|
|
320
360
|
pub median_gas: BigInt,
|
|
321
361
|
}
|
|
322
362
|
|
|
323
|
-
/// See [edr_solidity_tests::fuzz::FuzzCase]
|
|
363
|
+
/// See [`edr_solidity_tests::fuzz::FuzzCase`]
|
|
324
364
|
#[napi(object)]
|
|
325
365
|
#[derive(Clone)]
|
|
326
366
|
pub struct FuzzCase {
|
|
@@ -344,17 +384,17 @@ impl Debug for FuzzCase {
|
|
|
344
384
|
}
|
|
345
385
|
}
|
|
346
386
|
|
|
347
|
-
/// See [edr_solidity_tests::result::TestKind::Invariant]
|
|
387
|
+
/// See [`edr_solidity_tests::result::TestKind::Invariant`]
|
|
348
388
|
#[napi(object)]
|
|
349
389
|
#[derive(Debug, Clone)]
|
|
350
390
|
pub struct InvariantTestKind {
|
|
351
|
-
/// See [edr_solidity_tests::result::TestKind::Invariant]
|
|
391
|
+
/// See [`edr_solidity_tests::result::TestKind::Invariant`]
|
|
352
392
|
#[napi(readonly)]
|
|
353
393
|
pub runs: BigInt,
|
|
354
|
-
/// See [edr_solidity_tests::result::TestKind::Invariant]
|
|
394
|
+
/// See [`edr_solidity_tests::result::TestKind::Invariant`]
|
|
355
395
|
#[napi(readonly)]
|
|
356
396
|
pub calls: BigInt,
|
|
357
|
-
/// See [edr_solidity_tests::result::TestKind::Invariant]
|
|
397
|
+
/// See [`edr_solidity_tests::result::TestKind::Invariant`]
|
|
358
398
|
#[napi(readonly)]
|
|
359
399
|
pub reverts: BigInt,
|
|
360
400
|
}
|
|
@@ -370,26 +410,26 @@ pub struct CounterExampleSequence {
|
|
|
370
410
|
pub sequence: Vec<BaseCounterExample>,
|
|
371
411
|
}
|
|
372
412
|
|
|
373
|
-
/// See [edr_solidity_tests::fuzz::BaseCounterExample]
|
|
413
|
+
/// See [`edr_solidity_tests::fuzz::BaseCounterExample`]
|
|
374
414
|
#[napi(object)]
|
|
375
415
|
#[derive(Clone)]
|
|
376
416
|
pub struct BaseCounterExample {
|
|
377
|
-
/// See [edr_solidity_tests::fuzz::BaseCounterExample::sender]
|
|
417
|
+
/// See [`edr_solidity_tests::fuzz::BaseCounterExample::sender`]
|
|
378
418
|
#[napi(readonly)]
|
|
379
419
|
pub sender: Option<Uint8Array>,
|
|
380
|
-
/// See [edr_solidity_tests::fuzz::BaseCounterExample::addr]
|
|
420
|
+
/// See [`edr_solidity_tests::fuzz::BaseCounterExample::addr`]
|
|
381
421
|
#[napi(readonly)]
|
|
382
422
|
pub address: Option<Uint8Array>,
|
|
383
|
-
/// See [edr_solidity_tests::fuzz::BaseCounterExample::calldata]
|
|
423
|
+
/// See [`edr_solidity_tests::fuzz::BaseCounterExample::calldata`]
|
|
384
424
|
#[napi(readonly)]
|
|
385
425
|
pub calldata: Uint8Array,
|
|
386
|
-
/// See [edr_solidity_tests::fuzz::BaseCounterExample::contract_name]
|
|
426
|
+
/// See [`edr_solidity_tests::fuzz::BaseCounterExample::contract_name`]
|
|
387
427
|
#[napi(readonly)]
|
|
388
428
|
pub contract_name: Option<String>,
|
|
389
|
-
/// See [edr_solidity_tests::fuzz::BaseCounterExample::signature]
|
|
429
|
+
/// See [`edr_solidity_tests::fuzz::BaseCounterExample::signature`]
|
|
390
430
|
#[napi(readonly)]
|
|
391
431
|
pub signature: Option<String>,
|
|
392
|
-
/// See [edr_solidity_tests::fuzz::BaseCounterExample::args]
|
|
432
|
+
/// See [`edr_solidity_tests::fuzz::BaseCounterExample::args`]
|
|
393
433
|
#[napi(readonly)]
|
|
394
434
|
pub args: Option<String>,
|
|
395
435
|
}
|
|
@@ -431,9 +471,10 @@ pub struct CallTrace {
|
|
|
431
471
|
pub gas_used: BigInt,
|
|
432
472
|
/// The amount of native token that was included with the call.
|
|
433
473
|
pub value: BigInt,
|
|
434
|
-
/// The target of the call.
|
|
435
|
-
|
|
436
|
-
|
|
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>,
|
|
437
478
|
/// The input (calldata) to the call. If it encodes a known function call,
|
|
438
479
|
/// it will be decoded into the function name and a list of arguments.
|
|
439
480
|
/// For example, `{ name: "ownerOf", arguments: ["1"] }`. Note that the
|
|
@@ -502,12 +543,8 @@ impl CallTrace {
|
|
|
502
543
|
/// Instantiates a `CallTrace` with the details from a node and the supplied
|
|
503
544
|
/// children.
|
|
504
545
|
fn new(node: &traces::CallTraceNode, children: Vec<Either<CallTrace, LogTrace>>) -> Self {
|
|
505
|
-
let contract = node
|
|
506
|
-
|
|
507
|
-
.decoded
|
|
508
|
-
.label
|
|
509
|
-
.clone()
|
|
510
|
-
.unwrap_or(node.trace.address.to_checksum(None));
|
|
546
|
+
let contract = node.trace.decoded.label.clone();
|
|
547
|
+
let address = node.trace.address.to_checksum(None);
|
|
511
548
|
|
|
512
549
|
let inputs = match &node.trace.decoded.call_data {
|
|
513
550
|
Some(traces::DecodedCallData { signature, args }) => {
|
|
@@ -540,6 +577,7 @@ impl CallTrace {
|
|
|
540
577
|
gas_used: node.trace.gas_used.into(),
|
|
541
578
|
value: u256_to_bigint(&node.trace.value),
|
|
542
579
|
contract,
|
|
580
|
+
address,
|
|
543
581
|
inputs,
|
|
544
582
|
outputs,
|
|
545
583
|
children,
|
|
@@ -567,7 +605,10 @@ impl CallTrace {
|
|
|
567
605
|
loop {
|
|
568
606
|
// We will break out of the loop before the stack goes empty.
|
|
569
607
|
let mut item = stack.pop().unwrap();
|
|
570
|
-
let node =
|
|
608
|
+
let node = arena
|
|
609
|
+
.nodes()
|
|
610
|
+
.get(item.arena_index)
|
|
611
|
+
.expect("Arena index should be valid");
|
|
571
612
|
|
|
572
613
|
if item.visited {
|
|
573
614
|
let mut logs = node
|
|
@@ -581,11 +622,20 @@ impl CallTrace {
|
|
|
581
622
|
.iter()
|
|
582
623
|
.filter_map(|ord| match *ord {
|
|
583
624
|
traces::TraceMemberOrder::Log(i) => {
|
|
584
|
-
let log = logs
|
|
625
|
+
let log = logs
|
|
626
|
+
.get_mut(i)
|
|
627
|
+
.expect("Log index should be valid")
|
|
628
|
+
.take()
|
|
629
|
+
.unwrap();
|
|
585
630
|
Some(Either::B(log))
|
|
586
631
|
}
|
|
587
632
|
traces::TraceMemberOrder::Call(i) => {
|
|
588
|
-
let child_trace = item
|
|
633
|
+
let child_trace = item
|
|
634
|
+
.child_traces
|
|
635
|
+
.get_mut(i)
|
|
636
|
+
.expect("Child trace index should be valid")
|
|
637
|
+
.take()
|
|
638
|
+
.unwrap();
|
|
589
639
|
Some(Either::A(child_trace))
|
|
590
640
|
}
|
|
591
641
|
traces::TraceMemberOrder::Step(_) => None,
|
|
@@ -595,7 +645,9 @@ impl CallTrace {
|
|
|
595
645
|
let trace = CallTrace::new(node, children);
|
|
596
646
|
|
|
597
647
|
if let Some(parent_stack_index) = item.parent_stack_index {
|
|
598
|
-
let parent =
|
|
648
|
+
let parent = stack
|
|
649
|
+
.get_mut(parent_stack_index)
|
|
650
|
+
.expect("Parent stack index should be valid");
|
|
599
651
|
parent.child_traces.push(Some(trace));
|
|
600
652
|
} else {
|
|
601
653
|
return trace;
|
|
@@ -666,3 +718,19 @@ impl From<traces::CallKind> for CallKind {
|
|
|
666
718
|
}
|
|
667
719
|
}
|
|
668
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
|
+
}
|
package/src/solidity_tests.rs
CHANGED
|
@@ -9,7 +9,7 @@ pub mod test_results;
|
|
|
9
9
|
|
|
10
10
|
use std::path::Path;
|
|
11
11
|
|
|
12
|
-
use
|
|
12
|
+
use edr_primitives::Bytes;
|
|
13
13
|
use edr_solidity::linker::{LinkOutput, Linker};
|
|
14
14
|
use edr_solidity_tests::{constants::LIBRARY_DEPLOYER, contracts::ContractsByArtifact};
|
|
15
15
|
use foundry_compilers::artifacts::Libraries;
|
package/src/trace/debug.rs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//! Port of `hardhat-network/stack-traces/debug.ts` from Hardhat.
|
|
2
2
|
|
|
3
|
-
use napi::bindgen_prelude::
|
|
3
|
+
use napi::bindgen_prelude::Either25;
|
|
4
4
|
use napi_derive::napi;
|
|
5
5
|
|
|
6
6
|
use super::solidity_stack_trace::{RevertErrorStackTraceEntry, SolidityStackTrace};
|
|
@@ -11,31 +11,32 @@ fn print_stack_trace(trace: SolidityStackTrace) -> napi::Result<()> {
|
|
|
11
11
|
let entry_values = trace
|
|
12
12
|
.into_iter()
|
|
13
13
|
.map(|entry| match entry {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
14
|
+
Either25::A(entry) => serde_json::to_value(entry),
|
|
15
|
+
Either25::B(entry) => serde_json::to_value(entry),
|
|
16
|
+
Either25::C(entry) => serde_json::to_value(entry),
|
|
17
|
+
Either25::D(entry) => serde_json::to_value(entry),
|
|
18
|
+
Either25::F(entry) => serde_json::to_value(entry),
|
|
19
|
+
Either25::G(entry) => serde_json::to_value(entry),
|
|
20
|
+
Either25::H(entry) => serde_json::to_value(entry),
|
|
21
|
+
Either25::I(entry) => serde_json::to_value(entry),
|
|
22
|
+
Either25::J(entry) => serde_json::to_value(entry),
|
|
23
|
+
Either25::K(entry) => serde_json::to_value(entry),
|
|
24
|
+
Either25::L(entry) => serde_json::to_value(entry),
|
|
25
|
+
Either25::M(entry) => serde_json::to_value(entry),
|
|
26
|
+
Either25::N(entry) => serde_json::to_value(entry),
|
|
27
|
+
Either25::O(entry) => serde_json::to_value(entry),
|
|
28
|
+
Either25::P(entry) => serde_json::to_value(entry),
|
|
29
|
+
Either25::Q(entry) => serde_json::to_value(entry),
|
|
30
|
+
Either25::R(entry) => serde_json::to_value(entry),
|
|
31
|
+
Either25::S(entry) => serde_json::to_value(entry),
|
|
32
|
+
Either25::T(entry) => serde_json::to_value(entry),
|
|
33
|
+
Either25::U(entry) => serde_json::to_value(entry),
|
|
34
|
+
Either25::V(entry) => serde_json::to_value(entry),
|
|
35
|
+
Either25::W(entry) => serde_json::to_value(entry),
|
|
36
|
+
Either25::X(entry) => serde_json::to_value(entry),
|
|
37
|
+
Either25::Y(entry) => serde_json::to_value(entry),
|
|
37
38
|
// Decode the error message from the return data
|
|
38
|
-
|
|
39
|
+
Either25::E(entry @ RevertErrorStackTraceEntry { .. }) => {
|
|
39
40
|
use serde::de::Error;
|
|
40
41
|
|
|
41
42
|
let decoded_error_msg = ReturnData::new(entry.return_data.clone())
|
|
@@ -45,7 +46,9 @@ fn print_stack_trace(trace: SolidityStackTrace) -> napi::Result<()> {
|
|
|
45
46
|
})?;
|
|
46
47
|
|
|
47
48
|
let mut value = serde_json::to_value(entry)?;
|
|
48
|
-
|
|
49
|
+
if let Some(obj) = value.as_object_mut() {
|
|
50
|
+
obj.insert("message".to_string(), decoded_error_msg.into());
|
|
51
|
+
}
|
|
49
52
|
Ok(value)
|
|
50
53
|
}
|
|
51
54
|
})
|
package/src/trace/exit.rs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
use std::fmt;
|
|
5
5
|
|
|
6
|
+
use edr_evm_spec::EvmHaltReason;
|
|
6
7
|
use napi_derive::napi;
|
|
7
8
|
|
|
8
9
|
#[napi]
|
|
@@ -50,20 +51,20 @@ impl fmt::Display for ExitCode {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
#[allow(clippy::fallible_impl_from)] // naively ported for now
|
|
53
|
-
impl From<edr_solidity::exit_code::ExitCode<
|
|
54
|
-
fn from(code: edr_solidity::exit_code::ExitCode<
|
|
54
|
+
impl From<edr_solidity::exit_code::ExitCode<EvmHaltReason>> for ExitCode {
|
|
55
|
+
fn from(code: edr_solidity::exit_code::ExitCode<EvmHaltReason>) -> Self {
|
|
55
56
|
use edr_solidity::exit_code::ExitCode;
|
|
56
57
|
|
|
57
58
|
match code {
|
|
58
59
|
ExitCode::Success => Self::SUCCESS,
|
|
59
60
|
ExitCode::Revert => Self::REVERT,
|
|
60
|
-
ExitCode::Halt(
|
|
61
|
-
ExitCode::Halt(
|
|
61
|
+
ExitCode::Halt(EvmHaltReason::OutOfGas(_)) => Self::OUT_OF_GAS,
|
|
62
|
+
ExitCode::Halt(EvmHaltReason::OpcodeNotFound | EvmHaltReason::InvalidFEOpcode
|
|
62
63
|
// Returned when an opcode is not implemented for the hardfork
|
|
63
|
-
|
|
|
64
|
-
ExitCode::Halt(
|
|
65
|
-
ExitCode::Halt(
|
|
66
|
-
ExitCode::Halt(
|
|
64
|
+
| EvmHaltReason::NotActivated) => Self::INVALID_OPCODE,
|
|
65
|
+
ExitCode::Halt(EvmHaltReason::StackUnderflow) => Self::STACK_UNDERFLOW,
|
|
66
|
+
ExitCode::Halt(EvmHaltReason::CreateContractSizeLimit) => Self::CODESIZE_EXCEEDS_MAXIMUM,
|
|
67
|
+
ExitCode::Halt(EvmHaltReason::CreateCollision) => Self::CREATE_COLLISION,
|
|
67
68
|
_ => Self::UNKNOWN_HALT_REASON,
|
|
68
69
|
}
|
|
69
70
|
}
|