@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/src/chains/op.rs CHANGED
@@ -1,14 +1,25 @@
1
1
  use std::{str::FromStr, sync::Arc};
2
2
 
3
- use edr_eth::hex;
4
3
  use edr_napi_core::{
5
- logger::{self, Logger},
6
- provider::{self, ProviderBuilder, SyncProviderFactory},
7
- subscription,
4
+ logger::Logger,
5
+ provider::{SyncProvider, SyncProviderFactory},
6
+ subscription::subscriber_callback_for_chain_spec,
8
7
  };
9
- use edr_op::{predeploys::GAS_PRICE_ORACLE_ADDRESS, OpChainSpec, OpSpecId};
8
+ use edr_op::{
9
+ predeploys::{
10
+ gas_price_oracle_code_ecotone, gas_price_oracle_code_fjord, gas_price_oracle_code_isthmus,
11
+ l1_block_code_bedrock, l1_block_code_ecotone, l1_block_code_isthmus,
12
+ GAS_PRICE_ORACLE_ADDRESS, L1_BLOCK_PREDEPLOY_ADDRESS,
13
+ },
14
+ OpChainSpec,
15
+ };
16
+ use edr_primitives::hex;
17
+ use edr_provider::time::CurrentTime;
10
18
  use edr_solidity::contract_decoder::ContractDecoder;
11
- use napi::bindgen_prelude::{BigInt, Uint8Array};
19
+ use napi::{
20
+ bindgen_prelude::{BigInt, Uint8Array},
21
+ tokio::runtime,
22
+ };
12
23
  use napi_derive::napi;
13
24
 
