@nomicfoundation/edr 0.12.0-next.0 → 0.12.0-next.10
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 +217 -64
- package/index.js +4 -1
- package/package.json +26 -21
- package/src/account.rs +6 -5
- 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 +84 -78
- package/src/chains/op.rs +50 -51
- package/src/config.rs +166 -9
- package/src/context.rs +96 -89
- 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 +1 -1
- package/src/provider/response.rs +4 -4
- package/src/provider.rs +51 -4
- package/src/result.rs +35 -80
- package/src/serde.rs +1 -1
- package/src/solidity_tests/config.rs +80 -12
- package/src/solidity_tests/l1.rs +7 -7
- package/src/solidity_tests/op.rs +5 -5
- package/src/solidity_tests/runner.rs +1 -1
- package/src/solidity_tests/test_results.rs +109 -41
- 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 +6 -5
- package/src/ts/solidity_tests.ts +46 -0
- package/src/withdrawal.rs +5 -5
- package/Cargo.toml +0 -92
- package/build.rs +0 -3
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
|
|
@@ -331,6 +399,8 @@ impl ObservabilityConfig {
|
|
|
331
399
|
.code_coverage
|
|
332
400
|
.map(
|
|
333
401
|
|code_coverage| -> napi::Result<Box<dyn SyncOnCollectedCoverageCallback>> {
|
|
402
|
+
let runtime = runtime.clone();
|
|
403
|
+
|
|
334
404
|
let mut on_collected_coverage_callback: ThreadsafeFunction<
|
|
335
405
|
_,
|
|
336
406
|
ErrorStrategy::Fatal,
|
|
@@ -385,10 +455,10 @@ impl ObservabilityConfig {
|
|
|
385
455
|
Ok(())
|
|
386
456
|
});
|
|
387
457
|
|
|
388
|
-
let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
|
|
389
|
-
|
|
390
458
|
assert_eq!(status, napi::Status::Ok);
|
|
391
459
|
|
|
460
|
+
let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
|
|
461
|
+
|
|
392
462
|
Ok(())
|
|
393
463
|
});
|
|
394
464
|
|
|
@@ -396,9 +466,61 @@ impl ObservabilityConfig {
|
|
|
396
466
|
},
|
|
397
467
|
)
|
|
398
468
|
.transpose()?;
|
|
469
|
+
let on_collected_gas_report_fn = self.gas_report.map(
|
|
470
|
+
|gas_report| -> napi::Result<Box<dyn SyncOnCollectedGasReportCallback>> {
|
|
471
|
+
let mut on_collected_gas_report_callback: ThreadsafeFunction<
|
|
472
|
+
_,
|
|
473
|
+
ErrorStrategy::Fatal,
|
|
474
|
+
> = gas_report
|
|
475
|
+
.on_collected_gas_report_callback
|
|
476
|
+
.create_threadsafe_function(
|
|
477
|
+
0,
|
|
478
|
+
|ctx: ThreadSafeCallContext<GasReport>| {
|
|
479
|
+
let report = ctx.value;
|
|
480
|
+
Ok(vec![report])
|
|
481
|
+
}
|
|
482
|
+
,
|
|
483
|
+
)?;
|
|
484
|
+
// Maintain a weak reference to the function to avoid blocking the event loop
|
|
485
|
+
// from exiting.
|
|
486
|
+
on_collected_gas_report_callback.unref(env)?;
|
|
487
|
+
|
|
488
|
+
let on_collected_gas_report_fn: Box<dyn SyncOnCollectedGasReportCallback> =
|
|
489
|
+
Box::new(move |report| {
|
|
490
|
+
let runtime = runtime.clone();
|
|
491
|
+
|
|
492
|
+
let (sender, receiver) = std::sync::mpsc::channel();
|
|
493
|
+
|
|
494
|
+
// Convert the report to the N-API representation
|
|
495
|
+
let status = on_collected_gas_report_callback
|
|
496
|
+
.call_with_return_value(GasReport::from(report), ThreadsafeFunctionCallMode::Blocking, move |result: Promise<()>| {
|
|
497
|
+
// We spawn a background task to handle the async callback
|
|
498
|
+
runtime.spawn(async move {
|
|
499
|
+
let result = result.await;
|
|
500
|
+
sender.send(result).map_err(|_error| {
|
|
501
|
+
napi::Error::new(
|
|
502
|
+
napi::Status::GenericFailure,
|
|
503
|
+
"Failed to send result from on_collected_gas_report_callback",
|
|
504
|
+
)
|
|
505
|
+
})
|
|
506
|
+
});
|
|
507
|
+
Ok(())
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
assert_eq!(status, napi::Status::Ok);
|
|
511
|
+
|
|
512
|
+
let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
|
|
513
|
+
|
|
514
|
+
Ok(())
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
Ok(on_collected_gas_report_fn)
|
|
518
|
+
},
|
|
519
|
+
).transpose()?;
|
|
399
520
|
|
|
400
521
|
Ok(edr_provider::observability::Config {
|
|
401
522
|
on_collected_coverage_fn,
|
|
523
|
+
on_collected_gas_report_fn,
|
|
402
524
|
..edr_provider::observability::Config::default()
|
|
403
525
|
})
|
|
404
526
|
}
|
|
@@ -418,7 +540,7 @@ impl ProviderConfig {
|
|
|
418
540
|
// This is the only place in production code where it's allowed to use
|
|
419
541
|
// `DangerousSecretKeyStr`.
|
|
420
542
|
#[allow(deprecated)]
|
|
421
|
-
use
|
|
543
|
+
use edr_signer::DangerousSecretKeyStr;
|
|
422
544
|
|
|
423
545
|
static_assertions::assert_not_impl_all!(JsString: Debug, Display, serde::Serialize);
|
|
424
546
|
static_assertions::assert_not_impl_all!(JsStringUtf8: Debug, Display, serde::Serialize);
|
|
@@ -438,6 +560,11 @@ impl ProviderConfig {
|
|
|
438
560
|
})
|
|
439
561
|
.collect::<napi::Result<Vec<_>>>()?;
|
|
440
562
|
|
|
563
|
+
let base_fee_params: Option<Vec<(BaseFeeActivation<String>, ConstantBaseFeeParams)>> = self
|
|
564
|
+
.base_fee_config
|
|
565
|
+
.map(|vec| vec.into_iter().map(TryInto::try_into).collect())
|
|
566
|
+
.transpose()?;
|
|
567
|
+
|
|
441
568
|
let block_gas_limit =
|
|
442
569
|
NonZeroU64::new(self.block_gas_limit.try_cast()?).ok_or_else(|| {
|
|
443
570
|
napi::Error::new(
|
|
@@ -450,7 +577,7 @@ impl ProviderConfig {
|
|
|
450
577
|
.genesis_state
|
|
451
578
|
.into_iter()
|
|
452
579
|
.map(TryInto::try_into)
|
|
453
|
-
.collect::<napi::Result<HashMap<
|
|
580
|
+
.collect::<napi::Result<HashMap<edr_primitives::Address, edr_provider::AccountOverride>>>()?;
|
|
454
581
|
|
|
455
582
|
let precompile_overrides = self
|
|
456
583
|
.precompile_overrides
|
|
@@ -463,6 +590,7 @@ impl ProviderConfig {
|
|
|
463
590
|
allow_unlimited_contract_size: self.allow_unlimited_contract_size,
|
|
464
591
|
bail_on_call_failure: self.bail_on_call_failure,
|
|
465
592
|
bail_on_transaction_failure: self.bail_on_transaction_failure,
|
|
593
|
+
base_fee_params,
|
|
466
594
|
block_gas_limit,
|
|
467
595
|
chain_id: self.chain_id.try_cast()?,
|
|
468
596
|
coinbase: self.coinbase.try_cast()?,
|
|
@@ -541,3 +669,32 @@ impl From<BuildInfoAndOutput> for edr_napi_core::solidity::config::BuildInfoAndO
|
|
|
541
669
|
}
|
|
542
670
|
}
|
|
543
671
|
}
|
|
672
|
+
|
|
673
|
+
/// Result of [`resolve_configs`].
|
|
674
|
+
pub struct ConfigResolution {
|
|
675
|
+
pub logger_config: edr_napi_core::logger::Config,
|
|
676
|
+
pub provider_config: edr_napi_core::provider::Config,
|
|
677
|
+
pub subscription_callback: edr_napi_core::subscription::Callback,
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/// Helper function for resolving the provided N-API configs.
|
|
681
|
+
pub fn resolve_configs(
|
|
682
|
+
env: &napi::Env,
|
|
683
|
+
runtime: runtime::Handle,
|
|
684
|
+
provider_config: ProviderConfig,
|
|
685
|
+
logger_config: LoggerConfig,
|
|
686
|
+
subscription_config: SubscriptionConfig,
|
|
687
|
+
) -> napi::Result<ConfigResolution> {
|
|
688
|
+
let provider_config = provider_config.resolve(env, runtime)?;
|
|
689
|
+
let logger_config = logger_config.resolve(env)?;
|
|
690
|
+
|
|
691
|
+
let subscription_config = edr_napi_core::subscription::Config::from(subscription_config);
|
|
692
|
+
let subscription_callback =
|
|
693
|
+
edr_napi_core::subscription::Callback::new(env, subscription_config.subscription_callback)?;
|
|
694
|
+
|
|
695
|
+
Ok(ConfigResolution {
|
|
696
|
+
logger_config,
|
|
697
|
+
provider_config,
|
|
698
|
+
subscription_callback,
|
|
699
|
+
})
|
|
700
|
+
}
|
package/src/context.rs
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
use std::sync::Arc;
|
|
2
2
|
|
|
3
|
-
use
|
|
4
|
-
use
|
|
5
|
-
provider::{self, SyncProviderFactory},
|
|
6
|
-
solidity,
|
|
7
|
-
};
|
|
8
|
-
use edr_solidity::contract_decoder::ContractDecoder;
|
|
3
|
+
use edr_napi_core::{provider::SyncProviderFactory, solidity};
|
|
4
|
+
use edr_primitives::HashMap;
|
|
9
5
|
use edr_solidity_tests::{
|
|
10
6
|
decode::RevertDecoder,
|
|
11
7
|
multi_runner::{SuiteResultAndArtifactId, TestContract, TestContracts},
|
|
@@ -22,14 +18,15 @@ use napi_derive::napi;
|
|
|
22
18
|
use tracing_subscriber::{prelude::*, EnvFilter, Registry};
|
|
23
19
|
|
|
24
20
|
use crate::{
|
|
25
|
-
config::{ProviderConfig, TracingConfigWithBuffers},
|
|
21
|
+
config::{resolve_configs, ConfigResolution, ProviderConfig, TracingConfigWithBuffers},
|
|
22
|
+
contract_decoder::ContractDecoder,
|
|
26
23
|
logger::LoggerConfig,
|
|
27
24
|
provider::{Provider, ProviderFactory},
|
|
28
25
|
solidity_tests::{
|
|
29
26
|
artifact::{Artifact, ArtifactId},
|
|
30
27
|
config::SolidityTestRunnerConfigArgs,
|
|
31
28
|
factory::SolidityTestRunnerFactory,
|
|
32
|
-
test_results::SuiteResult,
|
|
29
|
+
test_results::{SolidityTestResult, SuiteResult},
|
|
33
30
|
LinkingOutput,
|
|
34
31
|
},
|
|
35
32
|
subscription::SubscriptionConfig,
|
|
@@ -42,7 +39,7 @@ pub struct EdrContext {
|
|
|
42
39
|
|
|
43
40
|
#[napi]
|
|
44
41
|
impl EdrContext {
|
|
45
|
-
|
|
42
|
+
/// Creates a new [`EdrContext`] instance. Should only be called once!
|
|
46
43
|
#[napi(catch_unwind, constructor)]
|
|
47
44
|
pub fn new() -> napi::Result<Self> {
|
|
48
45
|
let context = Context::new()?;
|
|
@@ -52,7 +49,7 @@ impl EdrContext {
|
|
|
52
49
|
})
|
|
53
50
|
}
|
|
54
51
|
|
|
55
|
-
|
|
52
|
+
/// Constructs a new provider with the provided configuration.
|
|
56
53
|
#[napi(catch_unwind, ts_return_type = "Promise<Provider>")]
|
|
57
54
|
pub fn create_provider(
|
|
58
55
|
&self,
|
|
@@ -61,7 +58,7 @@ impl EdrContext {
|
|
|
61
58
|
provider_config: ProviderConfig,
|
|
62
59
|
logger_config: LoggerConfig,
|
|
63
60
|
subscription_config: SubscriptionConfig,
|
|
64
|
-
|
|
61
|
+
contract_decoder: &ContractDecoder,
|
|
65
62
|
) -> napi::Result<JsObject> {
|
|
66
63
|
let (deferred, promise) = env.create_deferred()?;
|
|
67
64
|
|
|
@@ -78,25 +75,18 @@ impl EdrContext {
|
|
|
78
75
|
}
|
|
79
76
|
|
|
80
77
|
let runtime = runtime::Handle::current();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
let contract_decoder = try_or_reject_promise!(ContractDecoder::new(&build_info_config)
|
|
96
|
-
.map_or_else(
|
|
97
|
-
|error| Err(napi::Error::from_reason(error.to_string())),
|
|
98
|
-
|contract_decoder| Ok(Arc::new(contract_decoder))
|
|
99
|
-
));
|
|
78
|
+
|
|
79
|
+
let ConfigResolution {
|
|
80
|
+
logger_config,
|
|
81
|
+
provider_config,
|
|
82
|
+
subscription_callback,
|
|
83
|
+
} = try_or_reject_promise!(resolve_configs(
|
|
84
|
+
&env,
|
|
85
|
+
runtime.clone(),
|
|
86
|
+
provider_config,
|
|
87
|
+
logger_config,
|
|
88
|
+
subscription_config,
|
|
89
|
+
));
|
|
100
90
|
|
|
101
91
|
#[cfg(feature = "scenarios")]
|
|
102
92
|
let scenario_file =
|
|
@@ -106,31 +96,33 @@ impl EdrContext {
|
|
|
106
96
|
logger_config.enable,
|
|
107
97
|
)));
|
|
108
98
|
|
|
109
|
-
let
|
|
99
|
+
let factory = {
|
|
110
100
|
// TODO: https://github.com/NomicFoundation/edr/issues/760
|
|
111
101
|
// TODO: Don't block the JS event loop
|
|
112
102
|
let context = runtime.block_on(async { self.inner.lock().await });
|
|
113
103
|
|
|
114
|
-
try_or_reject_promise!(context.
|
|
115
|
-
&env,
|
|
116
|
-
&chain_type,
|
|
117
|
-
provider_config,
|
|
118
|
-
logger_config,
|
|
119
|
-
subscription_config.into(),
|
|
120
|
-
&contract_decoder,
|
|
121
|
-
))
|
|
104
|
+
try_or_reject_promise!(context.get_provider_factory(&chain_type))
|
|
122
105
|
};
|
|
123
106
|
|
|
107
|
+
let contract_decoder = Arc::clone(contract_decoder.as_inner());
|
|
124
108
|
runtime.clone().spawn_blocking(move || {
|
|
125
|
-
let result =
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
109
|
+
let result = factory
|
|
110
|
+
.create_provider(
|
|
111
|
+
runtime.clone(),
|
|
112
|
+
provider_config,
|
|
113
|
+
logger_config,
|
|
114
|
+
subscription_callback,
|
|
115
|
+
Arc::clone(&contract_decoder),
|
|
132
116
|
)
|
|
133
|
-
|
|
117
|
+
.map(|provider| {
|
|
118
|
+
Provider::new(
|
|
119
|
+
provider,
|
|
120
|
+
runtime,
|
|
121
|
+
contract_decoder,
|
|
122
|
+
#[cfg(feature = "scenarios")]
|
|
123
|
+
scenario_file,
|
|
124
|
+
)
|
|
125
|
+
});
|
|
134
126
|
|
|
135
127
|
deferred.resolve(|_env| result);
|
|
136
128
|
});
|
|
@@ -138,7 +130,7 @@ impl EdrContext {
|
|
|
138
130
|
Ok(promise)
|
|
139
131
|
}
|
|
140
132
|
|
|
141
|
-
|
|
133
|
+
/// Registers a new provider factory for the provided chain type.
|
|
142
134
|
#[napi(catch_unwind)]
|
|
143
135
|
pub async fn register_provider_factory(
|
|
144
136
|
&self,
|
|
@@ -161,14 +153,29 @@ impl EdrContext {
|
|
|
161
153
|
Ok(())
|
|
162
154
|
}
|
|
163
155
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
156
|
+
/// Executes Solidity tests
|
|
157
|
+
///
|
|
158
|
+
/// The function will return a promise that resolves to a
|
|
159
|
+
/// [`SolidityTestResult`].
|
|
160
|
+
///
|
|
161
|
+
/// Arguments:
|
|
162
|
+
/// - `chainType`: the same chain type that was passed to
|
|
163
|
+
/// `registerProviderFactory`.
|
|
164
|
+
/// - `artifacts`: the project's compilation output artifacts. It's
|
|
165
|
+
/// important to include include all artifacts here, otherwise cheatcodes
|
|
166
|
+
/// that access artifacts and other functionality (e.g. auto-linking, gas
|
|
167
|
+
/// reports) can break.
|
|
168
|
+
/// - `testSuites`: the test suite ids that specify which test suites to
|
|
169
|
+
/// execute. The test suite artifacts must be present in `artifacts`.
|
|
170
|
+
/// - `configArgs`: solidity test runner configuration. See the struct docs
|
|
171
|
+
/// for details.
|
|
172
|
+
/// - `tracingConfig`: the build infos used for stack trace generation.
|
|
173
|
+
/// These are lazily parsed and it's important that they're passed as
|
|
174
|
+
/// Uint8 arrays for performance.
|
|
175
|
+
/// - `onTestSuiteCompletedCallback`: The progress callback will be called
|
|
176
|
+
/// with the results of each test suite as soon as it finished executing.
|
|
170
177
|
#[allow(clippy::too_many_arguments)]
|
|
171
|
-
#[napi(catch_unwind, ts_return_type = "Promise<
|
|
178
|
+
#[napi(catch_unwind, ts_return_type = "Promise<SolidityTestResult>")]
|
|
172
179
|
pub fn run_solidity_tests(
|
|
173
180
|
&self,
|
|
174
181
|
env: Env,
|
|
@@ -281,11 +288,12 @@ impl EdrContext {
|
|
|
281
288
|
|
|
282
289
|
let include_traces = config.include_traces.into();
|
|
283
290
|
|
|
291
|
+
let runtime_for_factory = runtime.clone();
|
|
284
292
|
let test_runner = try_or_reject_deferred!(runtime
|
|
285
293
|
.clone()
|
|
286
294
|
.spawn_blocking(move || {
|
|
287
295
|
factory.create_test_runner(
|
|
288
|
-
|
|
296
|
+
runtime_for_factory,
|
|
289
297
|
config,
|
|
290
298
|
contracts,
|
|
291
299
|
linking_output.known_contracts,
|
|
@@ -297,30 +305,40 @@ impl EdrContext {
|
|
|
297
305
|
.await
|
|
298
306
|
.expect("Failed to join test runner factory thread"));
|
|
299
307
|
|
|
300
|
-
let
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
308
|
+
let runtime_for_runner = runtime.clone();
|
|
309
|
+
let test_result = try_or_reject_deferred!(runtime
|
|
310
|
+
.clone()
|
|
311
|
+
.spawn_blocking(move || {
|
|
312
|
+
test_runner.run_tests(
|
|
313
|
+
runtime_for_runner,
|
|
314
|
+
test_filter,
|
|
315
|
+
Arc::new(
|
|
316
|
+
move |SuiteResultAndArtifactId {
|
|
317
|
+
artifact_id,
|
|
318
|
+
result,
|
|
319
|
+
}| {
|
|
320
|
+
let suite_result =
|
|
321
|
+
SuiteResult::new(artifact_id, result, include_traces);
|
|
322
|
+
|
|
323
|
+
let status = on_test_suite_completed_callback
|
|
324
|
+
.call(suite_result, ThreadsafeFunctionCallMode::Blocking);
|
|
325
|
+
|
|
326
|
+
// This should always succeed since we're using an unbounded queue.
|
|
327
|
+
// We add an assertion for
|
|
328
|
+
// completeness.
|
|
329
|
+
assert_eq!(
|
|
315
330
|
status,
|
|
316
331
|
napi::Status::Ok,
|
|
317
332
|
"Failed to call on_test_suite_completed_callback with status: {status}"
|
|
318
333
|
);
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
334
|
+
},
|
|
335
|
+
),
|
|
336
|
+
)
|
|
337
|
+
})
|
|
338
|
+
.await
|
|
339
|
+
.expect("Failed to join test runner thread"));
|
|
322
340
|
|
|
323
|
-
deferred.resolve(move |_env| Ok(()));
|
|
341
|
+
deferred.resolve(move |_env| Ok(SolidityTestResult::from(test_result)));
|
|
324
342
|
});
|
|
325
343
|
|
|
326
344
|
Ok(promise)
|
|
@@ -399,23 +417,12 @@ impl Context {
|
|
|
399
417
|
|
|
400
418
|
/// Tries to create a new provider for the provided chain type and
|
|
401
419
|
/// configuration.
|
|
402
|
-
pub fn
|
|
420
|
+
pub fn get_provider_factory(
|
|
403
421
|
&self,
|
|
404
|
-
env: &napi::Env,
|
|
405
422
|
chain_type: &str,
|
|
406
|
-
|
|
407
|
-
logger_config: edr_napi_core::logger::Config,
|
|
408
|
-
subscription_config: edr_napi_core::subscription::Config,
|
|
409
|
-
contract_decoder: &Arc<ContractDecoder>,
|
|
410
|
-
) -> napi::Result<Box<dyn provider::Builder>> {
|
|
423
|
+
) -> napi::Result<Arc<dyn SyncProviderFactory>> {
|
|
411
424
|
if let Some(factory) = self.provider_factories.get(chain_type) {
|
|
412
|
-
factory
|
|
413
|
-
env,
|
|
414
|
-
provider_config,
|
|
415
|
-
logger_config,
|
|
416
|
-
subscription_config,
|
|
417
|
-
contract_decoder.clone(),
|
|
418
|
-
)
|
|
425
|
+
Ok(Arc::clone(factory))
|
|
419
426
|
} else {
|
|
420
427
|
Err(napi::Error::new(
|
|
421
428
|
napi::Status::GenericFailure,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
use std::sync::Arc;
|
|
2
|
+
|
|
3
|
+
use napi_derive::napi;
|
|
4
|
+
|
|
5
|
+
use crate::config::TracingConfigWithBuffers;
|
|
6
|
+
|
|
7
|
+
#[napi]
|
|
8
|
+
pub struct ContractDecoder {
|
|
9
|
+
inner: Arc<edr_solidity::contract_decoder::ContractDecoder>,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#[napi]
|
|
13
|
+
impl ContractDecoder {
|
|
14
|
+
#[doc = "Creates an empty instance."]
|
|
15
|
+
#[napi(constructor, catch_unwind)]
|
|
16
|
+
// Following TS convention for the constructor without arguments to be `new()`.
|
|
17
|
+
#[allow(clippy::new_without_default)]
|
|
18
|
+
pub fn new() -> Self {
|
|
19
|
+
Self {
|
|
20
|
+
inner: Arc::new(edr_solidity::contract_decoder::ContractDecoder::default()),
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#[doc = "Creates a new instance with the provided configuration."]
|
|
25
|
+
#[napi(factory, catch_unwind)]
|
|
26
|
+
pub fn with_contracts(config: TracingConfigWithBuffers) -> napi::Result<Self> {
|
|
27
|
+
let build_info_config = edr_solidity::artifacts::BuildInfoConfig::parse_from_buffers(
|
|
28
|
+
(&edr_napi_core::solidity::config::TracingConfigWithBuffers::from(config)).into(),
|
|
29
|
+
)
|
|
30
|
+
.map_err(|error| napi::Error::from_reason(error.to_string()))?;
|
|
31
|
+
|
|
32
|
+
let contract_decoder =
|
|
33
|
+
edr_solidity::contract_decoder::ContractDecoder::new(&build_info_config).map_or_else(
|
|
34
|
+
|error| Err(napi::Error::from_reason(error.to_string())),
|
|
35
|
+
|contract_decoder| Ok(Arc::new(contract_decoder)),
|
|
36
|
+
)?;
|
|
37
|
+
|
|
38
|
+
Ok(Self {
|
|
39
|
+
inner: contract_decoder,
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
impl ContractDecoder {
|
|
45
|
+
/// Returns a reference to the inner contract decoder.
|
|
46
|
+
pub fn as_inner(&self) -> &Arc<edr_solidity::contract_decoder::ContractDecoder> {
|
|
47
|
+
&self.inner
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
impl From<Arc<edr_solidity::contract_decoder::ContractDecoder>> for ContractDecoder {
|
|
52
|
+
fn from(contract_decoder: Arc<edr_solidity::contract_decoder::ContractDecoder>) -> Self {
|
|
53
|
+
Self {
|
|
54
|
+
inner: contract_decoder,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/debug_trace.rs
CHANGED