@nomicfoundation/edr 0.11.3 → 0.12.0-next.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.
Files changed (46) hide show
  1. package/Cargo.toml +61 -27
  2. package/LICENSE +5 -1
  3. package/index.d.ts +875 -137
  4. package/index.js +61 -3
  5. package/package.json +20 -16
  6. package/src/account.rs +109 -32
  7. package/src/block.rs +2 -103
  8. package/src/call_override.rs +7 -7
  9. package/src/cast.rs +47 -17
  10. package/src/chains/generic.rs +51 -0
  11. package/src/chains/l1.rs +262 -0
  12. package/src/chains/op.rs +425 -0
  13. package/src/chains.rs +7 -0
  14. package/src/config.rs +537 -67
  15. package/src/context.rs +374 -17
  16. package/src/debug_trace.rs +2 -2
  17. package/src/instrument.rs +109 -0
  18. package/src/lib.rs +38 -14
  19. package/src/log.rs +12 -14
  20. package/src/logger.rs +77 -1177
  21. package/src/mock.rs +68 -0
  22. package/src/precompile.rs +50 -0
  23. package/src/provider/factory.rs +22 -0
  24. package/src/provider/response.rs +73 -0
  25. package/src/provider.rs +64 -325
  26. package/src/result.rs +60 -69
  27. package/src/scenarios.rs +11 -17
  28. package/src/serde.rs +57 -0
  29. package/src/solidity_tests/artifact.rs +184 -0
  30. package/src/solidity_tests/config.rs +725 -0
  31. package/src/solidity_tests/factory.rs +22 -0
  32. package/src/solidity_tests/l1.rs +68 -0
  33. package/src/solidity_tests/op.rs +69 -0
  34. package/src/solidity_tests/runner.rs +51 -0
  35. package/src/solidity_tests/test_results.rs +668 -0
  36. package/src/solidity_tests.rs +56 -0
  37. package/src/subscription.rs +32 -0
  38. package/src/trace/debug.rs +1 -1
  39. package/src/trace/exit.rs +12 -13
  40. package/src/trace/library_utils.rs +1 -1
  41. package/src/trace/return_data.rs +11 -11
  42. package/src/trace/solidity_stack_trace.rs +11 -8
  43. package/src/trace.rs +37 -44
  44. package/src/withdrawal.rs +4 -4
  45. package/src/provider/config.rs +0 -291
  46. package/src/subscribe.rs +0 -63