14
25
  use crate::{
@@ -19,27 +30,31 @@ use crate::{
19
30
  pub struct OpProviderFactory;
20
31
 
21
32
  impl SyncProviderFactory for OpProviderFactory {
22
- fn create_provider_builder(
33
+ fn create_provider(
23
34
  &self,
24
- env: &napi::Env,
25
- provider_config: provider::Config,
26
- logger_config: logger::Config,
27
- subscription_config: subscription::Config,
35
+ runtime: runtime::Handle,
36
+ provider_config: edr_napi_core::provider::Config,
37
+ logger_config: edr_napi_core::logger::Config,
38
+ subscription_callback: edr_napi_core::subscription::Callback,
28
39
  contract_decoder: Arc<ContractDecoder>,
29
- ) -> napi::Result<Box<dyn provider::Builder>> {
30
- let logger = Logger::<OpChainSpec>::new(logger_config, Arc::clone(&contract_decoder))?;
40
+ ) -> napi::Result<Arc<dyn SyncProvider>> {
41
+ let logger =
42
+ Logger::<OpChainSpec, CurrentTime>::new(logger_config, Arc::clone(&contract_decoder))?;
31
43
 
32
- let provider_config = edr_provider::ProviderConfig::<OpSpecId>::try_from(provider_config)?;
44
+ let provider_config =
45
+ edr_provider::ProviderConfig::<edr_op::Hardfork>::try_from(provider_config)?;
33
46
 
34
- let subscription_callback =
35
- subscription::Callback::new(env, subscription_config.subscription_callback)?;
36
-
37
- Ok(Box::new(ProviderBuilder::new(
38
- contract_decoder,
47
+ let provider = edr_provider::Provider::<OpChainSpec>::new(
48
+ runtime.clone(),
39
49
  Box::new(logger),
50
+ subscriber_callback_for_chain_spec::<OpChainSpec, CurrentTime>(subscription_callback),
40
51
  provider_config,
41
- subscription_callback,
42
- )))
52
+ contract_decoder,
53
+ CurrentTime,
54
+ )
55
+ .map_err(|error| napi::Error::new(napi::Status::GenericFailure, error.to_string()))?;
56
+
57
+ Ok(Arc::new(provider))
43
58
  }
44
59
  }
45
60
 
@@ -56,17 +71,17 @@ pub enum OpHardfork {
56
71
  Isthmus = 107,
57
72
  }
58
73
 
59
- impl From<OpHardfork> for OpSpecId {
74
+ impl From<OpHardfork> for edr_op::Hardfork {
60
75
  fn from(hardfork: OpHardfork) -> Self {
61
76
  match hardfork {
62
- OpHardfork::Bedrock => OpSpecId::BEDROCK,
63
- OpHardfork::Regolith => OpSpecId::REGOLITH,
64
- OpHardfork::Canyon => OpSpecId::CANYON,
65
- OpHardfork::Ecotone => OpSpecId::ECOTONE,
66
- OpHardfork::Fjord => OpSpecId::FJORD,
67
- OpHardfork::Granite => OpSpecId::GRANITE,
68
- OpHardfork::Holocene => OpSpecId::HOLOCENE,
69
- OpHardfork::Isthmus => OpSpecId::ISTHMUS,
77
+ OpHardfork::Bedrock => edr_op::Hardfork::BEDROCK,
78
+ OpHardfork::Regolith => edr_op::Hardfork::REGOLITH,
79
+ OpHardfork::Canyon => edr_op::Hardfork::CANYON,
80
+ OpHardfork::Ecotone => edr_op::Hardfork::ECOTONE,
81
+ OpHardfork::Fjord => edr_op::Hardfork::FJORD,
82
+ OpHardfork::Granite => edr_op::Hardfork::GRANITE,
83
+ OpHardfork::Holocene => edr_op::Hardfork::HOLOCENE,
84
+ OpHardfork::Isthmus => edr_op::Hardfork::ISTHMUS,
70
85
  }
71
86
  }
72
87
  }
@@ -121,7 +136,7 @@ pub fn op_hardfork_to_string(hardfork: OpHardfork) -> &'static str {
121
136
  /// The returned value will be updated after each network upgrade.
122
137
  #[napi(catch_unwind)]
123
138
  pub fn op_latest_hardfork() -> OpHardfork {
124
- OpHardfork::Holocene
139
+ OpHardfork::Isthmus
125
140
  }
126
141
 
127
142
  #[napi]
@@ -129,72 +144,13 @@ pub const OP_CHAIN_TYPE: &str = edr_op::CHAIN_TYPE;
129
144
 
130
145
  #[napi(catch_unwind)]
131
146
  pub fn op_genesis_state(hardfork: OpHardfork) -> Vec<AccountOverride> {
132
- let l1_block_code = hex::decode(include_str!("../../data/op/predeploys/l1_block.txt"))
133
- .expect("The bytecode for the L1Block predeploy should be a valid hex string");
147
+ let l1_block_code = l1_block_code(hardfork.into());
134
148
  let l1_block = AccountOverride {
135
- address: hex!("4200000000000000000000000000000000000015").into(),
149
+ address: Uint8Array::with_data_copied(L1_BLOCK_PREDEPLOY_ADDRESS),
136
150
  balance: Some(BigInt::from(0u64)),
137
151
  nonce: Some(BigInt::from(0u64)),
138
- code: Some(l1_block_code.into()),
139
- storage: Some(vec![
140
- StorageSlot {
141
- index: BigInt::from(0u64),
142
- // uint64 public number = 1
143
- // uint64 public timestamp = 1
144
- value: BigInt {
145
- words: vec![
146
- 0x0000000000000001_u64, // least significative
147
- 0x0000000000000001_u64,
148
- ],
149
- sign_bit: false,
150
- },
151
- },
152
- StorageSlot {
153
- index: BigInt::from(1u64),
154
- // uint256 baseFee = 10 gwei
155
- value: BigInt::from(0x00000002540be400_u64),
156
- },
157
- StorageSlot {
158
- index: BigInt::from(2u64),
159
- // bytes32 hash = 0
160
- value: BigInt::from(0u64),
161
- },
162
- StorageSlot {
163
- index: BigInt::from(3u64),
164
- // uint64 sequenceNumber = 0
165
- // uint32 blobBaseFeeScalar = 1014213
166
- // uint32 baseFeeScalar = 5227
167
- value: BigInt {
168
- words: vec![
169
- 0x0000000000000000_u64, // least significative
170
- 0x0000000000000000_u64,
171
- 0x00000000000f79c5_u64,
172
- 0x000000000000146b_u64,
173
- ],
174
- sign_bit: false,
175
- },
176
- },
177
- StorageSlot {
178
- index: BigInt::from(4u64),
179
- // bytes32 batcherHash = 0
180
- value: BigInt::from(0u64),
181
- },
182
- StorageSlot {
183
- index: BigInt::from(5u64),
184
- // uint256 l1FeeOverhead = 0
185
- value: BigInt::from(0u64),
186
- },
187
- StorageSlot {
188
- index: BigInt::from(6u64),
189
- // uint256 l1FeeScalar = 0
190
- value: BigInt::from(0u64),
191
- },
192
- StorageSlot {
193
- index: BigInt::from(7u64),
194
- // uint256 blobBaseFee = 10 gwei
195
- value: BigInt::from(0x00000002540be400_u64),
196
- },
197
- ]),
152
+ code: Some(l1_block_code),
153
+ storage: Some(l1_block_storage(hardfork.into())),
198
154
  };
199
155
 
200
156
  /* The rest of the predeploys use a stubbed bytecode that reverts with a
@@ -301,6 +257,11 @@ pub fn op_genesis_state(hardfork: OpHardfork) -> Vec<AccountOverride> {
301
257
  hex!("4200000000000000000000000000000000000021"),
302
258
  "0x60806040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401603490607b565b60405180910390fd5b60006048601f836099565b91507f5072656465706c6f7920454153206973206e6f7420737570706f727465642e006000830152602082019050919050565b60006020820190508181036000830152609281603d565b9050919050565b60008282526020820190509291505056fea2646970667358221220afa6c1aa54a8b3f4f979e1297db5838a94353f3b77b5ecc164da19db26ea89f564736f6c63430008000033",
303
259
  ),
260
+ (
261
+ "OperatorFeeVault",
262
+ hex!("0x420000000000000000000000000000000000001b"),
263
+ "0x60806040526040517f08c379a000000000000000000000000000000000000000000000000000000000815260040160349060b9565b60405180910390fd5b5f82825260208201905092915050565b7f5072656465706c6f79204f70657261746f724665655661756c74206973206e6f5f8201527f7420737570706f727465642e0000000000000000000000000000000000000000602082015250565b5f60a5602c83603d565b915060ae82604d565b604082019050919050565b5f6020820190508181035f83015260ce81609b565b905091905056fea2646970667358221220dc3131d0ea77326c36012aee5dd9a870b6f07d76e6f55c8029da9d70a83f50c364736f6c634300081e0033",
264
+ ),
304
265
  ];
305
266
 
306
267
  let stubbed_predeploys = stubbed_predeploys_data
@@ -328,10 +289,10 @@ pub fn op_provider_factory() -> ProviderFactory {
328
289
  factory.into()
329
290
  }
330
291
 
331
- fn gas_price_oracle_override(hardfork: OpSpecId) -> AccountOverride {
332
- if hardfork >= OpSpecId::ISTHMUS {
292
+ fn gas_price_oracle_override(hardfork: edr_op::Hardfork) -> AccountOverride {
293
+ if hardfork >= edr_op::Hardfork::ISTHMUS {
333
294
  gas_price_oracle_isthmus()
334
- } else if hardfork >= OpSpecId::FJORD {
295
+ } else if hardfork >= edr_op::Hardfork::FJORD {
335
296
  gas_price_oracle_fjord()
336
297
  } else {
337
298
  gas_price_oracle_ecotone()
@@ -339,16 +300,11 @@ fn gas_price_oracle_override(hardfork: OpSpecId) -> AccountOverride {
339
300
  }
340
301
 
341
302
  fn gas_price_oracle_ecotone() -> AccountOverride {
342
- let gas_price_oracle_code = hex::decode(include_str!(
343
- "../../data/op/predeploys/gas_price_oracle/ecotone.txt"
344
- ))
345
- .expect("The bytecode for the GasPriceOracle predeploy should be a valid hex string");
346
-
347
303
  AccountOverride {
348
304
  address: Uint8Array::with_data_copied(GAS_PRICE_ORACLE_ADDRESS),
349
305
  balance: None,
350
306
  nonce: None,
351
- code: Some(gas_price_oracle_code.into()),
307
+ code: Some(gas_price_oracle_code_ecotone().into()),
352
308
  storage: Some(vec![StorageSlot {
353
309
  index: BigInt::from(0u64),
354
310
  // bool isEcotone = true
@@ -360,16 +316,11 @@ fn gas_price_oracle_ecotone() -> AccountOverride {
360
316
  }
361
317
 
362
318
  fn gas_price_oracle_fjord() -> AccountOverride {
363
- let gas_price_oracle_code = hex::decode(include_str!(
364
- "../../data/op/predeploys/gas_price_oracle/fjord.txt"
365
- ))
366
- .expect("The bytecode for the GasPriceOracle predeploy should be a valid hex string");
367
-
368
319
  AccountOverride {
369
320
  address: Uint8Array::with_data_copied(GAS_PRICE_ORACLE_ADDRESS),
370
321
  balance: None,
371
322
  nonce: None,
372
- code: Some(gas_price_oracle_code.into()),
323
+ code: Some(gas_price_oracle_code_fjord().into()),
373
324
  storage: Some(vec![StorageSlot {
374
325
  index: BigInt::from(0u64),
375
326
  // bool isEcotone = true
@@ -382,16 +333,11 @@ fn gas_price_oracle_fjord() -> AccountOverride {
382
333
  }
383
334
 
384
335
  fn gas_price_oracle_isthmus() -> AccountOverride {
385
- let gas_price_oracle_code = hex::decode(include_str!(
386
- "../../data/op/predeploys/gas_price_oracle/isthmus.txt"
387
- ))
388
- .expect("The bytecode for the GasPriceOracle predeploy should be a valid hex string");
389
-
390
336
  AccountOverride {
391
337
  address: Uint8Array::with_data_copied(GAS_PRICE_ORACLE_ADDRESS),
392
338
  balance: None,
393
339
  nonce: None,
394
- code: Some(gas_price_oracle_code.into()),
340
+ code: Some(gas_price_oracle_code_isthmus().into()),
395
341
  storage: Some(vec![StorageSlot {
396
342
  index: BigInt::from(0u64),
397
343
  // bool isEcotone = true
@@ -403,6 +349,85 @@ fn gas_price_oracle_isthmus() -> AccountOverride {
403
349
  }]),
404
350
  }
405
351
  }
352
+ fn l1_block_storage(hardfork: edr_op::Hardfork) -> Vec<StorageSlot> {
353
+ let mut base_storage = vec![
354
+ StorageSlot {
355
+ index: BigInt::from(0u64),
356
+ // uint64 public number = 1
357
+ // uint64 public timestamp = 1
358
+ value: BigInt {
359
+ words: vec![
360
+ 0x0000000000000001_u64, // least significative
361
+ 0x0000000000000001_u64,
362
+ ],
363
+ sign_bit: false,
364
+ },
365
+ },
366
+ StorageSlot {
367
+ index: BigInt::from(1u64),
368
+ // uint256 baseFee = 10 gwei
369
+ value: BigInt::from(0x00000002540be400_u64),
370
+ },
371
+ StorageSlot {
372
+ index: BigInt::from(2u64),
373
+ // bytes32 hash = 0
374
+ value: BigInt::from(0u64),
375
+ },
376
+ StorageSlot {
377
+ index: BigInt::from(3u64),
378
+ // uint64 sequenceNumber = 0
379
+ // uint32 blobBaseFeeScalar = 1014213
380
+ // uint32 baseFeeScalar = 5227
381
+ value: BigInt {
382
+ words: vec![
383
+ 0x0000000000000000_u64, // least significative
384
+ 0x0000000000000000_u64,
385
+ 0x00000000000f79c5_u64,
386
+ 0x000000000000146b_u64,
387
+ ],
388
+ sign_bit: false,
389
+ },
390
+ },
391
+ StorageSlot {
392
+ index: BigInt::from(4u64),
393
+ // bytes32 batcherHash = 0
394
+ value: BigInt::from(0u64),
395
+ },
396
+ StorageSlot {
397
+ index: BigInt::from(5u64),
398
+ // uint256 l1FeeOverhead = 0
399
+ value: BigInt::from(0u64),
400
+ },
401
+ StorageSlot {
402
+ index: BigInt::from(6u64),
403
+ // uint256 l1FeeScalar = 0
404
+ value: BigInt::from(0u64),
405
+ },
406
+ StorageSlot {
407
+ index: BigInt::from(7u64),
408
+ // uint256 blobBaseFee = 10 gwei
409
+ value: BigInt::from(0x00000002540be400_u64),
410
+ },
411
+ ];
412
+ if hardfork >= edr_op::Hardfork::ISTHMUS {
413
+ base_storage.push(StorageSlot {
414
+ // Operator fee parameters
415
+ index: BigInt::from(8u64),
416
+ value: BigInt::from(0u64),
417
+ });
418
+ }
419
+ base_storage
420
+ }
421
+
422
+ fn l1_block_code(hardfork: edr_op::Hardfork) -> Uint8Array {
423
+ if hardfork >= edr_op::Hardfork::ISTHMUS {
424
+ l1_block_code_isthmus().into()
425
+ } else if hardfork >= edr_op::Hardfork::ECOTONE {
426
+ l1_block_code_ecotone().into()
427
+ } else {
428
+ l1_block_code_bedrock().into()
429
+ }
430
+ }
406
431
 
407
432
  macro_rules! export_spec_id {
408
433
  ($($variant:ident,)*) => {
package/src/config.rs CHANGED
@@ -6,10 +6,10 @@ use std::{
6
6
  };
7
7
 
8
8
  use edr_coverage::reporter::SyncOnCollectedCoverageCallback;
9
- use edr_eth::{
10
- signature::{secret_key_from_str, SecretKey},
11
- Bytes, HashMap, HashSet,
12
- };
9
+ use edr_eip1559::{BaseFeeActivation, ConstantBaseFeeParams};
10
+ use edr_gas_report::SyncOnCollectedGasReportCallback;
11
+ use edr_primitives::{Bytes, HashMap, HashSet};
12
+ use edr_signer::{secret_key_from_str, SecretKey};
13
13
  use napi::{
14
14
  bindgen_prelude::{BigInt, Promise, Reference, Uint8Array},
15
15
  threadsafe_function::{
@@ -20,7 +20,53 @@ use napi::{
20
20
  };
21
21
  use napi_derive::napi;
22
22
 
23
- use crate::{account::AccountOverride, block::BlobGas, cast::TryCast, precompile::Precompile};
23
+ use crate::{
24
+ account::AccountOverride, block::BlobGas, cast::TryCast, gas_report::GasReport,
25
+ logger::LoggerConfig, precompile::Precompile, subscription::SubscriptionConfig,
26
+ };
27
+
28
+ /// Configuration for EIP-1559 parameters
29
+ #[napi(object)]
30
+ pub struct BaseFeeParamActivation {
31
+ pub activation: Either<BaseFeeActivationByBlockNumber, BaseFeeActivationByHardfork>,
32
+ pub max_change_denominator: BigInt,
33
+ pub elasticity_multiplier: BigInt,
34
+ }
35
+
36
+ #[napi(object)]
37
+ pub struct BaseFeeActivationByBlockNumber {
38
+ /// The block number at which the `base_fee_params` is activated
39
+ pub block_number: BigInt,
40
+ }
41
+ #[napi(object)]
42
+ pub struct BaseFeeActivationByHardfork {
43
+ /// The hardfork at which the `base_fee_params` is activated
44
+ pub hardfork: String,
45
+ }
46
+
47
+ impl TryFrom<BaseFeeParamActivation> for (BaseFeeActivation<String>, ConstantBaseFeeParams) {
48
+ type Error = napi::Error;
49
+
50
+ fn try_from(value: BaseFeeParamActivation) -> Result<Self, Self::Error> {
51
+ let base_fee_params = ConstantBaseFeeParams {
52
+ max_change_denominator: value.max_change_denominator.try_cast()?,
53
+ elasticity_multiplier: value.elasticity_multiplier.try_cast()?,
54
+ };
55
+
56
+ match value.activation {
57
+ Either::A(BaseFeeActivationByBlockNumber { block_number }) => {
58
+ let activation_block_number: u64 = block_number.try_cast()?;
59
+ Ok((
60
+ BaseFeeActivation::BlockNumber(activation_block_number),
61
+ base_fee_params,
62
+ ))
63
+ }
64
+ Either::B(BaseFeeActivationByHardfork { hardfork }) => {
65
+ Ok((BaseFeeActivation::Hardfork(hardfork), base_fee_params))
66
+ }
67
+ }
68
+ }
69
+ }
24
70
 
25
71
  /// Specification of a chain with possible overrides.
26
72
  #[napi(object)]
@@ -47,6 +93,17 @@ pub struct CodeCoverageConfig {
47
93
  pub on_collected_coverage_callback: JsFunction,
48
94
  }
49
95
 
96
+ #[napi(object)]
97
+ pub struct GasReportConfig {
98
+ /// Gas reports are collected after a block is mined or `eth_call` is
99
+ /// executed.
100
+ ///
101
+ /// Exceptions thrown in the callback will be propagated to the original
102
+ /// caller.
103
+ #[napi(ts_type = "(gasReport: GasReport) => Promise<void>")]
104
+ pub on_collected_gas_report_callback: JsFunction,
105
+ }
106
+
50
107
  /// Configuration for forking a blockchain
51
108
  #[napi(object)]
52
109
  pub struct ForkConfig {
@@ -124,6 +181,8 @@ pub struct MiningConfig {
124
181
  pub struct ObservabilityConfig {
125
182
  /// If present, configures runtime observability to collect code coverage.
126
183
  pub code_coverage: Option<CodeCoverageConfig>,
184
+ /// If present, configures runtime observability to collect gas reports.
185
+ pub gas_report: Option<GasReportConfig>,
127
186
  }
128
187
 
129
188
  /// Configuration for a provider
@@ -137,6 +196,15 @@ pub struct ProviderConfig {
137
196
  pub bail_on_call_failure: bool,
138
197
  /// Whether to return an `Err` when a `eth_sendTransaction` fails
139
198
  pub bail_on_transaction_failure: bool,
199
+ /// EIP-1559 base fee parameters activations to be used to calculate the
200
+ /// block base fee.
201
+ ///
202
+ /// Provide an ordered list of `base_fee_params` to be
203
+ /// used starting from the specified activation point (hardfork or block
204
+ /// number).
205
+ /// If not provided, the default values from the chain spec
206
+ /// will be used.
207
+ pub base_fee_config: Option<Vec<BaseFeeParamActivation>>,
140
208
  /// The gas limit of each block
141
209
  pub block_gas_limit: BigInt,
142
210
  /// The chain ID of the blockchain
@@ -174,6 +242,12 @@ pub struct ProviderConfig {
174
242
  pub owned_accounts: Vec<JsString>,
175
243
  /// Overrides for precompiles
176
244
  pub precompile_overrides: Vec<Reference<Precompile>>,
245
+ /// Transaction gas cap, introduced in [EIP-7825].
246
+ ///
247
+ /// When not set, will default to value defined by the used hardfork
248
+ ///
249
+ /// [EIP-7825]: https://eips.ethereum.org/EIPS/eip-7825
250
+ pub transaction_gas_cap: Option<BigInt>,
177
251
  }
178
252
 
179
253
  impl TryFrom<ForkConfig> for edr_provider::ForkConfig<String> {
@@ -212,28 +286,28 @@ impl TryFrom<ForkConfig> for edr_provider::ForkConfig<String> {
212
286
  let condition = match condition {
213
287
  Either::A(HardforkActivationByBlockNumber {
214
288
  block_number,
215
- }) => edr_evm::hardfork::ForkCondition::Block(
289
+ }) => edr_chain_config::ForkCondition::Block(
216
290
  block_number.try_cast()?,
217
291
  ),
218
292
  Either::B(HardforkActivationByTimestamp {
219
293
  timestamp,
220
- }) => edr_evm::hardfork::ForkCondition::Timestamp(
294
+ }) => edr_chain_config::ForkCondition::Timestamp(
221
295
  timestamp.try_cast()?,
222
296
  ),
223
297
  };
224
298
 
225
- Ok(edr_evm::hardfork::Activation {
299
+ Ok(edr_chain_config::HardforkActivation {
226
300
  condition,
227
301
  hardfork,
228
302
  })
229
303
  },
230
304
  )
231
305
  .collect::<napi::Result<Vec<_>>>()
232
- .map(edr_evm::hardfork::Activations::new)
306
+ .map(edr_chain_config::HardforkActivations::new)
233
307
  })
234
308
  .transpose()?;
235
309
 
236
- let chain_config = edr_evm::hardfork::ChainOverride {
310
+ let chain_config = edr_chain_config::ChainOverride {
237
311
  name,
238
312
  hardfork_activation_overrides,
239
313
  };
@@ -271,7 +345,7 @@ impl From<MemPoolConfig> for edr_provider::MemPoolConfig {
271
345
  }
272
346
  }
273
347
 
274
- impl From<MineOrdering> for edr_evm::MineOrdering {
348
+ impl From<MineOrdering> for edr_block_miner::MineOrdering {
275
349
  fn from(value: MineOrdering) -> Self {
276
350
  match value {
277
351
  MineOrdering::Fifo => Self::Fifo,
@@ -331,6 +405,8 @@ impl ObservabilityConfig {
331
405
  .code_coverage
332
406
  .map(
333
407
  |code_coverage| -> napi::Result<Box<dyn SyncOnCollectedCoverageCallback>> {
408
+ let runtime = runtime.clone();
409
+
334
410
  let mut on_collected_coverage_callback: ThreadsafeFunction<
335
411
  _,
336
412
  ErrorStrategy::Fatal,
@@ -385,10 +461,10 @@ impl ObservabilityConfig {
385
461
  Ok(())
386
462
  });
387
463
 
388
- let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
389
-
390
464
  assert_eq!(status, napi::Status::Ok);
391
465
 
466
+ let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
467
+
392
468
  Ok(())
393
469
  });
394
470
 
@@ -396,9 +472,61 @@ impl ObservabilityConfig {
396
472
  },
397
473
  )
398
474
  .transpose()?;
475
+ let on_collected_gas_report_fn = self.gas_report.map(
476
+ |gas_report| -> napi::Result<Box<dyn SyncOnCollectedGasReportCallback>> {
477
+ let mut on_collected_gas_report_callback: ThreadsafeFunction<
478
+ _,
479
+ ErrorStrategy::Fatal,
480
+ > = gas_report
481
+ .on_collected_gas_report_callback
482
+ .create_threadsafe_function(
483
+ 0,
484
+ |ctx: ThreadSafeCallContext<GasReport>| {
485
+ let report = ctx.value;
486
+ Ok(vec![report])
487
+ }
488
+ ,
489
+ )?;
490
+ // Maintain a weak reference to the function to avoid blocking the event loop
491
+ // from exiting.
492
+ on_collected_gas_report_callback.unref(env)?;
493
+
494
+ let on_collected_gas_report_fn: Box<dyn SyncOnCollectedGasReportCallback> =
495
+ Box::new(move |report| {
496
+ let runtime = runtime.clone();
497
+
498
+ let (sender, receiver) = std::sync::mpsc::channel();
499
+
500
+ // Convert the report to the N-API representation
501
+ let status = on_collected_gas_report_callback
502
+ .call_with_return_value(GasReport::from(report), ThreadsafeFunctionCallMode::Blocking, move |result: Promise<()>| {
503
+ // We spawn a background task to handle the async callback
504
+ runtime.spawn(async move {
505
+ let result = result.await;
506
+ sender.send(result).map_err(|_error| {
507
+ napi::Error::new(
508
+ napi::Status::GenericFailure,
509
+ "Failed to send result from on_collected_gas_report_callback",
510
+ )
511
+ })
512
+ });
513
+ Ok(())
514
+ });
515
+
516
+ assert_eq!(status, napi::Status::Ok);
517
+
518
+ let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
519
+
520
+ Ok(())
521
+ });
522
+
523
+ Ok(on_collected_gas_report_fn)
524
+ },
525
+ ).transpose()?;
399
526
 
400
527
  Ok(edr_provider::observability::Config {
401
528
  on_collected_coverage_fn,
529
+ on_collected_gas_report_fn,
402
530
  ..edr_provider::observability::Config::default()
403
531
  })
404
532
  }
@@ -418,7 +546,7 @@ impl ProviderConfig {
418
546
  // This is the only place in production code where it's allowed to use
419
547
  // `DangerousSecretKeyStr`.
420
548
  #[allow(deprecated)]
421
- use edr_eth::signature::DangerousSecretKeyStr;
549
+ use edr_signer::DangerousSecretKeyStr;
422
550
 
423
551
  static_assertions::assert_not_impl_all!(JsString: Debug, Display, serde::Serialize);
424
552
  static_assertions::assert_not_impl_all!(JsStringUtf8: Debug, Display, serde::Serialize);
@@ -438,6 +566,11 @@ impl ProviderConfig {
438
566
  })
439
567
  .collect::<napi::Result<Vec<_>>>()?;
440
568
 
569
+ let base_fee_params: Option<Vec<(BaseFeeActivation<String>, ConstantBaseFeeParams)>> = self
570
+ .base_fee_config
571
+ .map(|vec| vec.into_iter().map(TryInto::try_into).collect())
572
+ .transpose()?;
573
+
441
574
  let block_gas_limit =
442
575
  NonZeroU64::new(self.block_gas_limit.try_cast()?).ok_or_else(|| {
443
576
  napi::Error::new(
@@ -450,7 +583,7 @@ impl ProviderConfig {
450
583
  .genesis_state
451
584
  .into_iter()
452
585
  .map(TryInto::try_into)
453
- .collect::<napi::Result<HashMap<edr_eth::Address, edr_provider::AccountOverride>>>()?;
586
+ .collect::<napi::Result<HashMap<edr_primitives::Address, edr_provider::AccountOverride>>>()?;
454
587
 
455
588
  let precompile_overrides = self
456
589
  .precompile_overrides
@@ -463,6 +596,7 @@ impl ProviderConfig {
463
596
  allow_unlimited_contract_size: self.allow_unlimited_contract_size,
464
597
  bail_on_call_failure: self.bail_on_call_failure,
465
598
  bail_on_transaction_failure: self.bail_on_transaction_failure,
599
+ base_fee_params,
466
600
  block_gas_limit,
467
601
  chain_id: self.chain_id.try_cast()?,
468
602
  coinbase: self.coinbase.try_cast()?,
@@ -491,6 +625,10 @@ impl ProviderConfig {
491
625
  observability: self.observability.resolve(env, runtime)?,
492
626
  owned_accounts,
493
627
  precompile_overrides,
628
+ transaction_gas_cap: self
629
+ .transaction_gas_cap
630
+ .map(TryCast::try_cast)
631
+ .transpose()?,
494
632
  })
495
633
  }
496
634
  }
@@ -541,3 +679,32 @@ impl From<BuildInfoAndOutput> for edr_napi_core::solidity::config::BuildInfoAndO
541
679
  }
542
680
  }
543
681
  }
682
+
683
+ /// Result of [`resolve_configs`].
684
+ pub struct ConfigResolution {
685
+ pub logger_config: edr_napi_core::logger::Config,
686
+ pub provider_config: edr_napi_core::provider::Config,
687
+ pub subscription_callback: edr_napi_core::subscription::Callback,
688
+ }
689
+
690
+ /// Helper function for resolving the provided N-API configs.
691
+ pub fn resolve_configs(
692
+ env: &napi::Env,
693
+ runtime: runtime::Handle,
694
+ provider_config: ProviderConfig,
695
+ logger_config: LoggerConfig,
696
+ subscription_config: SubscriptionConfig,
697
+ ) -> napi::Result<ConfigResolution> {
698
+ let provider_config = provider_config.resolve(env, runtime)?;
699
+ let logger_config = logger_config.resolve(env)?;
700
+
701
+ let subscription_config = edr_napi_core::subscription::Config::from(subscription_config);
702
+ let subscription_callback =
703
+ edr_napi_core::subscription::Callback::new(env, subscription_config.subscription_callback)?;
704
+
705
+ Ok(ConfigResolution {
706
+ logger_config,
707
+ provider_config,
708
+ subscription_callback,
709
+ })
710
+ }