@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/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::
|
|
6
|
-
provider::{
|
|
7
|
-
subscription,
|
|
4
|
+
logger::Logger,
|
|
5
|
+
provider::{SyncProvider, SyncProviderFactory},
|
|
6
|
+
subscription::subscriber_callback_for_chain_spec,
|
|
8
7
|
};
|
|
9
|
-
use edr_op::{
|
|
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::
|
|
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
|
|
33
|
+
fn create_provider(
|
|
23
34
|
&self,
|
|
24
|
-
|
|
25
|
-
provider_config: provider::Config,
|
|
26
|
-
logger_config: logger::Config,
|
|
27
|
-
|
|
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<
|
|
30
|
-
let logger =
|
|
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 =
|
|
44
|
+
let provider_config =
|
|
45
|
+
edr_provider::ProviderConfig::<edr_op::Hardfork>::try_from(provider_config)?;
|
|
33
46
|
|
|
34
|
-
let
|
|
35
|
-
|
|
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
|
-
|
|
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
|
|
74
|
+
impl From<OpHardfork> for edr_op::Hardfork {
|
|
60
75
|
fn from(hardfork: OpHardfork) -> Self {
|
|
61
76
|
match hardfork {
|
|
62
|
-
OpHardfork::Bedrock =>
|
|
63
|
-
OpHardfork::Regolith =>
|
|
64
|
-
OpHardfork::Canyon =>
|
|
65
|
-
OpHardfork::Ecotone =>
|
|
66
|
-
OpHardfork::Fjord =>
|
|
67
|
-
OpHardfork::Granite =>
|
|
68
|
-
OpHardfork::Holocene =>
|
|
69
|
-
OpHardfork::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::
|
|
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 =
|
|
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:
|
|
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
|
|
139
|
-
storage: Some(
|
|
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:
|
|
332
|
-
if hardfork >=
|
|
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 >=
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
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::{
|
|
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
|
-
}) =>
|
|
289
|
+
}) => edr_chain_config::ForkCondition::Block(
|
|
216
290
|
block_number.try_cast()?,
|
|
217
291
|
),
|
|
218
292
|
Either::B(HardforkActivationByTimestamp {
|
|
219
293
|
timestamp,
|
|
220
|
-
}) =>
|
|
294
|
+
}) => edr_chain_config::ForkCondition::Timestamp(
|
|
221
295
|
timestamp.try_cast()?,
|
|
222
296
|
),
|
|
223
297
|
};
|
|
224
298
|
|
|
225
|
-
Ok(
|
|
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(
|
|
306
|
+
.map(edr_chain_config::HardforkActivations::new)
|
|
233
307
|
})
|
|
234
308
|
.transpose()?;
|
|
235
309
|
|
|
236
|
-
let chain_config =
|
|
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
|
|
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
|
|
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<
|
|
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
|
+
}
|