package/src/mock.rs ADDED
@@ -0,0 +1,68 @@
1
+ use std::sync::Arc;
2
+
3
+ use edr_napi_core::provider::SyncProvider;
4
+ use edr_rpc_client::jsonrpc;
5
+ use edr_solidity::contract_decoder::ContractDecoder;
6
+ use napi::tokio::runtime;
7
+ use napi_derive::napi;
8
+
9
+ use crate::{context::EdrContext, provider::Provider};
10
+
11
+ /// A mock provider that always returns the given mocked response.
12
+ pub struct MockProvider {
13
+ mocked_response: serde_json::Value,
14
+ }
15
+
16
+ impl MockProvider {
17
+ pub fn new(mocked_response: serde_json::Value) -> Self {
18
+ Self { mocked_response }
19
+ }
20
+ }
21
+
22
+ impl SyncProvider for MockProvider {
23
+ fn handle_request(
24
+ &self,
25
+ _request: String,
26
+ _contract_decoder: Arc<ContractDecoder>,
27
+ ) -> napi::Result<edr_napi_core::spec::Response<edr_eth::l1::HaltReason>> {
28
+ let response = jsonrpc::ResponseData::Success {
29
+ result: self.mocked_response.clone(),
30
+ };
31
+ edr_napi_core::spec::marshal_response_data(response)
32
+ .map(|data| edr_napi_core::spec::Response {
33
+ solidity_trace: None,
34
+ data,
35
+ traces: Vec::new(),
36
+ })
37
+ .map_err(|error| napi::Error::new(napi::Status::GenericFailure, error.to_string()))
38
+ }
39
+
40
+ fn set_call_override_callback(
41
+ &self,
42
+ _call_override_callback: Arc<dyn edr_provider::SyncCallOverride>,
43
+ ) {
44
+ }
45
+
46
+ fn set_verbose_tracing(&self, _enabled: bool) {}
47
+ }
48
+
49
+ #[napi]
50
+ impl EdrContext {
51
+ #[doc = "Creates a mock provider, which always returns the given response."]
52
+ #[doc = "For testing purposes."]
53
+ #[napi]
54
+ pub fn create_mock_provider(
55
+ &self,
56
+ mocked_response: serde_json::Value,
57
+ ) -> napi::Result<Provider> {
58
+ let provider = Provider::new(
59
+ Arc::new(MockProvider::new(mocked_response)),
60
+ runtime::Handle::current(),
61
+ Arc::new(ContractDecoder::default()),
62
+ #[cfg(feature = "scenarios")]
63
+ None,
64
+ );
65
+
66
+ Ok(provider)
67
+ }
68
+ }
@@ -0,0 +1,50 @@
1
+ use edr_eth::Address;
2
+ use edr_evm::precompile::{self, PrecompileFn, PrecompileWithAddress};
3
+ use napi::bindgen_prelude::Uint8Array;
4
+ use napi_derive::napi;
5
+
6
+ #[napi]
7
+ #[derive(Clone)]
8
+ pub struct Precompile {
9
+ address: Address,
10
+ precompile_fn: PrecompileFn,
11
+ }
12
+
13
+ impl Precompile {
14
+ pub fn new(address: Address, precompile_fn: PrecompileFn) -> Self {
15
+ Self {
16
+ address,
17
+ precompile_fn,
18
+ }
19
+ }
20
+
21
+ /// Returns the address and precompile function as a tuple.
22
+ pub fn to_tuple(&self) -> (Address, PrecompileFn) {
23
+ (self.address, self.precompile_fn)
24
+ }
25
+ }
26
+
27
+ impl From<PrecompileWithAddress> for Precompile {
28
+ fn from(value: PrecompileWithAddress) -> Self {
29
+ Self {
30
+ address: value.0,
31
+ precompile_fn: value.1,
32
+ }
33
+ }
34
+ }
35
+
36
+ #[napi]
37
+ impl Precompile {
38
+ /// Returns the address of the precompile.
39
+ #[napi(catch_unwind, getter)]
40
+ pub fn address(&self) -> Uint8Array {
41
+ Uint8Array::with_data_copied(self.address)
42
+ }
43
+ }
44
+
45
+ /// [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md#specification)
46
+ /// secp256r1 precompile.
47
+ #[napi(catch_unwind)]
48
+ pub fn precompile_p256_verify() -> Precompile {
49
+ Precompile::from(precompile::secp256r1::P256VERIFY)
50
+ }
@@ -0,0 +1,22 @@
1
+ use std::sync::Arc;
2
+
3
+ use edr_napi_core::provider::SyncProviderFactory;
4
+ use napi_derive::napi;
5
+
6
+ #[napi]
7
+ pub struct ProviderFactory {
8
+ inner: Arc<dyn SyncProviderFactory>,
9
+ }
10
+
11
+ impl ProviderFactory {
12
+ /// Returns a reference to the inner provider factory.
13
+ pub fn as_inner(&self) -> &Arc<dyn SyncProviderFactory> {
14
+ &self.inner
15
+ }
16
+ }
17
+
18
+ impl From<Arc<dyn SyncProviderFactory>> for ProviderFactory {
19
+ fn from(inner: Arc<dyn SyncProviderFactory>) -> Self {
20
+ Self { inner }
21
+ }
22
+ }
@@ -0,0 +1,73 @@
1
+ use edr_eth::l1;
2
+ use edr_napi_core::spec::SolidityTraceData;
3
+ use edr_solidity::contract_decoder::NestedTraceDecoder as _;
4
+ use napi::Either;
5
+ use napi_derive::napi;
6
+
7
+ use crate::{
8
+ cast::TryCast,
9
+ trace::{solidity_stack_trace::SolidityStackTrace, RawTrace},
10
+ };
11
+
12
+ #[napi]
13
+ pub struct Response {
14
+ inner: edr_napi_core::spec::Response<l1::HaltReason>,
15
+ }
16
+
17
+ impl From<edr_napi_core::spec::Response<l1::HaltReason>> for Response {
18
+ fn from(value: edr_napi_core::spec::Response<l1::HaltReason>) -> Self {
19
+ Self { inner: value }
20
+ }
21
+ }
22
+
23
+ #[napi]
24
+ impl Response {
25
+ #[doc = "Returns the response data as a JSON string or a JSON object."]
26
+ #[napi(catch_unwind, getter)]
27
+ pub fn data(&self) -> Either<String, serde_json::Value> {
28
+ self.inner.data.clone()
29
+ }
30
+
31
+ // Rust port of https://github.com/NomicFoundation/hardhat/blob/c20bf195a6efdc2d74e778b7a4a7799aac224841/packages/hardhat-core/src/internal/hardhat-network/provider/provider.ts#L590
32
+ #[doc = "Compute the error stack trace. Return the stack trace if it can be decoded, otherwise returns none. Throws if there was an error computing the stack trace."]
33
+ #[napi(catch_unwind)]
34
+ pub fn stack_trace(&self) -> napi::Result<Option<SolidityStackTrace>> {
35
+ let Some(SolidityTraceData {
36
+ trace,
37
+ contract_decoder,
38
+ }) = &self.inner.solidity_trace
39
+ else {
40
+ return Ok(None);
41
+ };
42
+ let nested_trace = edr_solidity::nested_tracer::convert_trace_messages_to_nested_trace(
43
+ trace.as_ref().clone(),
44
+ )
45
+ .map_err(|err| napi::Error::from_reason(err.to_string()))?;
46
+
47
+ if let Some(vm_trace) = nested_trace {
48
+ let decoded_trace = contract_decoder
49
+ .try_to_decode_nested_trace(vm_trace)
50
+ .map_err(|err| napi::Error::from_reason(err.to_string()))?;
51
+ let stack_trace = edr_solidity::solidity_tracer::get_stack_trace(decoded_trace)
52
+ .map_err(|err| napi::Error::from_reason(err.to_string()))?;
53
+ let stack_trace = stack_trace
54
+ .into_iter()
55
+ .map(TryCast::try_cast)
56
+ .collect::<Result<Vec<_>, _>>()?;
57
+
58
+ Ok(Some(stack_trace))
59
+ } else {
60
+ Ok(None)
61
+ }
62
+ }
63
+
64
+ #[doc = "Returns the raw traces of executed contracts. This maybe contain zero or more traces."]
65
+ #[napi(catch_unwind, getter)]
66
+ pub fn traces(&self) -> Vec<RawTrace> {
67
+ self.inner
68
+ .traces
69
+ .iter()
70
+ .map(|trace| RawTrace::from(trace.clone()))
71
+ .collect()
72
+ }
73
+ }
package/src/provider.rs CHANGED
@@ -1,376 +1,115 @@
1
- mod config;
1
+ /// Types related to provider factories.
2
+ pub mod factory;
3
+ mod response;
2
4
 
