@nomicfoundation/edr 0.12.0-next.2 → 0.12.0-next.20
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 +220 -62
- package/index.js +5 -1
- package/package.json +12 -12
- package/src/account.rs +7 -6
- 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 +93 -81
- package/src/chains/op.rs +140 -115
- package/src/config.rs +182 -15
- package/src/context.rs +69 -73
- 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 +7 -7
- package/src/provider/response.rs +4 -4
- package/src/provider.rs +51 -4
- package/src/result.rs +42 -83
- package/src/serde.rs +1 -1
- package/src/solidity_tests/config.rs +93 -19
- package/src/solidity_tests/l1.rs +11 -7
- package/src/solidity_tests/op.rs +11 -8
- package/src/solidity_tests/runner.rs +1 -1
- package/src/solidity_tests/test_results.rs +122 -37
- 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 +11 -10
- package/src/withdrawal.rs +5 -5
package/src/provider.rs
CHANGED
|
@@ -5,18 +5,18 @@ mod response;
|
|
|
5
5
|
use std::sync::Arc;
|
|
6
6
|
|
|
7
7
|
use edr_napi_core::provider::SyncProvider;
|
|
8
|
-
use edr_solidity::
|
|
8
|
+
use edr_solidity::compiler::create_models_and_decode_bytecodes;
|
|
9
9
|
use napi::{tokio::runtime, Env, JsFunction, JsObject, Status};
|
|
10
10
|
use napi_derive::napi;
|
|
11
11
|
|
|
12
12
|
pub use self::factory::ProviderFactory;
|
|
13
13
|
use self::response::Response;
|
|
14
|
-
use crate::call_override::CallOverrideCallback;
|
|
14
|
+
use crate::{call_override::CallOverrideCallback, contract_decoder::ContractDecoder};
|
|
15
15
|
|
|
16
16
|
/// A JSON-RPC provider for Ethereum.
|
|
17
17
|
#[napi]
|
|
18
18
|
pub struct Provider {
|
|
19
|
-
contract_decoder: Arc<ContractDecoder>,
|
|
19
|
+
contract_decoder: Arc<edr_solidity::contract_decoder::ContractDecoder>,
|
|
20
20
|
provider: Arc<dyn SyncProvider>,
|
|
21
21
|
runtime: runtime::Handle,
|
|
22
22
|
#[cfg(feature = "scenarios")]
|
|
@@ -28,7 +28,7 @@ impl Provider {
|
|
|
28
28
|
pub fn new(
|
|
29
29
|
provider: Arc<dyn SyncProvider>,
|
|
30
30
|
runtime: runtime::Handle,
|
|
31
|
-
contract_decoder: Arc<ContractDecoder>,
|
|
31
|
+
contract_decoder: Arc<edr_solidity::contract_decoder::ContractDecoder>,
|
|
32
32
|
#[cfg(feature = "scenarios")] scenario_file: Option<
|
|
33
33
|
napi::tokio::sync::Mutex<napi::tokio::fs::File>,
|
|
34
34
|
>,
|
|
@@ -45,6 +45,53 @@ impl Provider {
|
|
|
45
45
|
|
|
46
46
|
#[napi]
|
|
47
47
|
impl Provider {
|
|
48
|
+
#[doc = "Adds a compilation result to the instance."]
|
|
49
|
+
#[doc = ""]
|
|
50
|
+
#[doc = "For internal use only. Support for this method may be removed in the future."]
|
|
51
|
+
#[napi(catch_unwind)]
|
|
52
|
+
pub async fn add_compilation_result(
|
|
53
|
+
&self,
|
|
54
|
+
solc_version: String,
|
|
55
|
+
compiler_input: serde_json::Value,
|
|
56
|
+
compiler_output: serde_json::Value,
|
|
57
|
+
) -> napi::Result<()> {
|
|
58
|
+
let contract_decoder = self.contract_decoder.clone();
|
|
59
|
+
|
|
60
|
+
self.runtime
|
|
61
|
+
.spawn_blocking(move || {
|
|
62
|
+
let compiler_input = serde_json::from_value(compiler_input)
|
|
63
|
+
.map_err(|error| napi::Error::from_reason(error.to_string()))?;
|
|
64
|
+
|
|
65
|
+
let compiler_output = serde_json::from_value(compiler_output)
|
|
66
|
+
.map_err(|error| napi::Error::from_reason(error.to_string()))?;
|
|
67
|
+
|
|
68
|
+
let contracts = match create_models_and_decode_bytecodes(
|
|
69
|
+
solc_version,
|
|
70
|
+
&compiler_input,
|
|
71
|
+
&compiler_output,
|
|
72
|
+
) {
|
|
73
|
+
Ok(contracts) => contracts,
|
|
74
|
+
Err(error) => {
|
|
75
|
+
return Err(napi::Error::from_reason(format!("Contract decoder failed to be updated. Please report this to help us improve Hardhat.\n{error}")));
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
for contract in contracts {
|
|
80
|
+
contract_decoder.add_contract_metadata(contract);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Ok(())
|
|
84
|
+
})
|
|
85
|
+
.await
|
|
86
|
+
.map_err(|error| napi::Error::new(Status::GenericFailure, error.to_string()))?
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#[doc = "Retrieves the instance's contract decoder."]
|
|
90
|
+
#[napi(catch_unwind)]
|
|
91
|
+
pub fn contract_decoder(&self) -> ContractDecoder {
|
|
92
|
+
ContractDecoder::from(Arc::clone(&self.contract_decoder))
|
|
93
|
+
}
|
|
94
|
+
|
|
48
95
|
#[doc = "Handles a JSON-RPC request and returns a JSON-RPC response."]
|
|
49
96
|
#[napi(catch_unwind)]
|
|
50
97
|
pub async fn handle_request(&self, request: String) -> napi::Result<Response> {
|
package/src/result.rs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
use
|
|
1
|
+
use edr_chain_spec::EvmHaltReason;
|
|
2
|
+
use edr_tracing::AfterMessage;
|
|
2
3
|
use napi::{
|
|
3
4
|
bindgen_prelude::{BigInt, Either3, Uint8Array},
|
|
4
5
|
Either,
|
|
@@ -16,27 +17,24 @@ pub enum SuccessReason {
|
|
|
16
17
|
Return,
|
|
17
18
|
/// The opcode `SELFDESTRUCT` was called
|
|
18
19
|
SelfDestruct,
|
|
19
|
-
EofReturnContract,
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
impl From<
|
|
23
|
-
fn from(eval:
|
|
22
|
+
impl From<edr_chain_spec_evm::result::SuccessReason> for SuccessReason {
|
|
23
|
+
fn from(eval: edr_chain_spec_evm::result::SuccessReason) -> Self {
|
|
24
24
|
match eval {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
edr_eth::result::SuccessReason::EofReturnContract => Self::EofReturnContract,
|
|
25
|
+
edr_chain_spec_evm::result::SuccessReason::Stop => Self::Stop,
|
|
26
|
+
edr_chain_spec_evm::result::SuccessReason::Return => Self::Return,
|
|
27
|
+
edr_chain_spec_evm::result::SuccessReason::SelfDestruct => Self::SelfDestruct,
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
impl From<SuccessReason> for
|
|
32
|
+
impl From<SuccessReason> for edr_chain_spec_evm::result::SuccessReason {
|
|
34
33
|
fn from(value: SuccessReason) -> Self {
|
|
35
34
|
match value {
|
|
36
35
|
SuccessReason::Stop => Self::Stop,
|
|
37
36
|
SuccessReason::Return => Self::Return,
|
|
38
37
|
SuccessReason::SelfDestruct => Self::SelfDestruct,
|
|
39
|
-
SuccessReason::EofReturnContract => Self::EofReturnContract,
|
|
40
38
|
}
|
|
41
39
|
}
|
|
42
40
|
}
|
|
@@ -100,81 +98,40 @@ pub enum ExceptionalHalt {
|
|
|
100
98
|
CreateContractStartingWithEF,
|
|
101
99
|
/// EIP-3860: Limit and meter initcode. Initcode size limit exceeded.
|
|
102
100
|
CreateInitCodeSizeLimit,
|
|
103
|
-
/// Aux data overflow, new aux data is larger tha u16 max size.
|
|
104
|
-
EofAuxDataOverflow,
|
|
105
|
-
/// Aud data is smaller then already present data size.
|
|
106
|
-
EofAuxDataTooSmall,
|
|
107
|
-
/// EOF Subroutine stack overflow
|
|
108
|
-
SubRoutineStackOverflow,
|
|
109
|
-
/// Check for target address validity is only done inside subcall.
|
|
110
|
-
InvalidEXTCALLTarget,
|
|
111
101
|
}
|
|
112
102
|
|
|
113
|
-
impl From<
|
|
114
|
-
fn from(halt:
|
|
103
|
+
impl From<EvmHaltReason> for ExceptionalHalt {
|
|
104
|
+
fn from(halt: EvmHaltReason) -> Self {
|
|
115
105
|
match halt {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
edr_eth::l1::HaltReason::CreateContractSizeLimit => {
|
|
128
|
-
ExceptionalHalt::CreateContractSizeLimit
|
|
106
|
+
EvmHaltReason::OutOfGas(..) => ExceptionalHalt::OutOfGas,
|
|
107
|
+
EvmHaltReason::OpcodeNotFound => ExceptionalHalt::OpcodeNotFound,
|
|
108
|
+
EvmHaltReason::InvalidFEOpcode => ExceptionalHalt::InvalidFEOpcode,
|
|
109
|
+
EvmHaltReason::InvalidJump => ExceptionalHalt::InvalidJump,
|
|
110
|
+
EvmHaltReason::NotActivated => ExceptionalHalt::NotActivated,
|
|
111
|
+
EvmHaltReason::StackUnderflow => ExceptionalHalt::StackUnderflow,
|
|
112
|
+
EvmHaltReason::StackOverflow => ExceptionalHalt::StackOverflow,
|
|
113
|
+
EvmHaltReason::OutOfOffset => ExceptionalHalt::OutOfOffset,
|
|
114
|
+
EvmHaltReason::CreateCollision => ExceptionalHalt::CreateCollision,
|
|
115
|
+
EvmHaltReason::PrecompileError | EvmHaltReason::PrecompileErrorWithContext(_) => {
|
|
116
|
+
ExceptionalHalt::PrecompileError
|
|
129
117
|
}
|
|
130
|
-
|
|
118
|
+
EvmHaltReason::NonceOverflow => ExceptionalHalt::NonceOverflow,
|
|
119
|
+
EvmHaltReason::CreateContractSizeLimit => ExceptionalHalt::CreateContractSizeLimit,
|
|
120
|
+
EvmHaltReason::CreateContractStartingWithEF => {
|
|
131
121
|
ExceptionalHalt::CreateContractStartingWithEF
|
|
132
122
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
ExceptionalHalt::SubRoutineStackOverflow
|
|
140
|
-
}
|
|
141
|
-
edr_eth::l1::HaltReason::InvalidEXTCALLTarget => ExceptionalHalt::InvalidEXTCALLTarget,
|
|
142
|
-
edr_eth::l1::HaltReason::OverflowPayment
|
|
143
|
-
| edr_eth::l1::HaltReason::StateChangeDuringStaticCall
|
|
144
|
-
| edr_eth::l1::HaltReason::CallNotAllowedInsideStatic
|
|
145
|
-
| edr_eth::l1::HaltReason::OutOfFunds
|
|
146
|
-
| edr_eth::l1::HaltReason::CallTooDeep => {
|
|
123
|
+
EvmHaltReason::CreateInitCodeSizeLimit => ExceptionalHalt::CreateInitCodeSizeLimit,
|
|
124
|
+
EvmHaltReason::OverflowPayment
|
|
125
|
+
| EvmHaltReason::StateChangeDuringStaticCall
|
|
126
|
+
| EvmHaltReason::CallNotAllowedInsideStatic
|
|
127
|
+
| EvmHaltReason::OutOfFunds
|
|
128
|
+
| EvmHaltReason::CallTooDeep => {
|
|
147
129
|
unreachable!("Internal halts that can be only found inside Inspector: {halt:?}")
|
|
148
130
|
}
|
|
149
131
|
}
|
|
150
132
|
}
|
|
151
133
|
}
|
|
152
134
|
|
|
153
|
-
impl From<ExceptionalHalt> for edr_eth::l1::HaltReason {
|
|
154
|
-
fn from(value: ExceptionalHalt) -> Self {
|
|
155
|
-
match value {
|
|
156
|
-
ExceptionalHalt::OutOfGas => Self::OutOfGas(edr_eth::l1::OutOfGasError::Basic),
|
|
157
|
-
ExceptionalHalt::OpcodeNotFound => Self::OpcodeNotFound,
|
|
158
|
-
ExceptionalHalt::InvalidFEOpcode => Self::InvalidFEOpcode,
|
|
159
|
-
ExceptionalHalt::InvalidJump => Self::InvalidJump,
|
|
160
|
-
ExceptionalHalt::NotActivated => Self::NotActivated,
|
|
161
|
-
ExceptionalHalt::StackUnderflow => Self::StackUnderflow,
|
|
162
|
-
ExceptionalHalt::StackOverflow => Self::StackOverflow,
|
|
163
|
-
ExceptionalHalt::OutOfOffset => Self::OutOfOffset,
|
|
164
|
-
ExceptionalHalt::CreateCollision => Self::CreateCollision,
|
|
165
|
-
ExceptionalHalt::PrecompileError => Self::PrecompileError,
|
|
166
|
-
ExceptionalHalt::NonceOverflow => Self::NonceOverflow,
|
|
167
|
-
ExceptionalHalt::CreateContractSizeLimit => Self::CreateContractSizeLimit,
|
|
168
|
-
ExceptionalHalt::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
|
|
169
|
-
ExceptionalHalt::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
|
|
170
|
-
ExceptionalHalt::EofAuxDataOverflow => Self::EofAuxDataOverflow,
|
|
171
|
-
ExceptionalHalt::EofAuxDataTooSmall => Self::EofAuxDataTooSmall,
|
|
172
|
-
ExceptionalHalt::SubRoutineStackOverflow => Self::SubRoutineStackOverflow,
|
|
173
|
-
ExceptionalHalt::InvalidEXTCALLTarget => Self::InvalidEXTCALLTarget,
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
135
|
/// The result when the EVM terminates due to an exceptional halt.
|
|
179
136
|
#[napi(object)]
|
|
180
137
|
pub struct HaltResult {
|
|
@@ -194,15 +151,15 @@ pub struct ExecutionResult {
|
|
|
194
151
|
pub contract_address: Option<Uint8Array>,
|
|
195
152
|
}
|
|
196
153
|
|
|
197
|
-
impl From<&AfterMessage<
|
|
198
|
-
fn from(value: &AfterMessage<
|
|
154
|
+
impl From<&AfterMessage<EvmHaltReason>> for ExecutionResult {
|
|
155
|
+
fn from(value: &AfterMessage<EvmHaltReason>) -> Self {
|
|
199
156
|
let AfterMessage {
|
|
200
157
|
execution_result,
|
|
201
158
|
contract_address,
|
|
202
159
|
} = value;
|
|
203
160
|
|
|
204
161
|
let result = match execution_result {
|
|
205
|
-
|
|
162
|
+
edr_chain_spec_evm::result::ExecutionResult::Success {
|
|
206
163
|
reason,
|
|
207
164
|
gas_used,
|
|
208
165
|
gas_refunded,
|
|
@@ -217,12 +174,12 @@ impl From<&AfterMessage<edr_eth::l1::HaltReason>> for ExecutionResult {
|
|
|
217
174
|
gas_refunded: BigInt::from(*gas_refunded),
|
|
218
175
|
logs,
|
|
219
176
|
output: match output {
|
|
220
|
-
|
|
177
|
+
edr_chain_spec_evm::result::Output::Call(return_value) => {
|
|
221
178
|
let return_value = Uint8Array::with_data_copied(return_value);
|
|
222
179
|
|
|
223
180
|
Either::A(CallOutput { return_value })
|
|
224
181
|
}
|
|
225
|
-
|
|
182
|
+
edr_chain_spec_evm::result::Output::Create(return_value, address) => {
|
|
226
183
|
let return_value = Uint8Array::with_data_copied(return_value);
|
|
227
184
|
|
|
228
185
|
Either::B(CreateOutput {
|
|
@@ -233,7 +190,7 @@ impl From<&AfterMessage<edr_eth::l1::HaltReason>> for ExecutionResult {
|
|
|
233
190
|
},
|
|
234
191
|
})
|
|
235
192
|
}
|
|
236
|
-
|
|
193
|
+
edr_chain_spec_evm::result::ExecutionResult::Revert { gas_used, output } => {
|
|
237
194
|
let output = Uint8Array::with_data_copied(output);
|
|
238
195
|
|
|
239
196
|
Either3::B(RevertResult {
|
|
@@ -241,10 +198,12 @@ impl From<&AfterMessage<edr_eth::l1::HaltReason>> for ExecutionResult {
|
|
|
241
198
|
output,
|
|
242
199
|
})
|
|
243
200
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
201
|
+
edr_chain_spec_evm::result::ExecutionResult::Halt { reason, gas_used } => {
|
|
202
|
+
Either3::C(HaltResult {
|
|
203
|
+
reason: ExceptionalHalt::from(reason.clone()),
|
|
204
|
+
gas_used: BigInt::from(*gas_used),
|
|
205
|
+
})
|
|
206
|
+
}
|
|
248
207
|
};
|
|
249
208
|
|
|
250
209
|
let contract_address = contract_address.as_ref().map(Uint8Array::with_data_copied);
|
package/src/serde.rs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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,
|
|
8
8
|
inspectors::cheatcodes::{CheatsConfigOptions, ExecutionContextConfig},
|
|
9
9
|
TestFilterConfig,
|
|
10
10
|
};
|
|
11
|
-
use foundry_cheatcodes::{FsPermissions,
|
|
11
|
+
use foundry_cheatcodes::{FsPermissions, RpcEndpointUrl, RpcEndpoints};
|
|
12
12
|
use napi::{
|
|
13
13
|
bindgen_prelude::{BigInt, Uint8Array},
|
|
14
14
|
tokio::runtime,
|
|
@@ -36,8 +36,6 @@ pub struct SolidityTestRunnerConfigArgs {
|
|
|
36
36
|
pub project_root: String,
|
|
37
37
|
/// Configures the permissions of cheat codes that access the file system.
|
|
38
38
|
pub fs_permissions: Option<Vec<PathPermission>>,
|
|
39
|
-
/// Whether to support the `testFail` prefix. Defaults to false.
|
|
40
|
-
pub test_fail: Option<bool>,
|
|
41
39
|
/// Address labels for traces. Defaults to none.
|
|
42
40
|
pub labels: Option<Vec<AddressLabel>>,
|
|
43
41
|
/// Whether to enable isolation of calls. In isolation mode all top-level
|
|
@@ -109,7 +107,7 @@ pub struct SolidityTestRunnerConfigArgs {
|
|
|
109
107
|
/// Defaults to false.
|
|
110
108
|
pub disable_block_gas_limit: Option<bool>,
|
|
111
109
|
/// The memory limit of the EVM in bytes.
|
|
112
|
-
/// Defaults to 33_554_432 (2^25 = 32MiB).
|
|
110
|
+
/// Defaults to `33_554_432` (2^25 = 32MiB).
|
|
113
111
|
#[serde(serialize_with = "serialize_optional_bigint_as_struct")]
|
|
114
112
|
pub memory_limit: Option<BigInt>,
|
|
115
113
|
/// The predeploys applied in local mode. Defaults to no predeploys.
|
|
@@ -143,6 +141,8 @@ pub struct SolidityTestRunnerConfigArgs {
|
|
|
143
141
|
/// If an invariant config setting is not set, but a corresponding fuzz
|
|
144
142
|
/// config value is set, then the fuzz config value will be used.
|
|
145
143
|
pub invariant: Option<InvariantConfigArgs>,
|
|
144
|
+
/// Whether to collect stack traces.
|
|
145
|
+
pub collect_stack_traces: Option<CollectStackTraces>,
|
|
146
146
|
/// Controls which test results should include execution traces. Defaults to
|
|
147
147
|
/// None.
|
|
148
148
|
pub include_traces: Option<IncludeTraces>,
|
|
@@ -153,6 +153,11 @@ pub struct SolidityTestRunnerConfigArgs {
|
|
|
153
153
|
/// A regex pattern to filter tests. If provided, only test methods that
|
|
154
154
|
/// match the pattern will be executed and reported as a test result.
|
|
155
155
|
pub test_pattern: Option<String>,
|
|
156
|
+
/// Controls whether to generate a gas report after running the tests.
|
|
157
|
+
/// Enabling this also enables collection of all traces and EVM isolation
|
|
158
|
+
/// mode.
|
|
159
|
+
/// Defaults to false.
|
|
160
|
+
pub generate_gas_report: Option<bool>,
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
impl SolidityTestRunnerConfigArgs {
|
|
@@ -166,7 +171,6 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
166
171
|
let SolidityTestRunnerConfigArgs {
|
|
167
172
|
project_root,
|
|
168
173
|
fs_permissions,
|
|
169
|
-
test_fail,
|
|
170
174
|
labels,
|
|
171
175
|
isolate,
|
|
172
176
|
ffi,
|
|
@@ -194,9 +198,11 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
194
198
|
prompt_timeout,
|
|
195
199
|
fuzz,
|
|
196
200
|
invariant,
|
|
201
|
+
collect_stack_traces,
|
|
197
202
|
include_traces,
|
|
198
203
|
observability,
|
|
199
204
|
test_pattern,
|
|
205
|
+
generate_gas_report,
|
|
200
206
|
} = self;
|
|
201
207
|
|
|
202
208
|
let test_pattern = TestFilterConfig {
|
|
@@ -237,7 +243,7 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
237
243
|
RpcEndpoints::new(
|
|
238
244
|
endpoints
|
|
239
245
|
.into_iter()
|
|
240
|
-
.map(|(chain, url)| (chain,
|
|
246
|
+
.map(|(chain, url)| (chain, RpcEndpointUrl::new(url))),
|
|
241
247
|
)
|
|
242
248
|
})
|
|
243
249
|
.unwrap_or_default(),
|
|
@@ -258,6 +264,7 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
258
264
|
.into_iter()
|
|
259
265
|
.map(|AddressLabel { address, label }| Ok((address.try_cast()?, label)))
|
|
260
266
|
.collect::<Result<_, napi::Error>>()?,
|
|
267
|
+
seed: fuzz.seed,
|
|
261
268
|
allow_internal_expect_revert: allow_internal_expect_revert.unwrap_or(false),
|
|
262
269
|
};
|
|
263
270
|
|
|
@@ -273,7 +280,6 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
273
280
|
let config = edr_napi_core::solidity::config::TestRunnerConfig {
|
|
274
281
|
project_root: project_root.into(),
|
|
275
282
|
include_traces: include_traces.unwrap_or_default().into(),
|
|
276
|
-
test_fail: test_fail.unwrap_or_default(),
|
|
277
283
|
isolate,
|
|
278
284
|
ffi,
|
|
279
285
|
sender: sender.map(TryCast::try_cast).transpose()?,
|
|
@@ -296,8 +302,13 @@ impl SolidityTestRunnerConfigArgs {
|
|
|
296
302
|
cheatcode,
|
|
297
303
|
fuzz,
|
|
298
304
|
invariant,
|
|
305
|
+
collect_stack_traces: collect_stack_traces.map_or(
|
|
306
|
+
edr_solidity_tests::CollectStackTraces::OnFailure,
|
|
307
|
+
edr_solidity_tests::CollectStackTraces::from,
|
|
308
|
+
),
|
|
299
309
|
on_collected_coverage_fn,
|
|
300
310
|
test_pattern,
|
|
311
|
+
generate_gas_report,
|
|
301
312
|
};
|
|
302
313
|
|
|
303
314
|
Ok(config)
|
|
@@ -356,7 +367,7 @@ impl TryFrom<FuzzConfigArgs> for FuzzConfig {
|
|
|
356
367
|
} = value;
|
|
357
368
|
|
|
358
369
|
let failure_persist_dir = failure_persist_dir.map(PathBuf::from);
|
|
359
|
-
let failure_persist_file = failure_persist_file.
|
|
370
|
+
let failure_persist_file = failure_persist_file.unwrap_or_else(|| "failures".to_string());
|
|
360
371
|
let seed = seed
|
|
361
372
|
.map(|s| {
|
|
362
373
|
s.parse().map_err(|_err| {
|
|
@@ -447,6 +458,10 @@ pub struct InvariantConfigArgs {
|
|
|
447
458
|
/// process is disabled if set to 0.
|
|
448
459
|
/// Defaults to 5000.
|
|
449
460
|
pub shrink_run_limit: Option<u32>,
|
|
461
|
+
/// The maximum number of rejects via `vm.assume` which can be encountered
|
|
462
|
+
/// during a single invariant run.
|
|
463
|
+
/// Defaults to 65536.
|
|
464
|
+
pub max_assume_rejects: Option<u32>,
|
|
450
465
|
}
|
|
451
466
|
|
|
452
467
|
impl InvariantConfigArgs {
|
|
@@ -500,6 +515,7 @@ impl From<InvariantConfigArgs> for InvariantConfig {
|
|
|
500
515
|
include_storage,
|
|
501
516
|
include_push_bytes,
|
|
502
517
|
shrink_run_limit,
|
|
518
|
+
max_assume_rejects,
|
|
503
519
|
} = value;
|
|
504
520
|
|
|
505
521
|
let failure_persist_dir = failure_persist_dir.map(PathBuf::from);
|
|
@@ -543,6 +559,10 @@ impl From<InvariantConfigArgs> for InvariantConfig {
|
|
|
543
559
|
invariant.shrink_run_limit = shrink_run_limit;
|
|
544
560
|
}
|
|
545
561
|
|
|
562
|
+
if let Some(max_assume_rejects) = max_assume_rejects {
|
|
563
|
+
invariant.max_assume_rejects = max_assume_rejects;
|
|
564
|
+
}
|
|
565
|
+
|
|
546
566
|
invariant
|
|
547
567
|
}
|
|
548
568
|
}
|
|
@@ -657,24 +677,55 @@ impl From<PathPermission> for foundry_cheatcodes::PathPermission {
|
|
|
657
677
|
}
|
|
658
678
|
}
|
|
659
679
|
|
|
660
|
-
|
|
680
|
+
/**
|
|
681
|
+
* Determines the level of file system access for the given path.
|
|
682
|
+
*
|
|
683
|
+
* Exact path matching is used for file permissions. Prefix matching is used
|
|
684
|
+
* for directory permissions.
|
|
685
|
+
*
|
|
686
|
+
* Giving write access to configuration files, source files or executables
|
|
687
|
+
* in a project is considered dangerous, because it can be used by malicious
|
|
688
|
+
* Solidity dependencies to escape the EVM sandbox. It is therefore
|
|
689
|
+
* recommended to give write access to specific safe files only. If write
|
|
690
|
+
* access to a directory is needed, please make sure that it doesn't contain
|
|
691
|
+
* configuration files, source files or executables neither in the top level
|
|
692
|
+
* directory, nor in any subdirectories.
|
|
693
|
+
*/
|
|
661
694
|
#[napi]
|
|
662
695
|
#[derive(Debug, serde::Serialize)]
|
|
663
696
|
pub enum FsAccessPermission {
|
|
664
|
-
///
|
|
665
|
-
|
|
666
|
-
/// Only reading
|
|
667
|
-
|
|
668
|
-
/// Only writing
|
|
669
|
-
|
|
697
|
+
/// Allows reading and writing the file
|
|
698
|
+
ReadWriteFile,
|
|
699
|
+
/// Only allows reading the file
|
|
700
|
+
ReadFile,
|
|
701
|
+
/// Only allows writing the file
|
|
702
|
+
WriteFile,
|
|
703
|
+
/// Allows reading and writing all files in the directory and its
|
|
704
|
+
/// subdirectories
|
|
705
|
+
DangerouslyReadWriteDirectory,
|
|
706
|
+
/// Allows reading all files in the directory and its subdirectories
|
|
707
|
+
ReadDirectory,
|
|
708
|
+
/// Allows writing all files in the directory and its subdirectories
|
|
709
|
+
DangerouslyWriteDirectory,
|
|
670
710
|
}
|
|
671
711
|
|
|
672
712
|
impl From<FsAccessPermission> for foundry_cheatcodes::FsAccessPermission {
|
|
673
713
|
fn from(value: FsAccessPermission) -> Self {
|
|
674
714
|
match value {
|
|
675
|
-
FsAccessPermission::
|
|
676
|
-
|
|
677
|
-
|
|
715
|
+
FsAccessPermission::ReadWriteFile => {
|
|
716
|
+
foundry_cheatcodes::FsAccessPermission::ReadWriteFile
|
|
717
|
+
}
|
|
718
|
+
FsAccessPermission::ReadFile => foundry_cheatcodes::FsAccessPermission::ReadFile,
|
|
719
|
+
FsAccessPermission::WriteFile => foundry_cheatcodes::FsAccessPermission::WriteFile,
|
|
720
|
+
FsAccessPermission::DangerouslyReadWriteDirectory => {
|
|
721
|
+
foundry_cheatcodes::FsAccessPermission::DangerouslyReadWriteDirectory
|
|
722
|
+
}
|
|
723
|
+
FsAccessPermission::ReadDirectory => {
|
|
724
|
+
foundry_cheatcodes::FsAccessPermission::ReadDirectory
|
|
725
|
+
}
|
|
726
|
+
FsAccessPermission::DangerouslyWriteDirectory => {
|
|
727
|
+
foundry_cheatcodes::FsAccessPermission::DangerouslyWriteDirectory
|
|
728
|
+
}
|
|
678
729
|
}
|
|
679
730
|
}
|
|
680
731
|
}
|
|
@@ -690,6 +741,29 @@ pub struct AddressLabel {
|
|
|
690
741
|
pub label: String,
|
|
691
742
|
}
|
|
692
743
|
|
|
744
|
+
/// A type that controls when stack traces are collected.
|
|
745
|
+
#[napi]
|
|
746
|
+
#[derive(Debug, serde::Serialize)]
|
|
747
|
+
pub enum CollectStackTraces {
|
|
748
|
+
/// Always collects stack traces, adding performance overhead.
|
|
749
|
+
Always,
|
|
750
|
+
/// Only collects stack traces upon failure, re-executing the test. This
|
|
751
|
+
/// minimizes performance overhead.
|
|
752
|
+
///
|
|
753
|
+
/// Not all tests can be re-executed since certain cheatcodes contain
|
|
754
|
+
/// non-deterministic side-effects.
|
|
755
|
+
OnFailure,
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
impl From<CollectStackTraces> for edr_solidity_tests::CollectStackTraces {
|
|
759
|
+
fn from(value: CollectStackTraces) -> Self {
|
|
760
|
+
match value {
|
|
761
|
+
CollectStackTraces::Always => edr_solidity_tests::CollectStackTraces::Always,
|
|
762
|
+
CollectStackTraces::OnFailure => edr_solidity_tests::CollectStackTraces::OnFailure,
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
693
767
|
/// Configuration for [`SolidityTestRunnerConfigArgs::include_traces`] that
|
|
694
768
|
/// controls execution trace decoding and inclusion in test results.
|
|
695
769
|
#[napi]
|
package/src/solidity_tests/l1.rs
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
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
|
-
contracts::ContractsByArtifact,
|
|
11
|
-
|
|
10
|
+
contracts::ContractsByArtifact,
|
|
11
|
+
decode::RevertDecoder,
|
|
12
|
+
evm_context::L1EvmBuilder,
|
|
13
|
+
multi_runner::TestContract,
|
|
14
|
+
revm::context::{BlockEnv, TxEnv},
|
|
15
|
+
MultiContractRunner,
|
|
12
16
|
};
|
|
13
17
|
use napi::tokio;
|
|
14
18
|
use napi_derive::napi;
|
|
@@ -33,13 +37,13 @@ impl SyncTestRunnerFactory for L1TestRunnerFactory {
|
|
|
33
37
|
let runner = tokio::task::block_in_place(|| {
|
|
34
38
|
runtime
|
|
35
39
|
.block_on(MultiContractRunner::<
|
|
36
|
-
|
|
40
|
+
BlockEnv,
|
|
37
41
|
(),
|
|
38
42
|
L1EvmBuilder,
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
edr_chain_l1::HaltReason,
|
|
44
|
+
edr_chain_l1::Hardfork,
|
|
41
45
|
_,
|
|
42
|
-
|
|
46
|
+
edr_chain_l1::InvalidTransaction,
|
|
43
47
|
TxEnv,
|
|
44
48
|
>::new(
|
|
45
49
|
config.try_into()?,
|
package/src/solidity_tests/op.rs
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
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
|
-
use edr_op::solidity_tests::OpEvmBuilder;
|
|
7
|
+
use edr_op::{solidity_tests::OpEvmBuilder, transaction::OpTxEnv};
|
|
8
|
+
use edr_primitives::Bytes;
|
|
9
9
|
use edr_solidity::artifacts::ArtifactId;
|
|
10
10
|
use edr_solidity_tests::{
|
|
11
|
-
contracts::ContractsByArtifact,
|
|
11
|
+
contracts::ContractsByArtifact,
|
|
12
|
+
decode::RevertDecoder,
|
|
13
|
+
multi_runner::TestContract,
|
|
14
|
+
revm::context::{BlockEnv, TxEnv},
|
|
12
15
|
MultiContractRunner,
|
|
13
16
|
};
|
|
14
17
|
use napi::tokio;
|
|
@@ -34,14 +37,14 @@ impl SyncTestRunnerFactory for OpTestRunnerFactory {
|
|
|
34
37
|
let runner = tokio::task::block_in_place(|| {
|
|
35
38
|
runtime
|
|
36
39
|
.block_on(MultiContractRunner::<
|
|
37
|
-
|
|
40
|
+
BlockEnv,
|
|
38
41
|
_,
|
|
39
42
|
OpEvmBuilder,
|
|
40
|
-
edr_op::
|
|
41
|
-
edr_op::
|
|
43
|
+
edr_op::HaltReason,
|
|
44
|
+
edr_op::Hardfork,
|
|
42
45
|
_,
|
|
43
|
-
edr_op::
|
|
44
|
-
|
|
46
|
+
edr_op::InvalidTransaction,
|
|
47
|
+
OpTxEnv<TxEnv>,
|
|
45
48
|
>::new(
|
|
46
49
|
config.try_into()?,
|
|
47
50
|
contracts,
|