@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.
- package/Cargo.toml +61 -27
- package/LICENSE +5 -1
- package/index.d.ts +875 -137
- package/index.js +61 -3
- package/package.json +20 -16
- package/src/account.rs +109 -32
- package/src/block.rs +2 -103
- package/src/call_override.rs +7 -7
- package/src/cast.rs +47 -17
- package/src/chains/generic.rs +51 -0
- package/src/chains/l1.rs +262 -0
- package/src/chains/op.rs +425 -0
- package/src/chains.rs +7 -0
- package/src/config.rs +537 -67
- package/src/context.rs +374 -17
- package/src/debug_trace.rs +2 -2
- package/src/instrument.rs +109 -0
- package/src/lib.rs +38 -14
- package/src/log.rs +12 -14
- package/src/logger.rs +77 -1177
- package/src/mock.rs +68 -0
- package/src/precompile.rs +50 -0
- package/src/provider/factory.rs +22 -0
- package/src/provider/response.rs +73 -0
- package/src/provider.rs +64 -325
- package/src/result.rs +60 -69
- package/src/scenarios.rs +11 -17
- package/src/serde.rs +57 -0
- package/src/solidity_tests/artifact.rs +184 -0
- package/src/solidity_tests/config.rs +725 -0
- package/src/solidity_tests/factory.rs +22 -0
- package/src/solidity_tests/l1.rs +68 -0
- package/src/solidity_tests/op.rs +69 -0
- package/src/solidity_tests/runner.rs +51 -0
- package/src/solidity_tests/test_results.rs +668 -0
- package/src/solidity_tests.rs +56 -0
- package/src/subscription.rs +32 -0
- package/src/trace/debug.rs +1 -1
- package/src/trace/exit.rs +12 -13
- package/src/trace/library_utils.rs +1 -1
- package/src/trace/return_data.rs +11 -11
- package/src/trace/solidity_stack_trace.rs +11 -8
- package/src/trace.rs +37 -44
- package/src/withdrawal.rs +4 -4
- package/src/provider/config.rs +0 -291
- package/src/subscribe.rs +0 -63
package/src/chains.rs
ADDED
package/src/config.rs
CHANGED
|
@@ -1,73 +1,543 @@
|
|
|
1
|
+
use core::fmt::{Debug, Display};
|
|
2
|
+
use std::{
|
|
3
|
+
num::NonZeroU64,
|
|
4
|
+
path::PathBuf,
|
|
5
|
+
time::{Duration, SystemTime},
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
use edr_coverage::reporter::SyncOnCollectedCoverageCallback;
|
|
9
|
+
use edr_eth::{
|
|
10
|
+
signature::{secret_key_from_str, SecretKey},
|
|
11
|
+
Bytes, HashMap, HashSet,
|
|
12
|
+
};
|
|
13
|
+
use napi::{
|
|
14
|
+
bindgen_prelude::{BigInt, Promise, Reference, Uint8Array},
|
|
15
|
+
threadsafe_function::{
|
|
16
|
+
ErrorStrategy, ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode,
|
|
17
|
+
},
|
|
18
|
+
tokio::runtime,
|
|
19
|
+
Either, JsFunction, JsString, JsStringUtf8,
|
|
20
|
+
};
|
|
1
21
|
use napi_derive::napi;
|
|
2
22
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
///
|
|
9
|
-
|
|
10
|
-
///
|
|
11
|
-
|
|
12
|
-
///
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
///
|
|
21
|
-
|
|
22
|
-
///
|
|
23
|
-
|
|
24
|
-
///
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
///
|
|
35
|
-
|
|
36
|
-
///
|
|
37
|
-
|
|
38
|
-
///
|
|
39
|
-
|
|
40
|
-
///
|
|
41
|
-
|
|
42
|
-
///
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
23
|
+
use crate::{account::AccountOverride, block::BlobGas, cast::TryCast, precompile::Precompile};
|
|
24
|
+
|
|
25
|
+
/// Specification of a chain with possible overrides.
|
|
26
|
+
#[napi(object)]
|
|
27
|
+
pub struct ChainOverride {
|
|
28
|
+
/// The chain ID
|
|
29
|
+
pub chain_id: BigInt,
|
|
30
|
+
/// The chain's name
|
|
31
|
+
pub name: String,
|
|
32
|
+
/// If present, overrides for the chain's supported hardforks
|
|
33
|
+
pub hardfork_activation_overrides: Option<Vec<HardforkActivation>>,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Configuration for a code coverage reporter.
|
|
37
|
+
#[napi(object)]
|
|
38
|
+
pub struct CodeCoverageConfig {
|
|
39
|
+
/// The callback to be called when coverage has been collected.
|
|
40
|
+
///
|
|
41
|
+
/// The callback receives an array of unique coverage hit markers (i.e. no
|
|
42
|
+
/// repetition) per transaction.
|
|
43
|
+
///
|
|
44
|
+
/// Exceptions thrown in the callback will be propagated to the original
|
|
45
|
+
/// caller.
|
|
46
|
+
#[napi(ts_type = "(coverageHits: Uint8Array[]) => Promise<void>")]
|
|
47
|
+
pub on_collected_coverage_callback: JsFunction,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Configuration for forking a blockchain
|
|
51
|
+
#[napi(object)]
|
|
52
|
+
pub struct ForkConfig {
|
|
53
|
+
/// The block number to fork from. If not provided, the latest safe block is
|
|
54
|
+
/// used.
|
|
55
|
+
pub block_number: Option<BigInt>,
|
|
56
|
+
/// The directory to cache remote JSON-RPC responses
|
|
57
|
+
pub cache_dir: Option<String>,
|
|
58
|
+
/// Overrides for the configuration of chains.
|
|
59
|
+
pub chain_overrides: Option<Vec<ChainOverride>>,
|
|
60
|
+
/// The HTTP headers to use when making requests to the JSON-RPC endpoint
|
|
61
|
+
pub http_headers: Option<Vec<HttpHeader>>,
|
|
62
|
+
/// The URL of the JSON-RPC endpoint to fork from
|
|
63
|
+
pub url: String,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#[napi(object)]
|
|
67
|
+
pub struct HttpHeader {
|
|
68
|
+
pub name: String,
|
|
69
|
+
pub value: String,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Configuration for a hardfork activation
|
|
73
|
+
#[napi(object)]
|
|
74
|
+
pub struct HardforkActivation {
|
|
75
|
+
/// The condition for the hardfork activation
|
|
76
|
+
pub condition: Either<HardforkActivationByBlockNumber, HardforkActivationByTimestamp>,
|
|
77
|
+
/// The activated hardfork
|
|
78
|
+
pub hardfork: String,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#[napi(object)]
|
|
82
|
+
pub struct HardforkActivationByBlockNumber {
|
|
83
|
+
/// The block number at which the hardfork is activated
|
|
84
|
+
pub block_number: BigInt,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[napi(object)]
|
|
88
|
+
pub struct HardforkActivationByTimestamp {
|
|
89
|
+
/// The timestamp at which the hardfork is activated
|
|
90
|
+
pub timestamp: BigInt,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#[napi(string_enum)]
|
|
94
|
+
#[doc = "The type of ordering to use when selecting blocks to mine."]
|
|
95
|
+
pub enum MineOrdering {
|
|
96
|
+
#[doc = "Insertion order"]
|
|
97
|
+
Fifo,
|
|
98
|
+
#[doc = "Effective miner fee"]
|
|
99
|
+
Priority,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// Configuration for the provider's mempool.
|
|
103
|
+
#[napi(object)]
|
|
104
|
+
pub struct MemPoolConfig {
|
|
105
|
+
pub order: MineOrdering,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#[napi(object)]
|
|
109
|
+
pub struct IntervalRange {
|
|
110
|
+
pub min: BigInt,
|
|
111
|
+
pub max: BigInt,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// Configuration for the provider's miner.
|
|
115
|
+
#[napi(object)]
|
|
116
|
+
pub struct MiningConfig {
|
|
117
|
+
pub auto_mine: bool,
|
|
118
|
+
pub interval: Option<Either<BigInt, IntervalRange>>,
|
|
119
|
+
pub mem_pool: MemPoolConfig,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// Configuration for runtime observability.
|
|
123
|
+
#[napi(object)]
|
|
124
|
+
pub struct ObservabilityConfig {
|
|
125
|
+
/// If present, configures runtime observability to collect code coverage.
|
|
126
|
+
pub code_coverage: Option<CodeCoverageConfig>,
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// Configuration for a provider
|
|
130
|
+
#[napi(object)]
|
|
131
|
+
pub struct ProviderConfig {
|
|
132
|
+
/// Whether to allow blocks with the same timestamp
|
|
133
|
+
pub allow_blocks_with_same_timestamp: bool,
|
|
134
|
+
/// Whether to allow unlimited contract size
|
|
135
|
+
pub allow_unlimited_contract_size: bool,
|
|
136
|
+
/// Whether to return an `Err` when `eth_call` fails
|
|
137
|
+
pub bail_on_call_failure: bool,
|
|
138
|
+
/// Whether to return an `Err` when a `eth_sendTransaction` fails
|
|
139
|
+
pub bail_on_transaction_failure: bool,
|
|
140
|
+
/// The gas limit of each block
|
|
141
|
+
pub block_gas_limit: BigInt,
|
|
142
|
+
/// The chain ID of the blockchain
|
|
143
|
+
pub chain_id: BigInt,
|
|
144
|
+
/// The address of the coinbase
|
|
145
|
+
pub coinbase: Uint8Array,
|
|
146
|
+
/// The configuration for forking a blockchain. If not provided, a local
|
|
147
|
+
/// blockchain will be created
|
|
148
|
+
pub fork: Option<ForkConfig>,
|
|
149
|
+
/// The genesis state of the blockchain
|
|
150
|
+
pub genesis_state: Vec<AccountOverride>,
|
|
151
|
+
/// The hardfork of the blockchain
|
|
152
|
+
pub hardfork: String,
|
|
153
|
+
/// The initial base fee per gas of the blockchain. Required for EIP-1559
|
|
154
|
+
/// transactions and later
|
|
155
|
+
pub initial_base_fee_per_gas: Option<BigInt>,
|
|
156
|
+
/// The initial blob gas of the blockchain. Required for EIP-4844
|
|
157
|
+
pub initial_blob_gas: Option<BlobGas>,
|
|
158
|
+
/// The initial date of the blockchain, in seconds since the Unix epoch
|
|
159
|
+
pub initial_date: Option<BigInt>,
|
|
160
|
+
/// The initial parent beacon block root of the blockchain. Required for
|
|
161
|
+
/// EIP-4788
|
|
162
|
+
pub initial_parent_beacon_block_root: Option<Uint8Array>,
|
|
163
|
+
/// The minimum gas price of the next block.
|
|
164
|
+
pub min_gas_price: BigInt,
|
|
165
|
+
/// The configuration for the miner
|
|
166
|
+
pub mining: MiningConfig,
|
|
167
|
+
/// The network ID of the blockchain
|
|
168
|
+
pub network_id: BigInt,
|
|
169
|
+
/// The configuration for the provider's observability
|
|
170
|
+
pub observability: ObservabilityConfig,
|
|
171
|
+
// Using JsString here as it doesn't have `Debug`, `Display` and `Serialize` implementation
|
|
172
|
+
// which prevents accidentally leaking the secret keys to error messages and logs.
|
|
173
|
+
/// Secret keys of owned accounts
|
|
174
|
+
pub owned_accounts: Vec<JsString>,
|
|
175
|
+
/// Overrides for precompiles
|
|
176
|
+
pub precompile_overrides: Vec<Reference<Precompile>>,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
impl TryFrom<ForkConfig> for edr_provider::ForkConfig<String> {
|
|
180
|
+
type Error = napi::Error;
|
|
181
|
+
|
|
182
|
+
fn try_from(value: ForkConfig) -> Result<Self, Self::Error> {
|
|
183
|
+
let block_number: Option<u64> = value.block_number.map(TryCast::try_cast).transpose()?;
|
|
184
|
+
|
|
185
|
+
let cache_dir = PathBuf::from(
|
|
186
|
+
value
|
|
187
|
+
.cache_dir
|
|
188
|
+
.unwrap_or(edr_defaults::CACHE_DIR.to_owned()),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
let chain_overrides = value
|
|
192
|
+
.chain_overrides
|
|
193
|
+
.map(|chain_overrides| {
|
|
194
|
+
chain_overrides
|
|
195
|
+
.into_iter()
|
|
196
|
+
.map(
|
|
197
|
+
|ChainOverride {
|
|
198
|
+
chain_id,
|
|
199
|
+
name,
|
|
200
|
+
hardfork_activation_overrides,
|
|
201
|
+
}| {
|
|
202
|
+
let hardfork_activation_overrides =
|
|
203
|
+
hardfork_activation_overrides
|
|
204
|
+
.map(|hardfork_activations| {
|
|
205
|
+
hardfork_activations
|
|
206
|
+
.into_iter()
|
|
207
|
+
.map(
|
|
208
|
+
|HardforkActivation {
|
|
209
|
+
condition,
|
|
210
|
+
hardfork,
|
|
211
|
+
}| {
|
|
212
|
+
let condition = match condition {
|
|
213
|
+
Either::A(HardforkActivationByBlockNumber {
|
|
214
|
+
block_number,
|
|
215
|
+
}) => edr_evm::hardfork::ForkCondition::Block(
|
|
216
|
+
block_number.try_cast()?,
|
|
217
|
+
),
|
|
218
|
+
Either::B(HardforkActivationByTimestamp {
|
|
219
|
+
timestamp,
|
|
220
|
+
}) => edr_evm::hardfork::ForkCondition::Timestamp(
|
|
221
|
+
timestamp.try_cast()?,
|
|
222
|
+
),
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
Ok(edr_evm::hardfork::Activation {
|
|
226
|
+
condition,
|
|
227
|
+
hardfork,
|
|
228
|
+
})
|
|
229
|
+
},
|
|
230
|
+
)
|
|
231
|
+
.collect::<napi::Result<Vec<_>>>()
|
|
232
|
+
.map(edr_evm::hardfork::Activations::new)
|
|
233
|
+
})
|
|
234
|
+
.transpose()?;
|
|
235
|
+
|
|
236
|
+
let chain_config = edr_evm::hardfork::ChainOverride {
|
|
237
|
+
name,
|
|
238
|
+
hardfork_activation_overrides,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
let chain_id = chain_id.try_cast()?;
|
|
242
|
+
Ok((chain_id, chain_config))
|
|
243
|
+
},
|
|
244
|
+
)
|
|
245
|
+
.collect::<napi::Result<_>>()
|
|
246
|
+
})
|
|
247
|
+
.transpose()?;
|
|
248
|
+
|
|
249
|
+
let http_headers = value.http_headers.map(|http_headers| {
|
|
250
|
+
http_headers
|
|
251
|
+
.into_iter()
|
|
252
|
+
.map(|HttpHeader { name, value }| (name, value))
|
|
253
|
+
.collect()
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
Ok(Self {
|
|
257
|
+
block_number,
|
|
258
|
+
cache_dir,
|
|
259
|
+
chain_overrides: chain_overrides.unwrap_or_default(),
|
|
260
|
+
http_headers,
|
|
261
|
+
url: value.url,
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
impl From<MemPoolConfig> for edr_provider::MemPoolConfig {
|
|
267
|
+
fn from(value: MemPoolConfig) -> Self {
|
|
268
|
+
Self {
|
|
269
|
+
order: value.order.into(),
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
impl From<MineOrdering> for edr_evm::MineOrdering {
|
|
275
|
+
fn from(value: MineOrdering) -> Self {
|
|
50
276
|
match value {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
277
|
+
MineOrdering::Fifo => Self::Fifo,
|
|
278
|
+
MineOrdering::Priority => Self::Priority,
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
impl TryFrom<MiningConfig> for edr_provider::MiningConfig {
|
|
284
|
+
type Error = napi::Error;
|
|
285
|
+
|
|
286
|
+
fn try_from(value: MiningConfig) -> Result<Self, Self::Error> {
|
|
287
|
+
let mem_pool = value.mem_pool.into();
|
|
288
|
+
|
|
289
|
+
let interval = value
|
|
290
|
+
.interval
|
|
291
|
+
.map(|interval| {
|
|
292
|
+
let interval = match interval {
|
|
293
|
+
Either::A(interval) => {
|
|
294
|
+
let interval = interval.try_cast()?;
|
|
295
|
+
let interval = NonZeroU64::new(interval).ok_or_else(|| {
|
|
296
|
+
napi::Error::new(
|
|
297
|
+
napi::Status::GenericFailure,
|
|
298
|
+
"Interval must be greater than 0",
|
|
299
|
+
)
|
|
300
|
+
})?;
|
|
301
|
+
|
|
302
|
+
edr_provider::IntervalConfig::Fixed(interval)
|
|
303
|
+
}
|
|
304
|
+
Either::B(IntervalRange { min, max }) => edr_provider::IntervalConfig::Range {
|
|
305
|
+
min: min.try_cast()?,
|
|
306
|
+
max: max.try_cast()?,
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
napi::Result::Ok(interval)
|
|
311
|
+
})
|
|
312
|
+
.transpose()?;
|
|
313
|
+
|
|
314
|
+
Ok(Self {
|
|
315
|
+
auto_mine: value.auto_mine,
|
|
316
|
+
interval,
|
|
317
|
+
mem_pool,
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
impl ObservabilityConfig {
|
|
323
|
+
/// Resolves the instance, converting it to a
|
|
324
|
+
/// [`edr_provider::observability::Config`].
|
|
325
|
+
pub fn resolve(
|
|
326
|
+
self,
|
|
327
|
+
env: &napi::Env,
|
|
328
|
+
runtime: runtime::Handle,
|
|
329
|
+
) -> napi::Result<edr_provider::observability::Config> {
|
|
330
|
+
let on_collected_coverage_fn = self
|
|
331
|
+
.code_coverage
|
|
332
|
+
.map(
|
|
333
|
+
|code_coverage| -> napi::Result<Box<dyn SyncOnCollectedCoverageCallback>> {
|
|
334
|
+
let mut on_collected_coverage_callback: ThreadsafeFunction<
|
|
335
|
+
_,
|
|
336
|
+
ErrorStrategy::Fatal,
|
|
337
|
+
> = code_coverage
|
|
338
|
+
.on_collected_coverage_callback
|
|
339
|
+
.create_threadsafe_function(
|
|
340
|
+
0,
|
|
341
|
+
|ctx: ThreadSafeCallContext<HashSet<Bytes>>| {
|
|
342
|
+
let hits = ctx
|
|
343
|
+
.env
|
|
344
|
+
.create_array_with_length(ctx.value.len())
|
|
345
|
+
.and_then(|mut hits| {
|
|
346
|
+
for (idx, hit) in ctx.value.into_iter().enumerate() {
|
|
347
|
+
ctx.env
|
|
348
|
+
.create_buffer_with_data(hit.to_vec())
|
|
349
|
+
.and_then(|hit| {
|
|
350
|
+
let idx = u32::try_from(idx).unwrap_or_else(|_| panic!("Number of hits should not exceed '{}'",
|
|
351
|
+
u32::MAX));
|
|
352
|
+
|
|
353
|
+
hits.set_element(idx, hit.into_raw())
|
|
354
|
+
})?;
|
|
355
|
+
}
|
|
356
|
+
Ok(hits)
|
|
357
|
+
})?;
|
|
358
|
+
|
|
359
|
+
Ok(vec![hits])
|
|
360
|
+
},
|
|
361
|
+
)?;
|
|
362
|
+
|
|
363
|
+
// Maintain a weak reference to the function to avoid blocking the event loop
|
|
364
|
+
// from exiting.
|
|
365
|
+
on_collected_coverage_callback.unref(env)?;
|
|
366
|
+
|
|
367
|
+
let on_collected_coverage_fn: Box<dyn SyncOnCollectedCoverageCallback> =
|
|
368
|
+
Box::new(move |hits| {
|
|
369
|
+
let runtime = runtime.clone();
|
|
370
|
+
|
|
371
|
+
let (sender, receiver) = std::sync::mpsc::channel();
|
|
372
|
+
|
|
373
|
+
let status = on_collected_coverage_callback
|
|
374
|
+
.call_with_return_value(hits, ThreadsafeFunctionCallMode::Blocking, move |result: Promise<()>| {
|
|
375
|
+
// We spawn a background task to handle the async callback
|
|
376
|
+
runtime.spawn(async move {
|
|
377
|
+
let result = result.await;
|
|
378
|
+
sender.send(result).map_err(|_error| {
|
|
379
|
+
napi::Error::new(
|
|
380
|
+
napi::Status::GenericFailure,
|
|
381
|
+
"Failed to send result from on_collected_coverage_callback",
|
|
382
|
+
)
|
|
383
|
+
})
|
|
384
|
+
});
|
|
385
|
+
Ok(())
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
|
|
389
|
+
|
|
390
|
+
assert_eq!(status, napi::Status::Ok);
|
|
391
|
+
|
|
392
|
+
Ok(())
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
Ok(on_collected_coverage_fn)
|
|
396
|
+
},
|
|
397
|
+
)
|
|
398
|
+
.transpose()?;
|
|
399
|
+
|
|
400
|
+
Ok(edr_provider::observability::Config {
|
|
401
|
+
on_collected_coverage_fn,
|
|
402
|
+
..edr_provider::observability::Config::default()
|
|
403
|
+
})
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
impl ProviderConfig {
|
|
408
|
+
/// Resolves the instance to a [`edr_napi_core::provider::Config`].
|
|
409
|
+
pub fn resolve(
|
|
410
|
+
self,
|
|
411
|
+
env: &napi::Env,
|
|
412
|
+
runtime: runtime::Handle,
|
|
413
|
+
) -> napi::Result<edr_napi_core::provider::Config> {
|
|
414
|
+
let owned_accounts = self
|
|
415
|
+
.owned_accounts
|
|
416
|
+
.into_iter()
|
|
417
|
+
.map(|secret_key| {
|
|
418
|
+
// This is the only place in production code where it's allowed to use
|
|
419
|
+
// `DangerousSecretKeyStr`.
|
|
420
|
+
#[allow(deprecated)]
|
|
421
|
+
use edr_eth::signature::DangerousSecretKeyStr;
|
|
422
|
+
|
|
423
|
+
static_assertions::assert_not_impl_all!(JsString: Debug, Display, serde::Serialize);
|
|
424
|
+
static_assertions::assert_not_impl_all!(JsStringUtf8: Debug, Display, serde::Serialize);
|
|
425
|
+
// `SecretKey` has `Debug` implementation, but it's opaque (only shows the
|
|
426
|
+
// type name)
|
|
427
|
+
static_assertions::assert_not_impl_any!(SecretKey: Display, serde::Serialize);
|
|
428
|
+
|
|
429
|
+
let secret_key = secret_key.into_utf8()?;
|
|
430
|
+
// This is the only place in production code where it's allowed to use
|
|
431
|
+
// `DangerousSecretKeyStr`.
|
|
432
|
+
#[allow(deprecated)]
|
|
433
|
+
let secret_key_str = DangerousSecretKeyStr(secret_key.as_str()?);
|
|
434
|
+
let secret_key: SecretKey = secret_key_from_str(secret_key_str)
|
|
435
|
+
.map_err(|error| napi::Error::new(napi::Status::InvalidArg, error))?;
|
|
436
|
+
|
|
437
|
+
Ok(secret_key)
|
|
438
|
+
})
|
|
439
|
+
.collect::<napi::Result<Vec<_>>>()?;
|
|
440
|
+
|
|
441
|
+
let block_gas_limit =
|
|
442
|
+
NonZeroU64::new(self.block_gas_limit.try_cast()?).ok_or_else(|| {
|
|
443
|
+
napi::Error::new(
|
|
444
|
+
napi::Status::GenericFailure,
|
|
445
|
+
"Block gas limit must be greater than 0",
|
|
446
|
+
)
|
|
447
|
+
})?;
|
|
448
|
+
|
|
449
|
+
let genesis_state = self
|
|
450
|
+
.genesis_state
|
|
451
|
+
.into_iter()
|
|
452
|
+
.map(TryInto::try_into)
|
|
453
|
+
.collect::<napi::Result<HashMap<edr_eth::Address, edr_provider::AccountOverride>>>()?;
|
|
454
|
+
|
|
455
|
+
let precompile_overrides = self
|
|
456
|
+
.precompile_overrides
|
|
457
|
+
.into_iter()
|
|
458
|
+
.map(|precompile| precompile.to_tuple())
|
|
459
|
+
.collect();
|
|
460
|
+
|
|
461
|
+
Ok(edr_napi_core::provider::Config {
|
|
462
|
+
allow_blocks_with_same_timestamp: self.allow_blocks_with_same_timestamp,
|
|
463
|
+
allow_unlimited_contract_size: self.allow_unlimited_contract_size,
|
|
464
|
+
bail_on_call_failure: self.bail_on_call_failure,
|
|
465
|
+
bail_on_transaction_failure: self.bail_on_transaction_failure,
|
|
466
|
+
block_gas_limit,
|
|
467
|
+
chain_id: self.chain_id.try_cast()?,
|
|
468
|
+
coinbase: self.coinbase.try_cast()?,
|
|
469
|
+
fork: self.fork.map(TryInto::try_into).transpose()?,
|
|
470
|
+
genesis_state,
|
|
471
|
+
hardfork: self.hardfork,
|
|
472
|
+
initial_base_fee_per_gas: self
|
|
473
|
+
.initial_base_fee_per_gas
|
|
474
|
+
.map(TryCast::try_cast)
|
|
475
|
+
.transpose()?,
|
|
476
|
+
initial_blob_gas: self.initial_blob_gas.map(TryInto::try_into).transpose()?,
|
|
477
|
+
initial_date: self
|
|
478
|
+
.initial_date
|
|
479
|
+
.map(|date| {
|
|
480
|
+
let elapsed_since_epoch = Duration::from_secs(date.try_cast()?);
|
|
481
|
+
napi::Result::Ok(SystemTime::UNIX_EPOCH + elapsed_since_epoch)
|
|
482
|
+
})
|
|
483
|
+
.transpose()?,
|
|
484
|
+
initial_parent_beacon_block_root: self
|
|
485
|
+
.initial_parent_beacon_block_root
|
|
486
|
+
.map(TryCast::try_cast)
|
|
487
|
+
.transpose()?,
|
|
488
|
+
mining: self.mining.try_into()?,
|
|
489
|
+
min_gas_price: self.min_gas_price.try_cast()?,
|
|
490
|
+
network_id: self.network_id.try_cast()?,
|
|
491
|
+
observability: self.observability.resolve(env, runtime)?,
|
|
492
|
+
owned_accounts,
|
|
493
|
+
precompile_overrides,
|
|
494
|
+
})
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/// Tracing config for Solidity stack trace generation.
|
|
499
|
+
#[napi(object)]
|
|
500
|
+
pub struct TracingConfigWithBuffers {
|
|
501
|
+
/// Build information to use for decoding contracts. Either a Hardhat v2
|
|
502
|
+
/// build info file that contains both input and output or a Hardhat v3
|
|
503
|
+
/// build info file that doesn't contain output and a separate output file.
|
|
504
|
+
pub build_infos: Option<Either<Vec<Uint8Array>, Vec<BuildInfoAndOutput>>>,
|
|
505
|
+
/// Whether to ignore contracts whose name starts with "Ignored".
|
|
506
|
+
pub ignore_contracts: Option<bool>,
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
impl From<TracingConfigWithBuffers> for edr_napi_core::solidity::config::TracingConfigWithBuffers {
|
|
510
|
+
fn from(value: TracingConfigWithBuffers) -> Self {
|
|
511
|
+
edr_napi_core::solidity::config::TracingConfigWithBuffers {
|
|
512
|
+
build_infos: value.build_infos.map(|infos| match infos {
|
|
513
|
+
Either::A(with_output) => Either::A(with_output),
|
|
514
|
+
Either::B(separate_output) => Either::B(
|
|
515
|
+
separate_output
|
|
516
|
+
.into_iter()
|
|
517
|
+
.map(edr_napi_core::solidity::config::BuildInfoAndOutput::from)
|
|
518
|
+
.collect(),
|
|
519
|
+
),
|
|
520
|
+
}),
|
|
521
|
+
ignore_contracts: value.ignore_contracts,
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/// Hardhat V3 build info where the compiler output is not part of the build
|
|
527
|
+
/// info file.
|
|
528
|
+
#[napi(object)]
|
|
529
|
+
pub struct BuildInfoAndOutput {
|
|
530
|
+
/// The build info input file
|
|
531
|
+
pub build_info: Uint8Array,
|
|
532
|
+
/// The build info output file
|
|
533
|
+
pub output: Uint8Array,
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
impl From<BuildInfoAndOutput> for edr_napi_core::solidity::config::BuildInfoAndOutput {
|
|
537
|
+
fn from(value: BuildInfoAndOutput) -> Self {
|
|
538
|
+
Self {
|
|
539
|
+
build_info: value.build_info,
|
|
540
|
+
output: value.output,
|
|
71
541
|
}
|
|
72
542
|
}
|
|
73
543
|
}
|