3
5
  use std::sync::Arc;
4
6
 
5
- use edr_provider::{time::CurrentTime, InvalidRequestReason};
6
- use edr_rpc_eth::jsonrpc;
7
+ use edr_napi_core::provider::SyncProvider;
7
8
  use edr_solidity::contract_decoder::ContractDecoder;
8
- use napi::{
9
- bindgen_prelude::Uint8Array, tokio::runtime, Either, Env, JsFunction, JsObject, Status,
10
- };
9
+ use napi::{tokio::runtime, Env, JsFunction, JsObject, Status};
11
10
  use napi_derive::napi;
12
11
 
13
- use self::config::ProviderConfig;
14
- use crate::{
15
- call_override::CallOverrideCallback,
16
- context::EdrContext,
17
- logger::{Logger, LoggerConfig, LoggerError},
18
- subscribe::SubscriberCallback,
19
- trace::{solidity_stack_trace::SolidityStackTrace, RawTrace},
20
- };
12
+ pub use self::factory::ProviderFactory;
13
+ use self::response::Response;
14
+ use crate::call_override::CallOverrideCallback;
21
15
 
22
16
  /// A JSON-RPC provider for Ethereum.
23
17
  #[napi]
24
18
  pub struct Provider {
25
- provider: Arc<edr_provider::Provider<LoggerError>>,
26
- runtime: runtime::Handle,
27
19
  contract_decoder: Arc<ContractDecoder>,
20
+ provider: Arc<dyn SyncProvider>,
21
+ runtime: runtime::Handle,
28
22
  #[cfg(feature = "scenarios")]
29
23
  scenario_file: Option<napi::tokio::sync::Mutex<napi::tokio::fs::File>>,
30
24
  }
