@nomicfoundation/edr 0.2.0-alpha.2
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/config.toml +8 -0
- package/.mocharc.json +4 -0
- package/Cargo.toml +50 -0
- package/LICENSE +1 -0
- package/artifacts/bindings-aarch64-apple-darwin/edr.darwin-arm64.node +0 -0
- package/artifacts/bindings-aarch64-pc-windows-msvc/edr.win32-arm64-msvc.node +0 -0
- package/artifacts/bindings-aarch64-unknown-linux-gnu/edr.linux-arm64-gnu.node +0 -0
- package/artifacts/bindings-aarch64-unknown-linux-musl/edr.linux-arm64-musl.node +0 -0
- package/artifacts/bindings-i686-pc-windows-msvc/edr.win32-ia32-msvc.node +0 -0
- package/artifacts/bindings-x86_64-apple-darwin/edr.darwin-x64.node +0 -0
- package/artifacts/bindings-x86_64-pc-windows-msvc/edr.win32-x64-msvc.node +0 -0
- package/artifacts/bindings-x86_64-unknown-linux-gnu/edr.linux-x64-gnu.node +0 -0
- package/artifacts/bindings-x86_64-unknown-linux-musl/edr.linux-x64-musl.node +0 -0
- package/build.rs +3 -0
- package/index.d.ts +383 -0
- package/index.js +264 -0
- package/npm/darwin-arm64/README.md +3 -0
- package/npm/darwin-arm64/edr.darwin-arm64.node +0 -0
- package/npm/darwin-arm64/package.json +22 -0
- package/npm/darwin-x64/README.md +3 -0
- package/npm/darwin-x64/edr.darwin-x64.node +0 -0
- package/npm/darwin-x64/package.json +22 -0
- package/npm/linux-arm64-gnu/README.md +3 -0
- package/npm/linux-arm64-gnu/edr.linux-arm64-gnu.node +0 -0
- package/npm/linux-arm64-gnu/package.json +25 -0
- package/npm/linux-arm64-musl/README.md +3 -0
- package/npm/linux-arm64-musl/edr.linux-arm64-musl.node +0 -0
- package/npm/linux-arm64-musl/package.json +25 -0
- package/npm/linux-x64-gnu/README.md +3 -0
- package/npm/linux-x64-gnu/edr.linux-x64-gnu.node +0 -0
- package/npm/linux-x64-gnu/package.json +25 -0
- package/npm/linux-x64-musl/README.md +3 -0
- package/npm/linux-x64-musl/edr.linux-x64-musl.node +0 -0
- package/npm/linux-x64-musl/package.json +25 -0
- package/npm/win32-arm64-msvc/README.md +3 -0
- package/npm/win32-arm64-msvc/edr.win32-arm64-msvc.node +0 -0
- package/npm/win32-arm64-msvc/package.json +22 -0
- package/npm/win32-ia32-msvc/README.md +3 -0
- package/npm/win32-ia32-msvc/edr.win32-ia32-msvc.node +0 -0
- package/npm/win32-ia32-msvc/package.json +22 -0
- package/npm/win32-x64-msvc/README.md +3 -0
- package/npm/win32-x64-msvc/edr.win32-x64-msvc.node +0 -0
- package/npm/win32-x64-msvc/package.json +22 -0
- package/package.json +61 -0
- package/src/account.rs +28 -0
- package/src/block.rs +110 -0
- package/src/cast.rs +119 -0
- package/src/config.rs +70 -0
- package/src/context.rs +74 -0
- package/src/debug_trace.rs +38 -0
- package/src/lib.rs +18 -0
- package/src/log.rs +41 -0
- package/src/logger.rs +1277 -0
- package/src/provider/config.rs +271 -0
- package/src/provider.rs +185 -0
- package/src/result.rs +254 -0
- package/src/subscribe.rs +60 -0
- package/src/sync.rs +85 -0
- package/src/threadsafe_function.rs +305 -0
- package/src/trace.rs +168 -0
- package/test/provider.ts +104 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
path::PathBuf,
|
|
3
|
+
time::{Duration, SystemTime},
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
use edr_eth::HashMap;
|
|
7
|
+
use edr_provider::AccountConfig;
|
|
8
|
+
use napi::{
|
|
9
|
+
bindgen_prelude::{BigInt, Buffer},
|
|
10
|
+
Either,
|
|
11
|
+
};
|
|
12
|
+
use napi_derive::napi;
|
|
13
|
+
|
|
14
|
+
use crate::{account::GenesisAccount, block::BlobGas, cast::TryCast, config::SpecId};
|
|
15
|
+
|
|
16
|
+
/// Configuration for a chain
|
|
17
|
+
#[napi(object)]
|
|
18
|
+
pub struct ChainConfig {
|
|
19
|
+
/// The chain ID
|
|
20
|
+
pub chain_id: BigInt,
|
|
21
|
+
/// The chain's supported hardforks
|
|
22
|
+
pub hardforks: Vec<HardforkActivation>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// Configuration for forking a blockchain
|
|
26
|
+
#[napi(object)]
|
|
27
|
+
pub struct ForkConfig {
|
|
28
|
+
/// The URL of the JSON-RPC endpoint to fork from
|
|
29
|
+
pub json_rpc_url: String,
|
|
30
|
+
/// The block number to fork from. If not provided, the latest safe block is
|
|
31
|
+
/// used.
|
|
32
|
+
pub block_number: Option<BigInt>,
|
|
33
|
+
/// The HTTP headers to use when making requests to the JSON-RPC endpoint
|
|
34
|
+
pub http_headers: Option<Vec<HttpHeader>>,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[napi(object)]
|
|
38
|
+
pub struct HttpHeader {
|
|
39
|
+
pub name: String,
|
|
40
|
+
pub value: String,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Configuration for a hardfork activation
|
|
44
|
+
#[napi(object)]
|
|
45
|
+
pub struct HardforkActivation {
|
|
46
|
+
/// The block number at which the hardfork is activated
|
|
47
|
+
pub block_number: BigInt,
|
|
48
|
+
/// The activated hardfork
|
|
49
|
+
pub spec_id: SpecId,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#[napi(string_enum)]
|
|
53
|
+
#[doc = "The type of ordering to use when selecting blocks to mine."]
|
|
54
|
+
pub enum MineOrdering {
|
|
55
|
+
#[doc = "Insertion order"]
|
|
56
|
+
Fifo,
|
|
57
|
+
#[doc = "Effective miner fee"]
|
|
58
|
+
Priority,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// Configuration for the provider's mempool.
|
|
62
|
+
#[napi(object)]
|
|
63
|
+
pub struct MemPoolConfig {
|
|
64
|
+
pub order: MineOrdering,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#[napi(object)]
|
|
68
|
+
pub struct IntervalRange {
|
|
69
|
+
pub min: BigInt,
|
|
70
|
+
pub max: BigInt,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// Configuration for the provider's miner.
|
|
74
|
+
#[napi(object)]
|
|
75
|
+
pub struct MiningConfig {
|
|
76
|
+
pub auto_mine: bool,
|
|
77
|
+
pub interval: Option<Either<BigInt, IntervalRange>>,
|
|
78
|
+
pub mem_pool: MemPoolConfig,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Configuration for a provider
|
|
82
|
+
#[napi(object)]
|
|
83
|
+
pub struct ProviderConfig {
|
|
84
|
+
/// Whether to allow blocks with the same timestamp
|
|
85
|
+
pub allow_blocks_with_same_timestamp: bool,
|
|
86
|
+
/// Whether to allow unlimited contract size
|
|
87
|
+
pub allow_unlimited_contract_size: bool,
|
|
88
|
+
/// Whether to return an `Err` when `eth_call` fails
|
|
89
|
+
pub bail_on_call_failure: bool,
|
|
90
|
+
/// Whether to return an `Err` when a `eth_sendTransaction` fails
|
|
91
|
+
pub bail_on_transaction_failure: bool,
|
|
92
|
+
/// The gas limit of each block
|
|
93
|
+
pub block_gas_limit: BigInt,
|
|
94
|
+
/// The directory to cache remote JSON-RPC responses
|
|
95
|
+
pub cache_dir: Option<String>,
|
|
96
|
+
/// The chain ID of the blockchain
|
|
97
|
+
pub chain_id: BigInt,
|
|
98
|
+
/// The configuration for chains
|
|
99
|
+
pub chains: Vec<ChainConfig>,
|
|
100
|
+
/// The address of the coinbase
|
|
101
|
+
pub coinbase: Buffer,
|
|
102
|
+
/// The configuration for forking a blockchain. If not provided, a local
|
|
103
|
+
/// blockchain will be created
|
|
104
|
+
pub fork: Option<ForkConfig>,
|
|
105
|
+
/// The genesis accounts of the blockchain
|
|
106
|
+
pub genesis_accounts: Vec<GenesisAccount>,
|
|
107
|
+
/// The hardfork of the blockchain
|
|
108
|
+
pub hardfork: SpecId,
|
|
109
|
+
/// The initial base fee per gas of the blockchain. Required for EIP-1559
|
|
110
|
+
/// transactions and later
|
|
111
|
+
pub initial_base_fee_per_gas: Option<BigInt>,
|
|
112
|
+
/// The initial blob gas of the blockchain. Required for EIP-4844
|
|
113
|
+
pub initial_blob_gas: Option<BlobGas>,
|
|
114
|
+
/// The initial date of the blockchain, in seconds since the Unix epoch
|
|
115
|
+
pub initial_date: Option<BigInt>,
|
|
116
|
+
/// The initial parent beacon block root of the blockchain. Required for
|
|
117
|
+
/// EIP-4788
|
|
118
|
+
pub initial_parent_beacon_block_root: Option<Buffer>,
|
|
119
|
+
/// The minimum gas price of the next block.
|
|
120
|
+
pub min_gas_price: BigInt,
|
|
121
|
+
/// The configuration for the miner
|
|
122
|
+
pub mining: MiningConfig,
|
|
123
|
+
/// The network ID of the blockchain
|
|
124
|
+
pub network_id: BigInt,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
impl TryFrom<ForkConfig> for edr_provider::hardhat_rpc_types::ForkConfig {
|
|
128
|
+
type Error = napi::Error;
|
|
129
|
+
|
|
130
|
+
fn try_from(value: ForkConfig) -> Result<Self, Self::Error> {
|
|
131
|
+
let block_number: Option<u64> = value.block_number.map(TryCast::try_cast).transpose()?;
|
|
132
|
+
let http_headers = value.http_headers.map(|http_headers| {
|
|
133
|
+
http_headers
|
|
134
|
+
.into_iter()
|
|
135
|
+
.map(|HttpHeader { name, value }| (name, value))
|
|
136
|
+
.collect()
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
Ok(Self {
|
|
140
|
+
json_rpc_url: value.json_rpc_url,
|
|
141
|
+
block_number,
|
|
142
|
+
http_headers,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
impl From<MemPoolConfig> for edr_provider::MemPoolConfig {
|
|
148
|
+
fn from(value: MemPoolConfig) -> Self {
|
|
149
|
+
Self {
|
|
150
|
+
order: value.order.into(),
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
impl From<MineOrdering> for edr_evm::MineOrdering {
|
|
156
|
+
fn from(value: MineOrdering) -> Self {
|
|
157
|
+
match value {
|
|
158
|
+
MineOrdering::Fifo => Self::Fifo,
|
|
159
|
+
MineOrdering::Priority => Self::Priority,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
impl TryFrom<MiningConfig> for edr_provider::MiningConfig {
|
|
165
|
+
type Error = napi::Error;
|
|
166
|
+
|
|
167
|
+
fn try_from(value: MiningConfig) -> Result<Self, Self::Error> {
|
|
168
|
+
let mem_pool = value.mem_pool.into();
|
|
169
|
+
|
|
170
|
+
let interval = value
|
|
171
|
+
.interval
|
|
172
|
+
.map(|interval| {
|
|
173
|
+
let interval = match interval {
|
|
174
|
+
Either::A(interval) => {
|
|
175
|
+
edr_provider::IntervalConfig::Fixed(interval.try_cast()?)
|
|
176
|
+
}
|
|
177
|
+
Either::B(IntervalRange { min, max }) => edr_provider::IntervalConfig::Range {
|
|
178
|
+
min: min.try_cast()?,
|
|
179
|
+
max: max.try_cast()?,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
napi::Result::Ok(interval)
|
|
184
|
+
})
|
|
185
|
+
.transpose()?;
|
|
186
|
+
|
|
187
|
+
Ok(Self {
|
|
188
|
+
auto_mine: value.auto_mine,
|
|
189
|
+
interval,
|
|
190
|
+
mem_pool,
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
impl TryFrom<ProviderConfig> for edr_provider::ProviderConfig {
|
|
196
|
+
type Error = napi::Error;
|
|
197
|
+
|
|
198
|
+
fn try_from(value: ProviderConfig) -> Result<Self, Self::Error> {
|
|
199
|
+
let chains = value
|
|
200
|
+
.chains
|
|
201
|
+
.into_iter()
|
|
202
|
+
.map(
|
|
203
|
+
|ChainConfig {
|
|
204
|
+
chain_id,
|
|
205
|
+
hardforks,
|
|
206
|
+
}| {
|
|
207
|
+
let hardforks = hardforks
|
|
208
|
+
.into_iter()
|
|
209
|
+
.map(
|
|
210
|
+
|HardforkActivation {
|
|
211
|
+
block_number,
|
|
212
|
+
spec_id,
|
|
213
|
+
}| {
|
|
214
|
+
let block_number = block_number.try_cast()?;
|
|
215
|
+
let spec_id = spec_id.try_into()?;
|
|
216
|
+
|
|
217
|
+
Ok((block_number, spec_id))
|
|
218
|
+
},
|
|
219
|
+
)
|
|
220
|
+
.collect::<napi::Result<Vec<_>>>()?;
|
|
221
|
+
|
|
222
|
+
let chain_id = chain_id.try_cast()?;
|
|
223
|
+
Ok((chain_id, edr_eth::spec::HardforkActivations::new(hardforks)))
|
|
224
|
+
},
|
|
225
|
+
)
|
|
226
|
+
.collect::<napi::Result<_>>()?;
|
|
227
|
+
|
|
228
|
+
Ok(Self {
|
|
229
|
+
accounts: value
|
|
230
|
+
.genesis_accounts
|
|
231
|
+
.into_iter()
|
|
232
|
+
.map(AccountConfig::try_from)
|
|
233
|
+
.collect::<napi::Result<Vec<_>>>()?,
|
|
234
|
+
allow_blocks_with_same_timestamp: value.allow_blocks_with_same_timestamp,
|
|
235
|
+
allow_unlimited_contract_size: value.allow_unlimited_contract_size,
|
|
236
|
+
bail_on_call_failure: value.bail_on_call_failure,
|
|
237
|
+
bail_on_transaction_failure: value.bail_on_transaction_failure,
|
|
238
|
+
block_gas_limit: value.block_gas_limit.try_cast()?,
|
|
239
|
+
cache_dir: PathBuf::from(
|
|
240
|
+
value
|
|
241
|
+
.cache_dir
|
|
242
|
+
.unwrap_or(String::from(edr_defaults::CACHE_DIR)),
|
|
243
|
+
),
|
|
244
|
+
chain_id: value.chain_id.try_cast()?,
|
|
245
|
+
chains,
|
|
246
|
+
coinbase: value.coinbase.try_cast()?,
|
|
247
|
+
fork: value.fork.map(TryInto::try_into).transpose()?,
|
|
248
|
+
genesis_accounts: HashMap::new(),
|
|
249
|
+
hardfork: value.hardfork.try_into()?,
|
|
250
|
+
initial_base_fee_per_gas: value
|
|
251
|
+
.initial_base_fee_per_gas
|
|
252
|
+
.map(TryCast::try_cast)
|
|
253
|
+
.transpose()?,
|
|
254
|
+
initial_blob_gas: value.initial_blob_gas.map(TryInto::try_into).transpose()?,
|
|
255
|
+
initial_date: value
|
|
256
|
+
.initial_date
|
|
257
|
+
.map(|date| {
|
|
258
|
+
let elapsed_since_epoch = Duration::from_secs(date.try_cast()?);
|
|
259
|
+
napi::Result::Ok(SystemTime::UNIX_EPOCH + elapsed_since_epoch)
|
|
260
|
+
})
|
|
261
|
+
.transpose()?,
|
|
262
|
+
initial_parent_beacon_block_root: value
|
|
263
|
+
.initial_parent_beacon_block_root
|
|
264
|
+
.map(TryCast::try_cast)
|
|
265
|
+
.transpose()?,
|
|
266
|
+
mining: value.mining.try_into()?,
|
|
267
|
+
min_gas_price: value.min_gas_price.try_cast()?,
|
|
268
|
+
network_id: value.network_id.try_cast()?,
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
}
|
package/src/provider.rs
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
mod config;
|
|
2
|
+
|
|
3
|
+
use std::sync::Arc;
|
|
4
|
+
|
|
5
|
+
use edr_eth::remote::jsonrpc;
|
|
6
|
+
use edr_provider::InvalidRequestReason;
|
|
7
|
+
use napi::{tokio::runtime, Env, JsFunction, JsObject, Status};
|
|
8
|
+
use napi_derive::napi;
|
|
9
|
+
|
|
10
|
+
use self::config::ProviderConfig;
|
|
11
|
+
use crate::{
|
|
12
|
+
context::EdrContext,
|
|
13
|
+
logger::{Logger, LoggerConfig, LoggerError},
|
|
14
|
+
subscribe::SubscriberCallback,
|
|
15
|
+
trace::RawTrace,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/// A JSON-RPC provider for Ethereum.
|
|
19
|
+
#[napi]
|
|
20
|
+
pub struct Provider {
|
|
21
|
+
provider: Arc<edr_provider::Provider<LoggerError>>,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#[napi]
|
|
25
|
+
impl Provider {
|
|
26
|
+
#[doc = "Constructs a new provider with the provided configuration."]
|
|
27
|
+
#[napi(ts_return_type = "Promise<Provider>")]
|
|
28
|
+
pub fn with_config(
|
|
29
|
+
env: Env,
|
|
30
|
+
// We take the context as argument to ensure that tracing is initialized properly.
|
|
31
|
+
_context: &EdrContext,
|
|
32
|
+
config: ProviderConfig,
|
|
33
|
+
logger_config: LoggerConfig,
|
|
34
|
+
#[napi(ts_arg_type = "(event: SubscriptionEvent) => void")] subscriber_callback: JsFunction,
|
|
35
|
+
) -> napi::Result<JsObject> {
|
|
36
|
+
let config = edr_provider::ProviderConfig::try_from(config)?;
|
|
37
|
+
let runtime = runtime::Handle::current();
|
|
38
|
+
|
|
39
|
+
let logger = Box::new(Logger::new(&env, logger_config)?);
|
|
40
|
+
let subscriber_callback = SubscriberCallback::new(&env, subscriber_callback)?;
|
|
41
|
+
let subscriber_callback = Box::new(move |event| subscriber_callback.call(event));
|
|
42
|
+
|
|
43
|
+
let (deferred, promise) = env.create_deferred()?;
|
|
44
|
+
runtime.clone().spawn_blocking(move || {
|
|
45
|
+
let result = edr_provider::Provider::new(runtime, logger, subscriber_callback, config)
|
|
46
|
+
.map_or_else(
|
|
47
|
+
|error| Err(napi::Error::new(Status::GenericFailure, error.to_string())),
|
|
48
|
+
|provider| {
|
|
49
|
+
Ok(Provider {
|
|
50
|
+
provider: Arc::new(provider),
|
|
51
|
+
})
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
deferred.resolve(|_env| result);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
Ok(promise)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#[doc = "Handles a JSON-RPC request and returns a JSON-RPC response."]
|
|
62
|
+
#[napi]
|
|
63
|
+
pub async fn handle_request(&self, json_request: String) -> napi::Result<Response> {
|
|
64
|
+
let provider = self.provider.clone();
|
|
65
|
+
let request = match serde_json::from_str(&json_request) {
|
|
66
|
+
Ok(request) => request,
|
|
67
|
+
Err(error) => {
|
|
68
|
+
let message = error.to_string();
|
|
69
|
+
let reason = InvalidRequestReason::new(&json_request, &message);
|
|
70
|
+
|
|
71
|
+
// HACK: We need to log failed deserialization attempts when they concern input
|
|
72
|
+
// validation.
|
|
73
|
+
if let Some((method_name, provider_error)) = reason.provider_error() {
|
|
74
|
+
// Ignore potential failure of logging, as returning the original error is more
|
|
75
|
+
// important
|
|
76
|
+
let _result = runtime::Handle::current()
|
|
77
|
+
.spawn_blocking(move || {
|
|
78
|
+
provider.log_failed_deserialization(&method_name, &provider_error)
|
|
79
|
+
})
|
|
80
|
+
.await
|
|
81
|
+
.map_err(|error| {
|
|
82
|
+
napi::Error::new(Status::GenericFailure, error.to_string())
|
|
83
|
+
})?;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let data = serde_json::from_str(&json_request).ok();
|
|
87
|
+
let response = jsonrpc::ResponseData::<()>::Error {
|
|
88
|
+
error: jsonrpc::Error {
|
|
89
|
+
code: reason.error_code(),
|
|
90
|
+
message: reason.error_message(),
|
|
91
|
+
data,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return serde_json::to_string(&response)
|
|
96
|
+
.map_err(|error| {
|
|
97
|
+
napi::Error::new(
|
|
98
|
+
Status::InvalidArg,
|
|
99
|
+
format!("Invalid JSON `{json_request}` due to: {error}"),
|
|
100
|
+
)
|
|
101
|
+
})
|
|
102
|
+
.map(|json_response| Response {
|
|
103
|
+
solidity_trace: None,
|
|
104
|
+
json: json_response,
|
|
105
|
+
traces: Vec::new(),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
let mut response = runtime::Handle::current()
|
|
111
|
+
.spawn_blocking(move || provider.handle_request(request))
|
|
112
|
+
.await
|
|
113
|
+
.map_err(|e| napi::Error::new(Status::GenericFailure, e.to_string()))?;
|
|
114
|
+
|
|
115
|
+
// We can take the solidity trace as it won't be used for anything else
|
|
116
|
+
let solidity_trace = response.as_mut().err().and_then(|error| {
|
|
117
|
+
if let edr_provider::ProviderError::TransactionFailed(failure) = error {
|
|
118
|
+
if matches!(
|
|
119
|
+
failure.failure.reason,
|
|
120
|
+
edr_provider::TransactionFailureReason::OutOfGas(_)
|
|
121
|
+
) {
|
|
122
|
+
None
|
|
123
|
+
} else {
|
|
124
|
+
Some(Arc::new(std::mem::take(
|
|
125
|
+
&mut failure.failure.solidity_trace,
|
|
126
|
+
)))
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
None
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// We can take the traces as they won't be used for anything else
|
|
134
|
+
let traces = match &mut response {
|
|
135
|
+
Ok(response) => std::mem::take(&mut response.traces),
|
|
136
|
+
Err(edr_provider::ProviderError::TransactionFailed(failure)) => {
|
|
137
|
+
std::mem::take(&mut failure.traces)
|
|
138
|
+
}
|
|
139
|
+
Err(_) => Vec::new(),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
let response = jsonrpc::ResponseData::from(response.map(|response| response.result));
|
|
143
|
+
|
|
144
|
+
serde_json::to_string(&response)
|
|
145
|
+
.map_err(|e| napi::Error::new(Status::GenericFailure, e.to_string()))
|
|
146
|
+
.map(|json_response| Response {
|
|
147
|
+
solidity_trace,
|
|
148
|
+
json: json_response,
|
|
149
|
+
traces: traces.into_iter().map(Arc::new).collect(),
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#[napi]
|
|
155
|
+
pub struct Response {
|
|
156
|
+
json: String,
|
|
157
|
+
/// When a transaction fails to execute, the provider returns a trace of the
|
|
158
|
+
/// transaction.
|
|
159
|
+
solidity_trace: Option<Arc<edr_evm::trace::Trace>>,
|
|
160
|
+
/// This may contain zero or more traces, depending on the (batch) request
|
|
161
|
+
traces: Vec<Arc<edr_evm::trace::Trace>>,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#[napi]
|
|
165
|
+
impl Response {
|
|
166
|
+
#[napi(getter)]
|
|
167
|
+
pub fn json(&self) -> String {
|
|
168
|
+
self.json.clone()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#[napi(getter)]
|
|
172
|
+
pub fn solidity_trace(&self) -> Option<RawTrace> {
|
|
173
|
+
self.solidity_trace
|
|
174
|
+
.as_ref()
|
|
175
|
+
.map(|trace| RawTrace::new(trace.clone()))
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#[napi(getter)]
|
|
179
|
+
pub fn traces(&self) -> Vec<RawTrace> {
|
|
180
|
+
self.traces
|
|
181
|
+
.iter()
|
|
182
|
+
.map(|trace| RawTrace::new(trace.clone()))
|
|
183
|
+
.collect()
|
|
184
|
+
}
|
|
185
|
+
}
|