31
25
 
32
- #[napi]
33
26
  impl Provider {
34
- #[doc = "Constructs a new provider with the provided configuration."]
35
- #[napi(ts_return_type = "Promise<Provider>")]
36
- pub fn with_config(
37
- env: Env,
38
- // We take the context as argument to ensure that tracing is initialized properly.
39
- _context: &EdrContext,
40
- config: ProviderConfig,
41
- logger_config: LoggerConfig,
42
- tracing_config: TracingConfigWithBuffers,
43
- #[napi(ts_arg_type = "(event: SubscriptionEvent) => void")] subscriber_callback: JsFunction,
44
- ) -> napi::Result<JsObject> {
45
- let runtime = runtime::Handle::current();
46
-
47
- let config = edr_provider::ProviderConfig::try_from(config)?;
48
-
49
- // TODO https://github.com/NomicFoundation/edr/issues/760
50
- let build_info_config =
51
- edr_solidity::artifacts::BuildInfoConfig::parse_from_buffers((&tracing_config).into())
52
- .map_err(|err| napi::Error::from_reason(err.to_string()))?;
53
- let contract_decoder = ContractDecoder::new(&build_info_config)
54
- .map_err(|error| napi::Error::from_reason(error.to_string()))?;
55
- let contract_decoder = Arc::new(contract_decoder);
56
-
57
- let logger = Box::new(Logger::new(
58
- &env,
59
- logger_config,
60
- Arc::clone(&contract_decoder),
61
- )?);
62
- let subscriber_callback = SubscriberCallback::new(&env, subscriber_callback)?;
63
- let subscriber_callback = Box::new(move |event| subscriber_callback.call(event));
64
-
65
- let (deferred, promise) = env.create_deferred()?;
66
- runtime.clone().spawn_blocking(move || {
27
+ /// Constructs a new instance.
28
+ pub fn new(
29
+ provider: Arc<dyn SyncProvider>,
30
+ runtime: runtime::Handle,
31
+ contract_decoder: Arc<ContractDecoder>,
32
+ #[cfg(feature = "scenarios")] scenario_file: Option<
33
+ napi::tokio::sync::Mutex<napi::tokio::fs::File>,
34
+ >,
35
+ ) -> Self {
36
+ Self {
37
+ contract_decoder,
38
+ provider,
39
+ runtime,
67
40
  #[cfg(feature = "scenarios")]
68
- let scenario_file =
69
- runtime::Handle::current().block_on(crate::scenarios::scenario_file(
70
- &config,
71
- edr_provider::Logger::is_enabled(&*logger),
72
- ))?;
73
-
74
- let result = edr_provider::Provider::new(
75
- runtime.clone(),
76
- logger,
77
- subscriber_callback,
78
- config,
79
- Arc::clone(&contract_decoder),
80
- CurrentTime,
81
- )
82
- .map_or_else(
83
- |error| Err(napi::Error::new(Status::GenericFailure, error.to_string())),
84
- |provider| {
85
- Ok(Provider {
86
- provider: Arc::new(provider),
87
- runtime,
88
- contract_decoder,
89
- #[cfg(feature = "scenarios")]
90
- scenario_file,
91
- })
92
- },
93
- );
94
-
95
- deferred.resolve(|_env| result);
96
- Ok::<_, napi::Error>(())
97
- });
98
-
99
- Ok(promise)
41
+ scenario_file,
42
+ }
100
43
  }
44
+ }
101
45
 
46
+ #[napi]
47
+ impl Provider {
102
48
  #[doc = "Handles a JSON-RPC request and returns a JSON-RPC response."]
103
- #[napi]
104
- pub async fn handle_request(&self, json_request: String) -> napi::Result<Response> {
49
+ #[napi(catch_unwind)]
50
+ pub async fn handle_request(&self, request: String) -> napi::Result<Response> {
105
51
  let provider = self.provider.clone();
106
- let request = match serde_json::from_str(&json_request) {
107
- Ok(request) => request,
108
- Err(error) => {
109
- let message = error.to_string();
110
- let reason = InvalidRequestReason::new(&json_request, &message);
111
-
112
- // HACK: We need to log failed deserialization attempts when they concern input
113
- // validation.
114
- if let Some((method_name, provider_error)) = reason.provider_error() {
115
- // Ignore potential failure of logging, as returning the original error is more
116
- // important
117
- let _result = runtime::Handle::current()
118
- .spawn_blocking(move || {
119
- provider.log_failed_deserialization(&method_name, &provider_error)
120
- })
121
- .await
122
- .map_err(|error| {
123
- napi::Error::new(Status::GenericFailure, error.to_string())
124
- })?;
125
- }
126
-
127
- let data = serde_json::from_str(&json_request).ok();
128
- let response = jsonrpc::ResponseData::<()>::Error {
129
- error: jsonrpc::Error {
130
- code: reason.error_code(),
131
- message: reason.error_message(),
132
- data,
133
- },
134
- };
135
-
136
- return serde_json::to_string(&response)
137
- .map_err(|error| {
138
- napi::Error::new(
139
- Status::InvalidArg,
140
- format!("Invalid JSON `{json_request}` due to: {error}"),
141
- )
142
- })
143
- .map(|json| Response {
144
- solidity_trace: None,
145
- data: Either::A(json),
146
- traces: Vec::new(),
147
- });
148
- }
149
- };
150
52
 
151
53
  #[cfg(feature = "scenarios")]
152
54
  if let Some(scenario_file) = &self.scenario_file {
153
55
  crate::scenarios::write_request(scenario_file, &request).await?;
154
56
  }
155
57
 
156
- let mut response = runtime::Handle::current()
157
- .spawn_blocking(move || provider.handle_request(request))
158
- .await
159
- .map_err(|e| napi::Error::new(Status::GenericFailure, e.to_string()))?;
58
+ let contract_decoder = Arc::clone(&self.contract_decoder);
160
59
 
161
- // We can take the solidity trace as it won't be used for anything else
162
- let solidity_trace = response.as_mut().err().and_then(|error| {
163
- if let edr_provider::ProviderError::TransactionFailed(failure) = error {
164
- if matches!(
165
- failure.failure.reason,
166
- edr_provider::TransactionFailureReason::OutOfGas(_)
167
- ) {
168
- None
169
- } else {
170
- Some(Arc::new(std::mem::take(
171
- &mut failure.failure.solidity_trace,
172
- )))
173
- }
174
- } else {
175
- None
176
- }
177
- });
178
-
179
- // We can take the traces as they won't be used for anything else
180
- let traces = match &mut response {
181
- Ok(response) => std::mem::take(&mut response.traces),
182
- Err(edr_provider::ProviderError::TransactionFailed(failure)) => {
183
- std::mem::take(&mut failure.traces)
184
- }
185
- Err(_) => Vec::new(),
186
- };
187
-
188
- let response = jsonrpc::ResponseData::from(response.map(|response| response.result));
189
-
190
- serde_json::to_string(&response)
191
- .and_then(|json| {
192
- // We experimentally determined that 500_000_000 was the maximum string length
193
- // that can be returned without causing the error:
194
- //
195
- // > Failed to convert rust `String` into napi `string`
196
- //
197
- // To be safe, we're limiting string lengths to half of that.
198
- const MAX_STRING_LENGTH: usize = 250_000_000;
199
-
200
- if json.len() <= MAX_STRING_LENGTH {
201
- Ok(Either::A(json))
202
- } else {
203
- serde_json::to_value(response).map(Either::B)
204
- }
205
- })
206
- .map_err(|error| napi::Error::new(Status::GenericFailure, error.to_string()))
207
- .map(|data| {
208
- let solidity_trace = solidity_trace.map(|trace| SolidityTraceData {
209
- trace,
210
- contract_decoder: Arc::clone(&self.contract_decoder),
211
- });
212
- Response {
213
- solidity_trace,
214
- data,
215
- traces: traces.into_iter().map(Arc::new).collect(),
216
- }
217
- })
60
+ self.runtime
61
+ .spawn_blocking(move || provider.handle_request(request, contract_decoder))
62
+ .await
63
+ .map_err(|error| napi::Error::new(Status::GenericFailure, error.to_string()))?
64
+ .map(Response::from)
218
65
  }
219
66
 
220
- #[napi(ts_return_type = "void")]
67
+ #[napi(catch_unwind, ts_return_type = "Promise<void>")]
221
68
  pub fn set_call_override_callback(
222
69
  &self,
223
70
  env: Env,
224
71
  #[napi(
225
- ts_arg_type = "(contract_address: Buffer, data: Buffer) => Promise<CallOverrideResult | undefined>"
72
+ ts_arg_type = "(contract_address: ArrayBuffer, data: ArrayBuffer) => Promise<CallOverrideResult | undefined>"
226
73
  )]
227
74
  call_override_callback: JsFunction,
228
- ) -> napi::Result<()> {
229
- let provider = self.provider.clone();
75
+ ) -> napi::Result<JsObject> {
76
+ let (deferred, promise) = env.create_deferred()?;
230
77
 
231
78
  let call_override_callback =
232
- CallOverrideCallback::new(&env, call_override_callback, self.runtime.clone())?;
79
+ match CallOverrideCallback::new(&env, call_override_callback, self.runtime.clone()) {
80
+ Ok(callback) => callback,
81
+ Err(error) => {
82
+ deferred.reject(error);
83
+ return Ok(promise);
84
+ }
85
+ };
86
+
233
87
  let call_override_callback =
234
88
  Arc::new(move |address, data| call_override_callback.call_override(address, data));
235
89
 
236
- provider.set_call_override_callback(Some(call_override_callback));
90
+ let provider = self.provider.clone();
91
+ self.runtime.spawn_blocking(move || {
92
+ provider.set_call_override_callback(call_override_callback);
93
+
94
+ deferred.resolve(|_env| Ok(()));
95
+ });
237
96
 
238
- Ok(())
97
+ Ok(promise)
239
98
  }
240
99
 
241
100
  /// Set to `true` to make the traces returned with `eth_call`,
242
101
  /// `eth_estimateGas`, `eth_sendRawTransaction`, `eth_sendTransaction`,
243
102
  /// `evm_mine`, `hardhat_mine` include the full stack and memory. Set to
244
103
  /// `false` to disable this.
245
- #[napi(ts_return_type = "void")]
246
- pub fn set_verbose_tracing(&self, verbose_tracing: bool) {
247
- self.provider.set_verbose_tracing(verbose_tracing);
248
- }
249
- }
250
-
251
- /// Tracing config for Solidity stack trace generation.
252
- #[napi(object)]
253
- pub struct TracingConfigWithBuffers {
254
- /// Build information to use for decoding contracts. Either a Hardhat v2
255
- /// build info file that contains both input and output or a Hardhat v3
256
- /// build info file that doesn't contain output and a separate output file.
257
- pub build_infos: Option<Either<Vec<Uint8Array>, Vec<BuildInfoAndOutput>>>,
258
- /// Whether to ignore contracts whose name starts with "Ignored".
259
- pub ignore_contracts: Option<bool>,
260
- }
261
-
262
- /// Hardhat V3 build info where the compiler output is not part of the build
263
- /// info file.
264
- #[napi(object)]
265
- pub struct BuildInfoAndOutput {
266
- /// The build info input file
267
- pub build_info: Uint8Array,
268
- /// The build info output file
269
- pub output: Uint8Array,
270
- }
271
-
272
- impl<'a> From<&'a BuildInfoAndOutput>
273
- for edr_solidity::artifacts::BuildInfoBufferSeparateOutput<'a>
274
- {
275
- fn from(value: &'a BuildInfoAndOutput) -> Self {
276
- Self {
277
- build_info: value.build_info.as_ref(),
278
- output: value.output.as_ref(),
279
- }
280
- }
281
- }
282
-
283
- impl<'a> From<&'a TracingConfigWithBuffers>
284
- for edr_solidity::artifacts::BuildInfoConfigWithBuffers<'a>
285
- {
286
- fn from(value: &'a TracingConfigWithBuffers) -> Self {
287
- use edr_solidity::artifacts::{BuildInfoBufferSeparateOutput, BuildInfoBuffers};
288
-
289
- let build_infos = value.build_infos.as_ref().map(|infos| match infos {
290
- Either::A(with_output) => BuildInfoBuffers::WithOutput(
291
- with_output
292
- .iter()
293
- .map(std::convert::AsRef::as_ref)
294
- .collect(),
295
- ),
296
- Either::B(separate_output) => BuildInfoBuffers::SeparateInputOutput(
297
- separate_output
298
- .iter()
299
- .map(BuildInfoBufferSeparateOutput::from)
300
- .collect(),
301
- ),
302
- });
303
-
304
- Self {
305
- build_infos,
306
- ignore_contracts: value.ignore_contracts,
307
- }
308
- }
309
- }
310
-
311
- #[derive(Debug)]
312
- struct SolidityTraceData {
313
- trace: Arc<edr_evm::trace::Trace>,
314
- contract_decoder: Arc<ContractDecoder>,
315
- }
316
-
317
- #[napi]
318
- pub struct Response {
319
- // N-API is known to be slow when marshalling `serde_json::Value`s, so we try to return a
320
- // `String`. If the object is too large to be represented as a `String`, we return a `Buffer`
321
- // instead.
322
- data: Either<String, serde_json::Value>,
323
- /// When a transaction fails to execute, the provider returns a trace of the
324
- /// transaction.
325
- solidity_trace: Option<SolidityTraceData>,
326
- /// This may contain zero or more traces, depending on the (batch) request
327
- traces: Vec<Arc<edr_evm::trace::Trace>>,
328
- }
329
-
330
- #[napi]
331
- impl Response {
332
- /// Returns the response data as a JSON string or a JSON object.
333
- #[napi(getter)]
334
- pub fn data(&self) -> Either<String, serde_json::Value> {
335
- self.data.clone()
336
- }
337
-
338
- #[napi(getter)]
339
- pub fn traces(&self) -> Vec<RawTrace> {
340
- self.traces
341
- .iter()
342
- .map(|trace| RawTrace::new(trace.clone()))
343
- .collect()
344
- }
345
-
346
- // Rust port of https://github.com/NomicFoundation/hardhat/blob/c20bf195a6efdc2d74e778b7a4a7799aac224841/packages/hardhat-core/src/internal/hardhat-network/provider/provider.ts#L590
347
- #[doc = "Compute the error stack trace. Return the stack trace if it can be decoded, otherwise returns none. Throws if there was an error computing the stack trace."]
348
- #[napi]
349
- pub fn stack_trace(&self) -> napi::Result<Option<SolidityStackTrace>> {
350
- let Some(SolidityTraceData {
351
- trace,
352
- contract_decoder,
353
- }) = &self.solidity_trace
354
- else {
355
- return Ok(None);
356
- };
357
- let nested_trace = edr_solidity::nested_tracer::convert_trace_messages_to_nested_trace(
358
- trace.as_ref().clone(),
359
- )
360
- .map_err(|err| napi::Error::from_reason(err.to_string()))?;
361
-
362
- if let Some(vm_trace) = nested_trace {
363
- let decoded_trace = contract_decoder.try_to_decode_message_trace(vm_trace);
364
- let stack_trace = edr_solidity::solidity_tracer::get_stack_trace(decoded_trace)
365
- .map_err(|err| napi::Error::from_reason(err.to_string()))?;
366
- let stack_trace = stack_trace
367
- .into_iter()
368
- .map(super::cast::TryCast::try_cast)
369
- .collect::<Result<Vec<_>, _>>()?;
104
+ #[napi(catch_unwind)]
105
+ pub async fn set_verbose_tracing(&self, verbose_tracing: bool) -> napi::Result<()> {
106
+ let provider = self.provider.clone();
370
107
 
371
- Ok(Some(stack_trace))
372
- } else {
373
- Ok(None)
374
- }
108
+ self.runtime
109
+ .spawn_blocking(move || {
110
+ provider.set_verbose_tracing(verbose_tracing);
111
+ })
112
+ .await
113
+ .map_err(|error| napi::Error::new(Status::GenericFailure, error.to_string()))
375
114
  }
376
115
  }