@mainsail/evm 0.0.1-evm.52 → 0.0.1-evm.53

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.
@@ -0,0 +1,2231 @@
1
+ use std::{sync::Arc, u64};
2
+
3
+ use ctx::{
4
+ BlockContext, CalculateRoundValidatorsContext, EvmOptions, ExecutionContext, GenesisContext,
5
+ JsBlockHeaderData, JsCalculateRoundValidatorsContext, JsCommitData, JsCommitKey, JsEvmOptions,
6
+ JsGenesisContext, JsPrepareNextCommitContext, JsPreverifyTransactionContext,
7
+ JsTransactionContext, JsTransactionData, JsTransactionSimulateContext,
8
+ JsTransactionViewContext, JsUpdateRewardsAndVotesContext, PrepareNextCommitContext,
9
+ PreverifyTxContext, TxContext, TxSimulateContext, TxViewContext, UpdateRewardsAndVotesContext,
10
+ };
11
+ use logger::JsLogger;
12
+ use mainsail_evm_core::{
13
+ account::AccountInfoExtended,
14
+ db::{
15
+ BlockHeaderData, CommitData, CommitKey, GenesisInfo, PendingCommit, PersistentDB,
16
+ PersistentDBOptions, ProofData, TransactionData, TxnDatabaseReader,
17
+ },
18
+ legacy::{LegacyAccountAttributes, LegacyAddress, LegacyColdWallet},
19
+ logger::LogLevel,
20
+ logs_bloom,
21
+ precompiles::MainsailPrecompiles,
22
+ receipt::{TxReceipt, map_execution_result},
23
+ state_changes::AccountUpdate,
24
+ state_commit, state_root,
25
+ };
26
+ use napi::bindgen_prelude::*;
27
+ use napi_derive::napi;
28
+ use result::{
29
+ CommitResult, JsAccountInfoExtended, JsCommitResult, JsGetState, JsLegacyAttributes,
30
+ JsLegacyColdWallet, JsTransactionReceipt, PreverifyTxResult, TxViewResult,
31
+ };
32
+ use revm::{
33
+ Database, DatabaseCommit, ExecuteEvm, MainBuilder, MainContext,
34
+ context::{
35
+ BlockEnv, ContextTr, TxEnv,
36
+ result::{EVMError, ExecutionResult, ResultAndState},
37
+ },
38
+ database::{State, TransitionAccount, WrapDatabaseRef, bal::EvmDatabaseError},
39
+ handler::EvmTr,
40
+ primitives::{Address, B256, Bytes, TxKind, U256, hex::ToHexExt, map::HashMap},
41
+ state::AccountInfo,
42
+ };
43
+
44
+ mod ctx;
45
+ mod logger;
46
+ mod result;
47
+ mod utils;
48
+
49
+ // A complex struct which cannot be exposed to JavaScript directly.
50
+ pub struct EvmInner {
51
+ persistent_db: PersistentDB,
52
+
53
+ // A pending commit consists of one or more transactions.
54
+ //pending_commit: Option<PendingCommit>,
55
+ pending_commits: HashMap<CommitKey, PendingCommit>,
56
+
57
+ snapshot: Option<PendingCommit>,
58
+
59
+ logger: JsLogger,
60
+ }
61
+
62
+ impl EvmInner {
63
+ pub fn new(opts: EvmOptions) -> Self {
64
+ let logger = JsLogger::new(opts.logger_callback).expect("logger ok");
65
+
66
+ let mut db_opts = PersistentDBOptions::new(opts.path).with_logger(logger.inner());
67
+
68
+ if let Some(history_size) = opts.history_size {
69
+ if history_size > 0 {
70
+ db_opts = db_opts.with_history_size(history_size)
71
+ }
72
+ }
73
+
74
+ let persistent_db = PersistentDB::new(db_opts).expect("path ok");
75
+
76
+ EvmInner {
77
+ persistent_db,
78
+ pending_commits: Default::default(),
79
+ snapshot: None,
80
+ logger,
81
+ }
82
+ }
83
+
84
+ pub fn prepare_next_commit(&mut self, ctx: PrepareNextCommitContext) -> Result<()> {
85
+ let genesis_block_number = self.genesis_block_number();
86
+ if let Some(pending) = self.pending_commits.get(&ctx.commit_key) {
87
+ // do not replace any pending commit, while still in bootstrapping phase.
88
+ if pending.key.0 == genesis_block_number && ctx.commit_key == pending.key {
89
+ return Ok(());
90
+ }
91
+
92
+ self.logger.log(
93
+ LogLevel::Debug,
94
+ format!(
95
+ "replacing existing pending commit {:?} for {:?}",
96
+ pending.key, ctx.commit_key
97
+ ),
98
+ );
99
+ }
100
+
101
+ let pending_commit = PendingCommit {
102
+ key: ctx.commit_key,
103
+ ..Default::default()
104
+ };
105
+
106
+ self.pending_commits
107
+ .insert(pending_commit.key, pending_commit);
108
+
109
+ Ok(())
110
+ }
111
+
112
+ pub fn view(&mut self, tx_ctx: TxViewContext) -> Result<TxViewResult> {
113
+ let result = self.transact_evm(tx_ctx.into());
114
+
115
+ Ok(match result {
116
+ Ok((r, _)) => {
117
+ // if !r.is_success() {
118
+ // self.logger
119
+ // .log(LogLevel::Warn, format!("view call failed: {:?}", r));
120
+ // }
121
+
122
+ TxViewResult {
123
+ success: r.is_success(),
124
+ output: r.into_output(),
125
+ }
126
+ }
127
+ Err(err) => {
128
+ self.logger.log(
129
+ LogLevel::Warn,
130
+ format!("view call returned error: {:?}", err),
131
+ );
132
+
133
+ TxViewResult {
134
+ success: false,
135
+ output: None,
136
+ }
137
+ }
138
+ })
139
+ }
140
+
141
+ pub fn code_at(
142
+ &mut self,
143
+ address: Address,
144
+ block_number: Option<u64>,
145
+ ) -> std::result::Result<Bytes, EVMError<String>> {
146
+ let account = match block_number {
147
+ None => self.persistent_db.basic(address),
148
+ Some(block_number) => {
149
+ let result = self
150
+ .persistent_db
151
+ .get_historical_account_info(block_number, address);
152
+
153
+ match result {
154
+ Ok((historical, _)) if historical.is_some() => Ok(historical),
155
+ Ok((_, missing_fallback)) if missing_fallback => {
156
+ self.persistent_db.basic(address)
157
+ } // fallback
158
+ Ok(_) => Ok(None),
159
+ Err(err) => Err(err),
160
+ }
161
+ }
162
+ }
163
+ .map_err(|err| EVMError::Database(format!("account lookup failed: {}", err).into()))?;
164
+
165
+ match account {
166
+ Some(account) => {
167
+ let code = self
168
+ .persistent_db
169
+ .code_by_hash(account.code_hash)
170
+ .map_err(|err| {
171
+ EVMError::Database(format!("code lookup failed: {}", err).into())
172
+ })?;
173
+
174
+ Ok(code.original_bytes())
175
+ }
176
+ None => Ok(Default::default()),
177
+ }
178
+ }
179
+
180
+ pub fn storage_at(
181
+ &mut self,
182
+ address: Address,
183
+ slot: U256,
184
+ ) -> std::result::Result<U256, EVMError<String>> {
185
+ match self.persistent_db.storage(address, slot) {
186
+ Ok(slot) => Ok(slot),
187
+ Err(err) => Err(EVMError::Database(
188
+ format!("storage lookup failed: {}", err).into(),
189
+ )),
190
+ }
191
+ }
192
+
193
+ pub fn initialize_genesis(
194
+ &mut self,
195
+ genesis_ctx: GenesisContext,
196
+ ) -> std::result::Result<(), EVMError<String>> {
197
+ match self.persistent_db.set_genesis_info(GenesisInfo {
198
+ account: genesis_ctx.account,
199
+ deployer_account: genesis_ctx.deployer_account,
200
+ validator_contract: genesis_ctx.validator_contract,
201
+ username_contract: genesis_ctx.username_contract,
202
+ initial_block_number: genesis_ctx.initial_block_number,
203
+ initial_supply: genesis_ctx.initial_supply,
204
+ }) {
205
+ Ok(_) => Ok(()),
206
+ Err(err) => Err(EVMError::Database(
207
+ format!("set_genesis_info failed: {}", err).into(),
208
+ )),
209
+ }
210
+ }
211
+
212
+ pub fn calculate_round_validators(
213
+ &mut self,
214
+ ctx: CalculateRoundValidatorsContext,
215
+ ) -> std::result::Result<(), EVMError<String>> {
216
+ assert!(
217
+ self.pending_commits.contains_key(&ctx.commit_key),
218
+ "calculate_round_validators is missing commit key {:?}",
219
+ ctx.commit_key
220
+ );
221
+
222
+ let genesis_info = self
223
+ .persistent_db
224
+ .genesis_info
225
+ .as_ref()
226
+ .expect("genesis info")
227
+ .clone();
228
+
229
+ let abi = ethers_contract::BaseContract::from(
230
+ ethers_core::abi::parse_abi(&["function calculateRoundValidators(uint8 n) external"])
231
+ .expect("encode abi"),
232
+ );
233
+
234
+ // encode abi into Bytes
235
+ let calldata = abi
236
+ .encode("calculateRoundValidators", ctx.round_validators)
237
+ .expect("encode calculateRoundValidators");
238
+
239
+ let nonce = self
240
+ .get_account_nonce(&ctx.commit_key, genesis_info.deployer_account)
241
+ .map_err(|err| EVMError::Database(format!("get_account_nonce: {err}").into()))?;
242
+
243
+ match self.transact_evm(ExecutionContext {
244
+ block_context: Some(BlockContext {
245
+ commit_key: ctx.commit_key,
246
+ gas_limit: u64::MAX,
247
+ timestamp: ctx.timestamp,
248
+ validator_address: ctx.validator_address,
249
+ }),
250
+ from: genesis_info.deployer_account,
251
+ to: Some(genesis_info.validator_contract),
252
+ data: Bytes::from(calldata.0),
253
+ value: U256::ZERO,
254
+ nonce: Some(nonce),
255
+ gas_limit: Some(u64::MAX),
256
+ gas_price: 0,
257
+ spec_id: ctx.spec_id,
258
+ tx_hash: None,
259
+ stateful: true,
260
+ }) {
261
+ Ok((receipt, _)) => {
262
+ self.logger.log(
263
+ LogLevel::Debug,
264
+ format!(
265
+ "calculate_round_validators {:?} {:?}",
266
+ ctx.commit_key, receipt
267
+ ),
268
+ );
269
+
270
+ assert!(
271
+ receipt.is_success(),
272
+ "calculate_round_validators unsuccessful"
273
+ );
274
+ Ok(())
275
+ }
276
+ Err(err) => Err(EVMError::Database(
277
+ format!("calculate_round_validators failed: {}", err).into(),
278
+ )),
279
+ }
280
+ }
281
+
282
+ pub fn update_rewards_and_votes(
283
+ &mut self,
284
+ ctx: UpdateRewardsAndVotesContext,
285
+ ) -> std::result::Result<(), EVMError<String>> {
286
+ assert!(
287
+ self.pending_commits.contains_key(&ctx.commit_key),
288
+ "update_rewards_and_votes is missing commit key {:?}",
289
+ ctx.commit_key
290
+ );
291
+
292
+ let genesis_info = self
293
+ .persistent_db
294
+ .genesis_info
295
+ .as_ref()
296
+ .expect("genesis info")
297
+ .clone();
298
+
299
+ let nonce = self
300
+ .get_account_nonce(&ctx.commit_key, genesis_info.deployer_account)
301
+ .map_err(|err| EVMError::Database(format!("get_account_nonce: {err}").into()))?;
302
+
303
+ let mut pending_commit = self.pending_commits.get_mut(&ctx.commit_key).expect("ok");
304
+ let mut rewards = HashMap::<Address, u128>::default();
305
+ rewards.insert(ctx.validator_address, ctx.block_reward);
306
+
307
+ match state_commit::apply_rewards(&mut self.persistent_db, &mut pending_commit, rewards) {
308
+ Ok(_) => {
309
+ // call into consensus contract to update votes
310
+ let voters = pending_commit
311
+ .cache
312
+ .accounts
313
+ .keys()
314
+ .map(|k| ethers_core::types::Address::from_slice(k.0.as_slice()))
315
+ .collect::<Vec<ethers_core::types::Address>>();
316
+
317
+ let abi = ethers_contract::BaseContract::from(
318
+ ethers_core::abi::parse_abi(&[
319
+ "function updateVoters(address[] calldata voters) external",
320
+ ])
321
+ .expect("encode abi"),
322
+ );
323
+
324
+ // encode abi into Bytes
325
+ let calldata = abi
326
+ .encode("updateVoters", voters.clone())
327
+ .expect("encode updateVoters");
328
+
329
+ match self.transact_evm(ExecutionContext {
330
+ block_context: Some(BlockContext {
331
+ commit_key: ctx.commit_key,
332
+ gas_limit: u64::MAX,
333
+ timestamp: ctx.timestamp,
334
+ validator_address: ctx.validator_address,
335
+ }),
336
+ from: genesis_info.deployer_account,
337
+ to: Some(genesis_info.validator_contract),
338
+ data: Bytes::from(calldata.0),
339
+ value: U256::ZERO,
340
+ nonce: Some(nonce),
341
+ gas_limit: Some(u64::MAX),
342
+ gas_price: 0,
343
+ spec_id: ctx.spec_id,
344
+ tx_hash: None,
345
+ stateful: true,
346
+ }) {
347
+ Ok((receipt, _)) => {
348
+ self.logger.log(
349
+ LogLevel::Debug,
350
+ format!(
351
+ "vote_update {:?} {:?} {:?}",
352
+ ctx.commit_key,
353
+ receipt,
354
+ voters.len()
355
+ ),
356
+ );
357
+
358
+ assert!(receipt.is_success(), "vote_update unsuccessful");
359
+ Ok(())
360
+ }
361
+ Err(err) => Err(EVMError::Database(
362
+ format!("vote_update failed: {err}").into(),
363
+ )),
364
+ }
365
+ }
366
+ Err(err) => Err(EVMError::Database(
367
+ format!("apply_rewards failed: {err}").into(),
368
+ )),
369
+ }
370
+ }
371
+
372
+ pub fn get_account_info(
373
+ &mut self,
374
+ address: Address,
375
+ block_number: Option<u64>,
376
+ ) -> std::result::Result<AccountInfo, EVMError<String>> {
377
+ let result = match block_number {
378
+ None => self.persistent_db.basic(address),
379
+ Some(block_number) => {
380
+ let result = self
381
+ .persistent_db
382
+ .get_historical_account_info(block_number, address);
383
+
384
+ match result {
385
+ Ok((historical, _)) if historical.is_some() => Ok(historical),
386
+ Ok((_, missing_fallback)) if missing_fallback => {
387
+ self.persistent_db.basic(address)
388
+ } // fallback
389
+ Ok(_) => Ok(None),
390
+ Err(err) => Err(err),
391
+ }
392
+ }
393
+ };
394
+
395
+ match result {
396
+ Ok(account) => Ok(account.unwrap_or_default()),
397
+ Err(err) => Err(EVMError::Database(
398
+ format!("account lookup failed: {}", err).into(),
399
+ )),
400
+ }
401
+ }
402
+
403
+ pub fn get_account_info_extended(
404
+ &mut self,
405
+ address: Address,
406
+ legacy_address: Option<LegacyAddress>,
407
+ ) -> std::result::Result<AccountInfoExtended, EVMError<String>> {
408
+ let mut info = self
409
+ .persistent_db
410
+ .basic(address)
411
+ .map_err(|err| {
412
+ EVMError::Database(format!("account info lookup failed: {}", err).into())
413
+ })?
414
+ .unwrap_or_default();
415
+
416
+ let mut legacy_attributes = Default::default();
417
+ if let Some(legacy_address) = legacy_address {
418
+ match self
419
+ .persistent_db
420
+ .get_legacy_cold_wallet(legacy_address)
421
+ .map_err(|err| {
422
+ EVMError::Database(format!("legacy cold wallet lookup failed: {}", err).into())
423
+ })? {
424
+ Some(legacy_cold_wallet) if legacy_cold_wallet.merge_info.is_none() => {
425
+ // Merge cold wallet with account
426
+ info.balance = info.balance.saturating_add(legacy_cold_wallet.balance);
427
+ legacy_attributes = Some(legacy_cold_wallet.legacy_attributes);
428
+ }
429
+ _ => (),
430
+ }
431
+ }
432
+
433
+ // Use cold wallet legacy attributes if present as they can't be present in both at the same time.
434
+ let legacy_attributes = {
435
+ match legacy_attributes {
436
+ Some(legacy_attributes) => legacy_attributes,
437
+ None => self
438
+ .persistent_db
439
+ .get_legacy_attributes(address)
440
+ .map_err(|err| {
441
+ EVMError::Database(
442
+ format!("legacy attributes lookup failed: {}", err).into(),
443
+ )
444
+ })?
445
+ .unwrap_or_default(),
446
+ }
447
+ };
448
+
449
+ Ok(AccountInfoExtended {
450
+ address,
451
+ info,
452
+ legacy_attributes,
453
+ })
454
+ }
455
+
456
+ pub fn import_account_infos(
457
+ &mut self,
458
+ infos: Vec<AccountInfoExtended>,
459
+ ) -> std::result::Result<(), EVMError<String>> {
460
+ let genesis_block_number = self.genesis_block_number();
461
+
462
+ let (_, pending) = self
463
+ .pending_commits
464
+ .iter_mut()
465
+ .find(|(key, _)| key.0 == genesis_block_number)
466
+ .expect("genesis commit");
467
+
468
+ for info in infos {
469
+ assert!(!pending.cache.accounts.contains_key(&info.address));
470
+
471
+ let (address, info, legacy_attributes) = info.into_parts();
472
+ pending.import_account(address, info, legacy_attributes);
473
+ }
474
+
475
+ Ok(())
476
+ }
477
+
478
+ pub fn import_legacy_cold_wallets(
479
+ &mut self,
480
+ wallets: Vec<LegacyColdWallet>,
481
+ ) -> std::result::Result<(), EVMError<String>> {
482
+ let genesis_block_number = self.genesis_block_number();
483
+
484
+ let (_, pending) = self
485
+ .pending_commits
486
+ .iter_mut()
487
+ .find(|(key, _)| key.0 == genesis_block_number)
488
+ .expect("genesis commit");
489
+
490
+ for wallet in wallets {
491
+ assert!(!pending.legacy_cold_wallets.contains_key(&wallet.address));
492
+ pending.legacy_cold_wallets.insert(wallet.address, wallet);
493
+ }
494
+
495
+ Ok(())
496
+ }
497
+
498
+ pub fn get_accounts(
499
+ &mut self,
500
+ offset: u64,
501
+ limit: u64,
502
+ ) -> std::result::Result<(Option<u64>, Vec<AccountInfoExtended>), EVMError<String>> {
503
+ match self.persistent_db.get_accounts(offset, limit) {
504
+ Ok((next_offset, accounts)) => Ok((next_offset, accounts)),
505
+ Err(err) => Err(EVMError::Database(
506
+ format!("failed reading accounts: {}", err).into(),
507
+ )),
508
+ }
509
+ }
510
+
511
+ pub fn get_legacy_attributes(
512
+ &mut self,
513
+ address: Address,
514
+ legacy_address: Option<LegacyAddress>,
515
+ ) -> std::result::Result<Option<LegacyAccountAttributes>, EVMError<String>> {
516
+ if let Some(legacy_attributes) =
517
+ self.persistent_db
518
+ .get_legacy_attributes(address)
519
+ .map_err(|err| {
520
+ EVMError::Database(format!("failed reading legacy attributes: {}", err).into())
521
+ })?
522
+ {
523
+ return Ok(Some(legacy_attributes));
524
+ }
525
+
526
+ // Try fallback to legacy attributes from cold wallets
527
+ let legacy_attributes = match legacy_address {
528
+ Some(legacy_address) => {
529
+ match self
530
+ .persistent_db
531
+ .get_legacy_cold_wallet(legacy_address)
532
+ .map_err(|err| {
533
+ EVMError::Database(
534
+ format!("legacy cold wallet attributes lookup failed: {}", err).into(),
535
+ )
536
+ })? {
537
+ Some(legacy_cold_wallet) => Some(legacy_cold_wallet.legacy_attributes),
538
+ None => None,
539
+ }
540
+ }
541
+ None => None,
542
+ };
543
+
544
+ Ok(legacy_attributes)
545
+ }
546
+
547
+ pub fn get_legacy_cold_wallets(
548
+ &mut self,
549
+ offset: u64,
550
+ limit: u64,
551
+ ) -> std::result::Result<(Option<u64>, Vec<LegacyColdWallet>), EVMError<String>> {
552
+ match self.persistent_db.get_legacy_cold_wallets(offset, limit) {
553
+ Ok((next_offset, accounts)) => Ok((next_offset, accounts)),
554
+ Err(err) => Err(EVMError::Database(
555
+ format!("failed reading legacy cold wallets: {}", err).into(),
556
+ )),
557
+ }
558
+ }
559
+
560
+ pub fn get_receipts(
561
+ &mut self,
562
+ offset: u64,
563
+ limit: u64,
564
+ ) -> std::result::Result<(Option<u64>, Vec<(u64, Vec<(B256, TxReceipt)>)>), EVMError<String>>
565
+ {
566
+ match self.persistent_db.get_receipts(offset, limit) {
567
+ Ok((next_offset, receipts)) => Ok((next_offset, receipts)),
568
+ Err(err) => Err(EVMError::Database(
569
+ format!("failed reading receipts: {}", err).into(),
570
+ )),
571
+ }
572
+ }
573
+
574
+ pub fn get_receipts_by_block_number(
575
+ &mut self,
576
+ block_number: u64,
577
+ ) -> std::result::Result<HashMap<B256, TxReceipt>, EVMError<String>> {
578
+ match self
579
+ .persistent_db
580
+ .get_receipts_by_block_number(block_number)
581
+ {
582
+ Ok(receipts) => Ok(receipts),
583
+ Err(err) => Err(EVMError::Database(
584
+ format!("failed reading receipts by block number: {}", err).into(),
585
+ )),
586
+ }
587
+ }
588
+
589
+ pub fn get_receipts_by_block_range(
590
+ &mut self,
591
+ from_block_number: u64,
592
+ to_block_number: u64,
593
+ ) -> std::result::Result<Vec<(u64, Vec<(B256, TxReceipt)>)>, EVMError<String>> {
594
+ match self
595
+ .persistent_db
596
+ .get_receipts_by_block_range(from_block_number, to_block_number)
597
+ {
598
+ Ok(receipts) => Ok(receipts),
599
+ Err(err) => Err(EVMError::Database(
600
+ format!("failed reading receipts by block range: {}", err).into(),
601
+ )),
602
+ }
603
+ }
604
+
605
+ pub fn preverify_transaction(
606
+ &mut self,
607
+ ctx: PreverifyTxContext,
608
+ ) -> std::result::Result<PreverifyTxResult, EVMError<String>> {
609
+ let mut pending_commit = PendingCommit::new(Default::default());
610
+
611
+ // Make legacy balance available to account in pending commit during preverification
612
+ if let Some(legacy_address) = ctx.legacy_address {
613
+ match self
614
+ .persistent_db
615
+ .get_legacy_cold_wallet(legacy_address)
616
+ .map_err(|err| {
617
+ EVMError::Database(format!("failed reading legacy cold wallet: {}", err).into())
618
+ })? {
619
+ Some(legacy_cold_wallet) if legacy_cold_wallet.merge_info.is_none() => {
620
+ let mut legacy_balances = HashMap::<Address, u128>::default();
621
+ legacy_balances.insert(
622
+ ctx.from,
623
+ legacy_cold_wallet.balance.try_into().expect("fit u128"),
624
+ );
625
+ state_commit::apply_rewards(
626
+ &mut self.persistent_db,
627
+ &mut pending_commit,
628
+ legacy_balances,
629
+ )
630
+ .map_err(|err| {
631
+ EVMError::Database(
632
+ format!("failed to apply legacy balance: {}", err).into(),
633
+ )
634
+ })?;
635
+ }
636
+ _ => (),
637
+ }
638
+ }
639
+
640
+ let db_reader = TxnDatabaseReader::new(&self.persistent_db).map_err(|err| {
641
+ EVMError::Database(format!("failed to create tx database reader {}", err))
642
+ })?;
643
+
644
+ let state_db = State::builder()
645
+ .with_bundle_update()
646
+ .with_cached_prestate(std::mem::take(&mut pending_commit.cache))
647
+ .with_database(WrapDatabaseRef(db_reader))
648
+ .build();
649
+
650
+ let evm = revm::Context::mainnet()
651
+ .with_db(state_db)
652
+ .modify_cfg_chained(|cfg| {
653
+ cfg.spec = ctx.spec_id;
654
+ })
655
+ .modify_block_chained(|block_env: &mut BlockEnv| {
656
+ block_env.gas_limit = ctx.block_gas_limit;
657
+ })
658
+ .modify_tx_chained(|tx_env: &mut TxEnv| {
659
+ tx_env.gas_limit = ctx.gas_limit;
660
+ tx_env.gas_price = ctx.gas_price;
661
+ tx_env.gas_priority_fee = None;
662
+ tx_env.caller = ctx.from;
663
+ tx_env.value = ctx.value;
664
+ tx_env.nonce = ctx.nonce;
665
+ tx_env.kind = match ctx.to {
666
+ Some(recipient) => TxKind::Call(recipient),
667
+ None => TxKind::Create,
668
+ };
669
+
670
+ tx_env.data = ctx.data;
671
+ })
672
+ .build_mainnet()
673
+ .with_precompiles(MainsailPrecompiles::new(ctx.spec_id));
674
+
675
+ let ctx = evm.ctx_ref();
676
+ let result = revm::handler::validation::validate_initial_tx_gas(
677
+ ctx.tx(),
678
+ (*ctx.cfg().spec()).into(),
679
+ false,
680
+ false,
681
+ 0,
682
+ );
683
+
684
+ Ok(match result {
685
+ Ok(result) => PreverifyTxResult {
686
+ success: true,
687
+ initial_gas_used: result.initial_total_gas(),
688
+ ..Default::default()
689
+ },
690
+ Err(err) => PreverifyTxResult {
691
+ error: Some(format!("preverify failed: {}", err.to_string())),
692
+ ..Default::default()
693
+ },
694
+ })
695
+ }
696
+
697
+ pub fn get_receipt(
698
+ &mut self,
699
+ block_number: u64,
700
+ tx_hash: B256,
701
+ ) -> std::result::Result<Option<TxReceipt>, EVMError<String>> {
702
+ match self.persistent_db.get_receipt(block_number, tx_hash) {
703
+ Ok((_, receipt)) => Ok(receipt),
704
+ Err(err) => Err(EVMError::Database(
705
+ format!("failed reading receipt: {}", err).into(),
706
+ )),
707
+ }
708
+ }
709
+
710
+ pub fn simulate(
711
+ &mut self,
712
+ ctx: TxSimulateContext,
713
+ ) -> std::result::Result<TxReceipt, EVMError<String>> {
714
+ self.execute(ctx.into())
715
+ }
716
+
717
+ pub fn process(
718
+ &mut self,
719
+ tx_ctx: TxContext,
720
+ ) -> std::result::Result<TxReceipt, EVMError<String>> {
721
+ let commit_key = &tx_ctx.block_context.commit_key;
722
+
723
+ let (committed, _) = self
724
+ .persistent_db
725
+ .get_receipt(commit_key.0, tx_ctx.tx_hash)
726
+ .map_err(|err| EVMError::Database(format!("commit receipt lookup: {}", err).into()))?;
727
+ assert!(!committed);
728
+
729
+ if let Some(mut pending) = self.pending_commits.get_mut(commit_key) {
730
+ // Make legacy cold wallet balance available to pending commit if not already present
731
+ if let Some(legacy_address) = tx_ctx.legacy_address {
732
+ if !pending
733
+ .merged_legacy_cold_wallets
734
+ .contains_key(&tx_ctx.from)
735
+ {
736
+ // Make legacy balance available to account in pending commit
737
+ match self
738
+ .persistent_db
739
+ .get_legacy_cold_wallet(legacy_address)
740
+ .map_err(|err| {
741
+ EVMError::Database(
742
+ format!("failed reading legacy cold wallet: {}", err).into(),
743
+ )
744
+ })? {
745
+ Some(legacy_cold_wallet) if legacy_cold_wallet.merge_info.is_none() => {
746
+ let mut legacy_balances = HashMap::<Address, u128>::default();
747
+ legacy_balances.insert(
748
+ tx_ctx.from,
749
+ legacy_cold_wallet.balance.try_into().expect("fit u128"),
750
+ );
751
+
752
+ state_commit::apply_rewards(
753
+ &mut self.persistent_db,
754
+ &mut pending,
755
+ legacy_balances,
756
+ )
757
+ .map_err(|err| {
758
+ EVMError::Database(
759
+ format!("failed to apply legacy balance: {}", err).into(),
760
+ )
761
+ })?;
762
+
763
+ pending
764
+ .merged_legacy_cold_wallets
765
+ .insert(tx_ctx.from, Some((tx_ctx.tx_hash, legacy_address)));
766
+ }
767
+ _ => {
768
+ // Prevent subsequent look ups for same sender in same commit
769
+ pending.merged_legacy_cold_wallets.insert(tx_ctx.from, None);
770
+ }
771
+ }
772
+ }
773
+ }
774
+ }
775
+
776
+ self.execute(tx_ctx.into())
777
+ }
778
+
779
+ pub fn commit(
780
+ &mut self,
781
+ commit_key: CommitKey,
782
+ commit_data: Option<CommitData>,
783
+ ) -> std::result::Result<Vec<AccountUpdate>, EVMError<String>> {
784
+ assert!(self.pending_commits.contains_key(&commit_key));
785
+
786
+ let pending_commit = self.take_pending_commit(commit_key);
787
+
788
+ // self.logger.log(
789
+ // LogLevel::Info,
790
+ // format!(
791
+ // "committing {:?} with {} transitions",
792
+ // commit_key,
793
+ // pending_commit.transitions.transitions.len(),
794
+ // ),
795
+ // );
796
+
797
+ match state_commit::commit_to_db(&mut self.persistent_db, pending_commit, commit_data) {
798
+ Ok(result) => Ok(result),
799
+ Err(err) => Err(EVMError::Database(format!("commit failed: {}", err).into())),
800
+ }
801
+ }
802
+
803
+ pub fn state_root(
804
+ &mut self,
805
+ commit_key: CommitKey,
806
+ current_hash: B256,
807
+ ) -> std::result::Result<String, EVMError<String>> {
808
+ let pending_commit = self
809
+ .pending_commits
810
+ .get_mut(&commit_key)
811
+ .expect("pending commit exists");
812
+
813
+ let genesis_info = self
814
+ .persistent_db
815
+ .genesis_info
816
+ .as_ref()
817
+ .expect("genesis info exists");
818
+
819
+ let result = state_root::calculate(&genesis_info, pending_commit, current_hash);
820
+
821
+ match result {
822
+ Ok(result) => Ok(result.encode_hex()),
823
+ Err(err) => Err(EVMError::Database(
824
+ format!("state_root failed: {}", err).into(),
825
+ )),
826
+ }
827
+ }
828
+
829
+ pub fn logs_bloom(
830
+ &mut self,
831
+ commit_key: CommitKey,
832
+ ) -> std::result::Result<String, EVMError<String>> {
833
+ let pending_commit = self
834
+ .pending_commits
835
+ .get(&commit_key)
836
+ .expect("pending commit exists");
837
+
838
+ let result = logs_bloom::calculate(pending_commit);
839
+
840
+ match result {
841
+ Ok(result) => Ok(result.encode_hex()),
842
+ Err(err) => Err(EVMError::Database(
843
+ format!("logs_bloom failed: {}", err).into(),
844
+ )),
845
+ }
846
+ }
847
+
848
+ pub fn is_empty(&mut self) -> std::result::Result<bool, EVMError<String>> {
849
+ let result = self.persistent_db.is_empty();
850
+
851
+ match result {
852
+ Ok(result) => Ok(result),
853
+ Err(err) => Err(EVMError::Database(
854
+ format!("is_empty failed: {}", err).into(),
855
+ )),
856
+ }
857
+ }
858
+
859
+ pub fn get_state(&mut self) -> std::result::Result<(u64, u64), EVMError<String>> {
860
+ let result = self.persistent_db.get_state();
861
+
862
+ match result {
863
+ Ok(result) => Ok(result),
864
+ Err(err) => Err(EVMError::Database(
865
+ format!("get_state failed: {}", err).into(),
866
+ )),
867
+ }
868
+ }
869
+
870
+ pub fn get_block_header_data(
871
+ &mut self,
872
+ block_number: u64,
873
+ ) -> std::result::Result<Option<BlockHeaderData>, EVMError<String>> {
874
+ let result = self.persistent_db.get_block_header_data(block_number);
875
+
876
+ match result {
877
+ Ok(result) => Ok(result),
878
+ Err(err) => Err(EVMError::Database(
879
+ format!("get_block_header_bytes failed: {}", err).into(),
880
+ )),
881
+ }
882
+ }
883
+
884
+ pub fn get_block_number_by_hash(
885
+ &mut self,
886
+ block_hash: B256,
887
+ ) -> std::result::Result<Option<u64>, EVMError<String>> {
888
+ let result = self.persistent_db.get_block_number_by_hash(block_hash);
889
+
890
+ match result {
891
+ Ok(result) => Ok(result),
892
+ Err(err) => Err(EVMError::Database(
893
+ format!("get_block_number_by_hash failed: {}", err).into(),
894
+ )),
895
+ }
896
+ }
897
+
898
+ pub fn get_commit_data(
899
+ &mut self,
900
+ block_number: u64,
901
+ ) -> std::result::Result<
902
+ Option<(ProofData, BlockHeaderData, Vec<TransactionData>)>,
903
+ EVMError<String>,
904
+ > {
905
+ let Some(proof) = self
906
+ .persistent_db
907
+ .get_proof_data(block_number)
908
+ .map_err(|err| EVMError::Database(format!("get_proof_data failed: {}", err).into()))?
909
+ else {
910
+ return Ok(None);
911
+ };
912
+
913
+ let header = self
914
+ .persistent_db
915
+ .get_block_header_data(block_number)
916
+ .map_err(|err| {
917
+ EVMError::Database(format!("get_block_header_data failed: {}", err).into())
918
+ })?
919
+ .ok_or_else(|| EVMError::Custom("header not found".into()))?;
920
+
921
+ let mut txs = Vec::with_capacity(header.transactions_count as usize);
922
+
923
+ for i in 0..header.transactions_count {
924
+ let key = format!("{block_number}-{i}");
925
+ let tx_data = self.get_transaction_data(key)?.ok_or_else(|| {
926
+ EVMError::Custom(format!("tx {block_number}-{i} not found").into())
927
+ })?;
928
+
929
+ txs.push(tx_data);
930
+ }
931
+
932
+ Ok(Some((proof, header, txs)))
933
+ }
934
+
935
+ pub fn get_commits_by_block_range(
936
+ &mut self,
937
+ from_block_number: u64,
938
+ to_block_number: u64,
939
+ max_bytes: u64,
940
+ ) -> std::result::Result<
941
+ Vec<(ProofData, BlockHeaderData, Vec<TransactionData>)>,
942
+ EVMError<String>,
943
+ > {
944
+ match self.persistent_db.get_commits_by_block_range(
945
+ from_block_number,
946
+ to_block_number,
947
+ max_bytes,
948
+ ) {
949
+ Ok(commits) => Ok(commits),
950
+ Err(err) => Err(EVMError::Database(
951
+ format!("failed reading commits by block range: {}", err).into(),
952
+ )),
953
+ }
954
+ }
955
+
956
+ pub fn get_transaction_data(
957
+ &mut self,
958
+ key: String,
959
+ ) -> std::result::Result<Option<TransactionData>, EVMError<String>> {
960
+ let result = self.persistent_db.get_transaction_data(key);
961
+
962
+ match result {
963
+ Ok(result) => Ok(result),
964
+ Err(err) => Err(EVMError::Database(
965
+ format!("get_transaction_data failed: {}", err).into(),
966
+ )),
967
+ }
968
+ }
969
+
970
+ pub fn get_transaction_key_by_hash(
971
+ &mut self,
972
+ tx_hash: B256,
973
+ ) -> std::result::Result<Option<String>, EVMError<String>> {
974
+ let result = self.persistent_db.get_transaction_key_by_hash(tx_hash);
975
+
976
+ match result {
977
+ Ok(result) => Ok(result),
978
+ Err(err) => Err(EVMError::Database(
979
+ format!("get_transaction_key_by_hash failed: {}", err).into(),
980
+ )),
981
+ }
982
+ }
983
+
984
+ pub fn snapshot(&mut self, commit_key: CommitKey) -> std::result::Result<(), EVMError<String>> {
985
+ self.logger.inner().log(
986
+ LogLevel::Debug,
987
+ format!("taking snapshot of commit {:?}", commit_key),
988
+ );
989
+
990
+ let _ = std::mem::replace(
991
+ &mut self.snapshot,
992
+ self.pending_commits.get(&commit_key).cloned(),
993
+ );
994
+
995
+ Ok(())
996
+ }
997
+
998
+ pub fn rollback(&mut self, commit_key: CommitKey) -> std::result::Result<(), EVMError<String>> {
999
+ self.logger.inner().log(
1000
+ LogLevel::Debug,
1001
+ format!("rolling back to commit {:?}", commit_key),
1002
+ );
1003
+
1004
+ match self.snapshot.take() {
1005
+ Some(commit) if commit.key == commit_key => {
1006
+ assert!(self.pending_commits.contains_key(&commit_key));
1007
+ self.pending_commits.insert(commit_key, commit);
1008
+
1009
+ Ok(())
1010
+ }
1011
+ Some(commit) => Err(EVMError::Custom(
1012
+ format!(
1013
+ "rollback commit key mismatch ({:?}, {:?})",
1014
+ commit.key, commit_key
1015
+ )
1016
+ .into(),
1017
+ )),
1018
+ None => Err(EVMError::Custom(
1019
+ format!("rollback to non-existent commit ({:?})", commit_key).into(),
1020
+ )),
1021
+ }
1022
+ }
1023
+
1024
+ pub fn dispose(&mut self) -> std::result::Result<(), EVMError<String>> {
1025
+ // replace to drop any reference to logging hook
1026
+ self.logger = JsLogger::new(None)
1027
+ .map_err(|err| EVMError::Custom(format!("close logger err={err}")))?;
1028
+
1029
+ Ok(())
1030
+ }
1031
+
1032
+ fn execute(
1033
+ &mut self,
1034
+ ctx: ExecutionContext,
1035
+ ) -> std::result::Result<TxReceipt, EVMError<String>> {
1036
+ match self.transact_evm(ctx.into()) {
1037
+ Ok((result, cumulative_gas_used)) => {
1038
+ let receipt = map_execution_result(result, cumulative_gas_used);
1039
+ Ok(receipt)
1040
+ }
1041
+ Err(err) => {
1042
+ match err {
1043
+ EVMError::Transaction(err) => {
1044
+ return Err(EVMError::Transaction(err));
1045
+ }
1046
+ // EVMError::Header(_) => todo!(),
1047
+ // EVMError::Database(_) => todo!(),
1048
+ // EVMError::Custom(_) => todo!(),
1049
+ _ => {
1050
+ panic!("fatal evm err {:?}", err);
1051
+ }
1052
+ }
1053
+ }
1054
+ }
1055
+ }
1056
+
1057
+ fn transact_evm(
1058
+ &mut self,
1059
+ ctx: ExecutionContext,
1060
+ ) -> std::result::Result<
1061
+ (ExecutionResult, u64),
1062
+ EVMError<EvmDatabaseError<mainsail_evm_core::db::Error>>,
1063
+ > {
1064
+ let mut state_builder = State::builder().with_bundle_update();
1065
+
1066
+ if let Some(commit_key) = ctx.block_context.as_ref().map(|b| &b.commit_key)
1067
+ && ctx.stateful
1068
+ {
1069
+ if let Some(pending_commit) = self.pending_commits.get_mut(commit_key) {
1070
+ state_builder =
1071
+ state_builder.with_cached_prestate(std::mem::take(&mut pending_commit.cache));
1072
+ }
1073
+ }
1074
+
1075
+ let db_reader = TxnDatabaseReader::new(&self.persistent_db)
1076
+ .map_err(|err| EVMError::Database(EvmDatabaseError::Database(err)))?;
1077
+
1078
+ let state_db = state_builder
1079
+ .with_database(WrapDatabaseRef(db_reader))
1080
+ .build();
1081
+
1082
+ let mut evm = revm::Context::mainnet()
1083
+ .with_db(state_db)
1084
+ .modify_cfg_chained(|cfg| {
1085
+ cfg.spec = ctx.spec_id;
1086
+ cfg.disable_nonce_check = ctx.nonce.is_none();
1087
+ })
1088
+ .modify_block_chained(|block_env: &mut BlockEnv| {
1089
+ let Some(block_ctx) = ctx.block_context.as_ref() else {
1090
+ return;
1091
+ };
1092
+
1093
+ block_env.number = U256::from(block_ctx.commit_key.0);
1094
+ block_env.beneficiary = block_ctx.validator_address;
1095
+ block_env.timestamp = U256::from(block_ctx.timestamp);
1096
+ block_env.gas_limit = block_ctx.gas_limit;
1097
+ block_env.difficulty = U256::ZERO;
1098
+ })
1099
+ .modify_tx_chained(|tx_env: &mut TxEnv| {
1100
+ tx_env.gas_limit = ctx.gas_limit.unwrap_or_else(|| u64::MAX);
1101
+ tx_env.gas_price = ctx.gas_price;
1102
+ tx_env.gas_priority_fee = None;
1103
+ tx_env.caller = ctx.from;
1104
+ tx_env.value = ctx.value;
1105
+ tx_env.nonce = ctx.nonce.unwrap_or_default();
1106
+ tx_env.kind = match ctx.to {
1107
+ Some(recipient) => TxKind::Call(recipient),
1108
+ None => TxKind::Create,
1109
+ };
1110
+
1111
+ tx_env.data = ctx.data;
1112
+ })
1113
+ .build_mainnet()
1114
+ .with_precompiles(MainsailPrecompiles::new(ctx.spec_id));
1115
+
1116
+ let result = evm.replay();
1117
+
1118
+ match result {
1119
+ Ok(result) => {
1120
+ let ResultAndState { state, result } = result;
1121
+
1122
+ let mut cumulative_gas_used = 0;
1123
+
1124
+ // Update state if transaction is part of a commit
1125
+ if let Some(commit_key) = ctx.block_context.as_ref().map(|b| &b.commit_key)
1126
+ && ctx.stateful
1127
+ {
1128
+ let state_db = evm.db_mut();
1129
+ state_db.commit(state);
1130
+
1131
+ if let Some(pending_commit) = self.pending_commits.get_mut(commit_key) {
1132
+ pending_commit.cache = std::mem::take(&mut state_db.cache);
1133
+
1134
+ if let Some(tx_hash) = ctx.tx_hash {
1135
+ pending_commit.cumulative_gas_used += result.tx_gas_used();
1136
+ pending_commit.results.insert(
1137
+ tx_hash,
1138
+ (result.clone(), pending_commit.cumulative_gas_used),
1139
+ );
1140
+ cumulative_gas_used = pending_commit.cumulative_gas_used;
1141
+ }
1142
+
1143
+ pending_commit.transitions.add_transitions(
1144
+ state_db
1145
+ .transition_state
1146
+ .take()
1147
+ .unwrap_or_default()
1148
+ .transitions
1149
+ .into_iter()
1150
+ .collect::<Vec<(Address, TransitionAccount)>>(),
1151
+ );
1152
+ }
1153
+ }
1154
+
1155
+ Ok((result, cumulative_gas_used))
1156
+ }
1157
+ Err(err) => Err(err),
1158
+ }
1159
+ }
1160
+
1161
+ fn get_account_nonce(
1162
+ &mut self,
1163
+ commit_key: &CommitKey,
1164
+ account: Address,
1165
+ ) -> std::result::Result<u64, mainsail_evm_core::db::Error> {
1166
+ if let Some(pending) = self.pending_commits.get(commit_key) {
1167
+ if pending.cache.accounts.contains_key(&account) {
1168
+ if let Some(cache) = pending.cache.accounts.get(&account) {
1169
+ if let Some(account) = &cache.account {
1170
+ return Ok(account.info.nonce);
1171
+ }
1172
+ }
1173
+ }
1174
+ }
1175
+
1176
+ if let Some(account_info) = self.persistent_db.basic(account)? {
1177
+ return Ok(account_info.nonce);
1178
+ }
1179
+
1180
+ return Ok(Default::default());
1181
+ }
1182
+
1183
+ fn take_pending_commit(&mut self, commit_key: CommitKey) -> PendingCommit {
1184
+ let pending_commit = self
1185
+ .pending_commits
1186
+ .remove(&commit_key)
1187
+ .expect("pending commit exists");
1188
+
1189
+ if self.pending_commits.len() > 0 {
1190
+ self.logger.log(
1191
+ LogLevel::Debug,
1192
+ format!(
1193
+ "taking {commit_key:?} and dropping {:?}",
1194
+ self.pending_commits.keys().collect::<Vec<_>>()
1195
+ ),
1196
+ );
1197
+ }
1198
+
1199
+ self.pending_commits.clear();
1200
+ self.snapshot.take();
1201
+
1202
+ pending_commit
1203
+ }
1204
+
1205
+ #[inline]
1206
+ fn genesis_block_number(&mut self) -> u64 {
1207
+ self.persistent_db
1208
+ .genesis_info
1209
+ .as_ref()
1210
+ .cloned()
1211
+ .unwrap_or_default()
1212
+ .initial_block_number
1213
+ }
1214
+ }
1215
+
1216
+ // The EVM wrapper is exposed to JavaScript.
1217
+
1218
+ #[napi(js_name = "Evm")]
1219
+ pub struct JsEvmWrapper {
1220
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1221
+ }
1222
+
1223
+ #[napi]
1224
+ impl JsEvmWrapper {
1225
+ #[napi(constructor)]
1226
+ pub fn new(opts: JsEvmOptions) -> Result<Self> {
1227
+ let opts = EvmOptions::try_from(opts)?;
1228
+ Ok(JsEvmWrapper {
1229
+ evm: Arc::new(tokio::sync::Mutex::new(EvmInner::new(opts))),
1230
+ })
1231
+ }
1232
+
1233
+ #[napi]
1234
+ pub fn preverify_transaction<'env>(
1235
+ &mut self,
1236
+ env: &'env Env,
1237
+ tx_ctx: JsPreverifyTransactionContext,
1238
+ ) -> Result<PromiseRaw<'env, result::JsPreverifyTransactionResult>> {
1239
+ let tx_ctx = PreverifyTxContext::try_from(tx_ctx)?;
1240
+ env.spawn_future_with_callback(
1241
+ Self::preverify_transaction_async(self.evm.clone(), tx_ctx),
1242
+ |_, result| Ok(result::JsPreverifyTransactionResult::new(result)),
1243
+ )
1244
+ }
1245
+
1246
+ #[napi]
1247
+ pub fn view<'env>(
1248
+ &mut self,
1249
+ env: &'env Env,
1250
+ view_ctx: JsTransactionViewContext,
1251
+ ) -> Result<PromiseRaw<'env, result::JsViewResult>> {
1252
+ let view_ctx = TxViewContext::try_from(view_ctx)?;
1253
+ env.spawn_future_with_callback(Self::view_async(self.evm.clone(), view_ctx), |_, result| {
1254
+ Ok(result::JsViewResult::new(result)?)
1255
+ })
1256
+ }
1257
+
1258
+ #[napi]
1259
+ pub fn process<'env>(
1260
+ &mut self,
1261
+ env: &'env Env,
1262
+ tx_ctx: JsTransactionContext,
1263
+ ) -> Result<PromiseRaw<'env, result::JsProcessResult>> {
1264
+ let tx_ctx = TxContext::try_from(tx_ctx)?;
1265
+ env.spawn_future_with_callback(
1266
+ Self::process_async(self.evm.clone(), tx_ctx),
1267
+ |_, result| Ok(result::JsProcessResult::new(result)),
1268
+ )
1269
+ }
1270
+
1271
+ #[napi]
1272
+ pub fn simulate<'env>(
1273
+ &mut self,
1274
+ env: &'env Env,
1275
+ tx_ctx: JsTransactionSimulateContext,
1276
+ ) -> Result<PromiseRaw<'env, result::JsSimulateResult>> {
1277
+ let tx_ctx = TxSimulateContext::try_from(tx_ctx)?;
1278
+ env.spawn_future_with_callback(
1279
+ Self::simulate_async(self.evm.clone(), tx_ctx),
1280
+ |_, result| Ok(result::JsSimulateResult::new(result)),
1281
+ )
1282
+ }
1283
+
1284
+ #[napi]
1285
+ pub fn initialize_genesis<'env>(
1286
+ &mut self,
1287
+ env: &'env Env,
1288
+ genesis_ctx: JsGenesisContext,
1289
+ ) -> Result<PromiseRaw<'env, ()>> {
1290
+ let genesis_ctx = GenesisContext::try_from(genesis_ctx)?;
1291
+ env.spawn_future_with_callback(
1292
+ Self::initialize_genesis_async(self.evm.clone(), genesis_ctx),
1293
+ |_, _| Ok(()),
1294
+ )
1295
+ }
1296
+
1297
+ #[napi]
1298
+ pub fn prepare_next_commit<'env>(
1299
+ &mut self,
1300
+ env: &'env Env,
1301
+ ctx: JsPrepareNextCommitContext,
1302
+ ) -> Result<PromiseRaw<'env, ()>> {
1303
+ let ctx = PrepareNextCommitContext::try_from(ctx)?;
1304
+ env.spawn_future_with_callback(
1305
+ Self::prepare_next_commit_async(self.evm.clone(), ctx),
1306
+ |_, _| Ok(()),
1307
+ )
1308
+ }
1309
+
1310
+ #[napi]
1311
+ pub fn calculate_round_validators<'env>(
1312
+ &mut self,
1313
+ env: &'env Env,
1314
+ ctx: JsCalculateRoundValidatorsContext,
1315
+ ) -> Result<PromiseRaw<'env, ()>> {
1316
+ let ctx = CalculateRoundValidatorsContext::try_from(ctx)?;
1317
+ env.spawn_future_with_callback(
1318
+ Self::calculate_round_validators_async(self.evm.clone(), ctx),
1319
+ |_, _| Ok(()),
1320
+ )
1321
+ }
1322
+
1323
+ #[napi]
1324
+ pub fn update_rewards_and_votes<'env>(
1325
+ &mut self,
1326
+ env: &'env Env,
1327
+ ctx: JsUpdateRewardsAndVotesContext,
1328
+ ) -> Result<PromiseRaw<'env, ()>> {
1329
+ let ctx = UpdateRewardsAndVotesContext::try_from(ctx)?;
1330
+ env.spawn_future_with_callback(
1331
+ Self::update_rewards_and_votes_async(self.evm.clone(), ctx),
1332
+ |_, _| Ok(()),
1333
+ )
1334
+ }
1335
+
1336
+ #[napi]
1337
+ pub fn get_account_info<'env>(
1338
+ &mut self,
1339
+ env: &'env Env,
1340
+ address: String,
1341
+ block_number: Option<BigInt>,
1342
+ ) -> Result<PromiseRaw<'env, result::JsAccountInfo>> {
1343
+ let address = utils::create_address_from_string(&address)?;
1344
+
1345
+ let block_number = match block_number {
1346
+ Some(block_number) => Some(block_number.get_u64().1),
1347
+ None => None,
1348
+ };
1349
+
1350
+ env.spawn_future_with_callback(
1351
+ Self::get_account_info_async(self.evm.clone(), address, block_number),
1352
+ |_, result| Ok(result::JsAccountInfo::new(result)?),
1353
+ )
1354
+ }
1355
+
1356
+ #[napi]
1357
+ pub fn get_account_info_extended<'env>(
1358
+ &mut self,
1359
+ env: &'env Env,
1360
+ address: String,
1361
+ legacy_address: Option<String>,
1362
+ ) -> Result<PromiseRaw<'env, result::JsAccountInfoExtended>> {
1363
+ let address = utils::create_address_from_string(&address)?;
1364
+ let legacy_address = if let Some(legacy_address) = legacy_address {
1365
+ Some(utils::create_legacy_address_from_string(&legacy_address)?)
1366
+ } else {
1367
+ None
1368
+ };
1369
+
1370
+ env.spawn_future_with_callback(
1371
+ Self::get_account_info_extended_async(self.evm.clone(), address, legacy_address),
1372
+ |_, result| Ok(result::JsAccountInfoExtended::new(result)),
1373
+ )
1374
+ }
1375
+
1376
+ #[napi]
1377
+ pub fn import_account_infos<'env>(
1378
+ &mut self,
1379
+ env: &'env Env,
1380
+ infos: Vec<JsAccountInfoExtended>,
1381
+ ) -> Result<PromiseRaw<'env, ()>> {
1382
+ let mut accounts: Vec<AccountInfoExtended> = Vec::with_capacity(infos.len());
1383
+ for info in infos {
1384
+ accounts.push(info.try_into()?);
1385
+ }
1386
+
1387
+ env.spawn_future_with_callback(
1388
+ Self::import_account_infos_async(self.evm.clone(), accounts),
1389
+ |_, _| Ok(()),
1390
+ )
1391
+ }
1392
+
1393
+ #[napi]
1394
+ pub fn import_legacy_cold_wallets<'env>(
1395
+ &mut self,
1396
+ env: &'env Env,
1397
+ infos: Vec<JsLegacyColdWallet>,
1398
+ ) -> Result<PromiseRaw<'env, ()>> {
1399
+ let mut cold_wallets: Vec<LegacyColdWallet> = Vec::with_capacity(infos.len());
1400
+ for info in infos {
1401
+ cold_wallets.push(info.try_into()?);
1402
+ }
1403
+
1404
+ env.spawn_future_with_callback(
1405
+ Self::import_legacy_cold_wallets_async(self.evm.clone(), cold_wallets),
1406
+ |_, _| Ok(()),
1407
+ )
1408
+ }
1409
+
1410
+ #[napi]
1411
+ pub fn get_accounts<'env>(
1412
+ &mut self,
1413
+ env: &'env Env,
1414
+ offset: BigInt,
1415
+ limit: BigInt,
1416
+ ) -> Result<PromiseRaw<'env, result::JsGetAccounts>> {
1417
+ let offset = offset.get_u64().1;
1418
+ let limit = limit.get_u64().1;
1419
+
1420
+ env.spawn_future_with_callback(
1421
+ Self::get_accounts_async(self.evm.clone(), offset, limit),
1422
+ |_, result| Ok(result::JsGetAccounts::new(result.0, result.1)),
1423
+ )
1424
+ }
1425
+
1426
+ #[napi]
1427
+ pub fn get_legacy_attributes<'env>(
1428
+ &mut self,
1429
+ env: &'env Env,
1430
+ address: String,
1431
+ legacy_address: Option<String>,
1432
+ ) -> Result<PromiseRaw<'env, Option<JsLegacyAttributes>>> {
1433
+ let address = utils::create_address_from_string(&address)?;
1434
+ let legacy_address = if let Some(legacy_address) = legacy_address {
1435
+ Some(utils::create_legacy_address_from_string(&legacy_address)?)
1436
+ } else {
1437
+ None
1438
+ };
1439
+
1440
+ env.spawn_future_with_callback(
1441
+ Self::get_legacy_attributes_async(self.evm.clone(), address, legacy_address),
1442
+ |_, result| {
1443
+ Ok(match result {
1444
+ Some(result) => Some(JsLegacyAttributes::new(result)),
1445
+ None => None,
1446
+ })
1447
+ },
1448
+ )
1449
+ }
1450
+
1451
+ #[napi]
1452
+ pub fn get_legacy_cold_wallets<'env>(
1453
+ &mut self,
1454
+ env: &'env Env,
1455
+ offset: BigInt,
1456
+ limit: BigInt,
1457
+ ) -> Result<PromiseRaw<'env, result::JsGetLegacyColdWallets>> {
1458
+ let offset = offset.get_u64().1;
1459
+ let limit = limit.get_u64().1;
1460
+
1461
+ env.spawn_future_with_callback(
1462
+ Self::get_legacy_cold_wallets_async(self.evm.clone(), offset, limit),
1463
+ |_, result| Ok(result::JsGetLegacyColdWallets::new(result.0, result.1)),
1464
+ )
1465
+ }
1466
+
1467
+ #[napi]
1468
+ pub fn get_receipts<'env>(
1469
+ &mut self,
1470
+ node_env: &'env Env,
1471
+ offset: BigInt,
1472
+ limit: BigInt,
1473
+ ) -> Result<PromiseRaw<'env, result::JsGetReceipts>> {
1474
+ let offset = offset.get_u64().1;
1475
+ let limit = limit.get_u64().1;
1476
+
1477
+ node_env.spawn_future_with_callback(
1478
+ Self::get_receipts_async(self.evm.clone(), offset, limit),
1479
+ |_, result| Ok(result::JsGetReceipts::new(result.0, result.1)?),
1480
+ )
1481
+ }
1482
+
1483
+ #[napi]
1484
+ pub fn get_receipts_by_block_number<'env>(
1485
+ &mut self,
1486
+ node_env: &'env Env,
1487
+ block_number: BigInt,
1488
+ ) -> Result<PromiseRaw<'env, HashMap<String, result::JsTransactionReceipt>>> {
1489
+ let block_number = block_number.get_u64().1;
1490
+
1491
+ node_env.spawn_future_with_callback(
1492
+ Self::get_receipts_by_block_number_async(self.evm.clone(), block_number),
1493
+ |_, result| {
1494
+ Ok(result
1495
+ .into_iter()
1496
+ .map(|(k, v)| (format!("{:x}", k), JsTransactionReceipt::new(v)))
1497
+ .collect())
1498
+ },
1499
+ )
1500
+ }
1501
+
1502
+ #[napi]
1503
+ pub fn get_receipts_by_block_range<'env>(
1504
+ &mut self,
1505
+ node_env: &'env Env,
1506
+ from_block_number: BigInt,
1507
+ to_block_number: BigInt,
1508
+ ) -> Result<PromiseRaw<'env, result::JsGetReceipts>> {
1509
+ let from_block_number = from_block_number.get_u64().1;
1510
+ let to_block_number = to_block_number.get_u64().1;
1511
+
1512
+ node_env.spawn_future_with_callback(
1513
+ Self::get_receipts_by_block_range_async(
1514
+ self.evm.clone(),
1515
+ from_block_number,
1516
+ to_block_number,
1517
+ ),
1518
+ |_, result| Ok(result::JsGetReceipts::new(None, result)?),
1519
+ )
1520
+ }
1521
+
1522
+ #[napi]
1523
+ pub fn get_receipt<'env>(
1524
+ &mut self,
1525
+ env: &'env Env,
1526
+ block_number: BigInt,
1527
+ tx_hash: String,
1528
+ ) -> Result<PromiseRaw<'env, result::JsGetReceipt>> {
1529
+ let block_number = block_number.get_u64().1;
1530
+ let tx_hash = utils::convert_string_to_b256(tx_hash)?;
1531
+
1532
+ env.spawn_future_with_callback(
1533
+ Self::get_receipt_async(self.evm.clone(), block_number, tx_hash),
1534
+ move |_, result| Ok(result::JsGetReceipt::new(result, block_number, tx_hash)),
1535
+ )
1536
+ }
1537
+
1538
+ #[napi]
1539
+ pub fn code_at<'env>(
1540
+ &mut self,
1541
+ env: &'env Env,
1542
+ address: String,
1543
+ block_number: Option<BigInt>,
1544
+ ) -> Result<PromiseRaw<'env, String>> {
1545
+ let address = utils::create_address_from_string(&address)?;
1546
+ let block_number = match block_number {
1547
+ Some(block_number) => Some(block_number.get_u64().1),
1548
+ None => None,
1549
+ };
1550
+
1551
+ env.spawn_future_with_callback(
1552
+ Self::code_at_async(self.evm.clone(), address, block_number),
1553
+ |_, result| Ok(result),
1554
+ )
1555
+ }
1556
+
1557
+ #[napi]
1558
+ pub fn storage_at<'env>(
1559
+ &mut self,
1560
+ env: &'env Env,
1561
+ address: String,
1562
+ slot: BigInt,
1563
+ ) -> Result<PromiseRaw<'env, String>> {
1564
+ let address = utils::create_address_from_string(&address)?;
1565
+ let slot = utils::convert_bigint_to_u256(slot)?;
1566
+ env.spawn_future_with_callback(
1567
+ Self::storage_at_async(self.evm.clone(), address, slot),
1568
+ |_, result| Ok(result),
1569
+ )
1570
+ }
1571
+
1572
+ #[napi]
1573
+ pub fn commit<'env>(
1574
+ &mut self,
1575
+ env: &'env Env,
1576
+ commit_key: JsCommitKey,
1577
+ commit_data: Option<JsCommitData>,
1578
+ ) -> Result<PromiseRaw<'env, JsCommitResult>> {
1579
+ let commit_key = CommitKey::try_from(commit_key)?;
1580
+ let commit_data = if let Some(commit_data) = commit_data {
1581
+ Some(CommitData::try_from(commit_data)?)
1582
+ } else {
1583
+ None
1584
+ };
1585
+
1586
+ env.spawn_future_with_callback(
1587
+ Self::commit_async(self.evm.clone(), commit_key, commit_data),
1588
+ |_, result| Ok(result::JsCommitResult::new(result)?),
1589
+ )
1590
+ }
1591
+
1592
+ #[napi]
1593
+ pub fn state_root<'env>(
1594
+ &mut self,
1595
+ env: &'env Env,
1596
+ commit_key: JsCommitKey,
1597
+ current_hash: String,
1598
+ ) -> Result<PromiseRaw<'env, String>> {
1599
+ let commit_key = CommitKey::try_from(commit_key)?;
1600
+ let current_hash = utils::convert_string_to_b256(current_hash)?;
1601
+ env.spawn_future_with_callback(
1602
+ Self::state_root_async(self.evm.clone(), commit_key, current_hash),
1603
+ |_, result| Ok(result),
1604
+ )
1605
+ }
1606
+
1607
+ #[napi]
1608
+ pub fn logs_bloom<'env>(
1609
+ &mut self,
1610
+ env: &'env Env,
1611
+ commit_key: JsCommitKey,
1612
+ ) -> Result<PromiseRaw<'env, String>> {
1613
+ let commit_key = CommitKey::try_from(commit_key)?;
1614
+ env.spawn_future_with_callback(
1615
+ Self::logs_bloom_async(self.evm.clone(), commit_key),
1616
+ |_, result| Ok(result),
1617
+ )
1618
+ }
1619
+
1620
+ #[napi]
1621
+ pub fn is_empty<'env>(&mut self, env: &'env Env) -> Result<PromiseRaw<'env, bool>> {
1622
+ env.spawn_future_with_callback(Self::is_empty_async(self.evm.clone()), |_, result| {
1623
+ Ok(result)
1624
+ })
1625
+ }
1626
+
1627
+ #[napi]
1628
+ pub fn get_state<'env>(&mut self, env: &'env Env) -> Result<PromiseRaw<'env, JsGetState>> {
1629
+ env.spawn_future_with_callback(Self::get_state_async(self.evm.clone()), |_, result| {
1630
+ Ok(result::JsGetState::new(result))
1631
+ })
1632
+ }
1633
+
1634
+ #[napi]
1635
+ pub fn get_block_header_data<'env>(
1636
+ &mut self,
1637
+ env: &'env Env,
1638
+ block_number: BigInt,
1639
+ ) -> Result<PromiseRaw<'env, Option<JsBlockHeaderData>>> {
1640
+ let block_number = block_number.get_u64().1;
1641
+ env.spawn_future_with_callback(
1642
+ Self::get_block_header_data_async(self.evm.clone(), block_number),
1643
+ |_, result| {
1644
+ Ok(match result {
1645
+ Some(data) => Some(JsBlockHeaderData::new(data)),
1646
+ None => None,
1647
+ })
1648
+ },
1649
+ )
1650
+ }
1651
+
1652
+ #[napi]
1653
+ pub fn get_block_number_by_hash<'env>(
1654
+ &mut self,
1655
+ env: &'env Env,
1656
+ block_hash: String,
1657
+ ) -> Result<PromiseRaw<'env, Option<BigInt>>> {
1658
+ let block_hash = utils::convert_string_to_b256(block_hash)?;
1659
+
1660
+ env.spawn_future_with_callback(
1661
+ Self::get_block_number_by_hash_async(self.evm.clone(), block_hash),
1662
+ |_, result| {
1663
+ Ok(match result {
1664
+ Some(result) => Some(BigInt::from(result)),
1665
+ None => None,
1666
+ })
1667
+ },
1668
+ )
1669
+ }
1670
+
1671
+ #[napi]
1672
+ pub fn get_commit_data<'env>(
1673
+ &mut self,
1674
+ env: &'env Env,
1675
+ block_number: BigInt,
1676
+ ) -> Result<PromiseRaw<'env, Option<JsCommitData>>> {
1677
+ let block_number = block_number.get_u64().1;
1678
+ env.spawn_future_with_callback(
1679
+ Self::get_commit_data_async(self.evm.clone(), block_number),
1680
+ |_, result| {
1681
+ Ok(match result {
1682
+ Some((proof, header, txs)) => Some(JsCommitData::new(proof, header, txs)),
1683
+ None => None,
1684
+ })
1685
+ },
1686
+ )
1687
+ }
1688
+
1689
+ #[napi]
1690
+ pub fn get_commits_by_block_range<'env>(
1691
+ &mut self,
1692
+ env: &'env Env,
1693
+ from_block_number: BigInt,
1694
+ to_block_number: BigInt,
1695
+ max_bytes: BigInt,
1696
+ ) -> Result<PromiseRaw<'env, Vec<JsCommitData>>> {
1697
+ let from_block_number = from_block_number.get_u64().1;
1698
+ let to_block_number = to_block_number.get_u64().1;
1699
+ let max_bytes = max_bytes.get_u64().1;
1700
+ env.spawn_future_with_callback(
1701
+ Self::get_commits_by_block_range_async(
1702
+ self.evm.clone(),
1703
+ from_block_number,
1704
+ to_block_number,
1705
+ max_bytes,
1706
+ ),
1707
+ |_, result| {
1708
+ Ok(result
1709
+ .into_iter()
1710
+ .map(|(proof, header, txs)| JsCommitData::new(proof, header, txs))
1711
+ .collect())
1712
+ },
1713
+ )
1714
+ }
1715
+
1716
+ #[napi]
1717
+ pub fn get_transaction_data<'env>(
1718
+ &mut self,
1719
+ env: &'env Env,
1720
+ key: String,
1721
+ ) -> Result<PromiseRaw<'env, Option<JsTransactionData>>> {
1722
+ env.spawn_future_with_callback(
1723
+ Self::get_transaction_data_async(self.evm.clone(), key),
1724
+ |_, result| Ok(result.map(|data| JsTransactionData::new(data))),
1725
+ )
1726
+ }
1727
+
1728
+ #[napi]
1729
+ pub fn get_transaction_key_by_hash<'env>(
1730
+ &mut self,
1731
+ env: &'env Env,
1732
+ tx_hash: String,
1733
+ ) -> Result<PromiseRaw<'env, Option<String>>> {
1734
+ let tx_hash = utils::convert_string_to_b256(tx_hash)?;
1735
+
1736
+ env.spawn_future_with_callback(
1737
+ Self::get_transaction_key_by_hash_async(self.evm.clone(), tx_hash),
1738
+ |_, result| Ok(result),
1739
+ )
1740
+ }
1741
+
1742
+ #[napi]
1743
+ pub fn snapshot<'env>(
1744
+ &mut self,
1745
+ env: &'env Env,
1746
+ commit_key: JsCommitKey,
1747
+ ) -> Result<PromiseRaw<'env, ()>> {
1748
+ let commit_key = CommitKey::try_from(commit_key)?;
1749
+ env.spawn_future_with_callback(
1750
+ Self::snapshot_async(self.evm.clone(), commit_key),
1751
+ |_, _| Ok(()),
1752
+ )
1753
+ }
1754
+
1755
+ #[napi]
1756
+ pub fn rollback<'env>(
1757
+ &mut self,
1758
+ env: &'env Env,
1759
+ commit_key: JsCommitKey,
1760
+ ) -> Result<PromiseRaw<'env, ()>> {
1761
+ let commit_key = CommitKey::try_from(commit_key)?;
1762
+ env.spawn_future_with_callback(
1763
+ Self::rollback_async(self.evm.clone(), commit_key),
1764
+ |_, _| Ok(()),
1765
+ )
1766
+ }
1767
+
1768
+ #[napi]
1769
+ pub fn dispose<'env>(&mut self, env: &'env Env) -> Result<PromiseRaw<'env, ()>> {
1770
+ env.spawn_future_with_callback(Self::dispose_async(self.evm.clone()), |_, _| Ok(()))
1771
+ }
1772
+
1773
+ async fn preverify_transaction_async(
1774
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1775
+ tx_ctx: PreverifyTxContext,
1776
+ ) -> Result<PreverifyTxResult> {
1777
+ let mut lock = evm.lock().await;
1778
+ let result = lock.preverify_transaction(tx_ctx);
1779
+
1780
+ match result {
1781
+ Ok(result) => Result::Ok(result),
1782
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1783
+ }
1784
+ }
1785
+
1786
+ async fn view_async(
1787
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1788
+ view_ctx: TxViewContext,
1789
+ ) -> Result<TxViewResult> {
1790
+ let mut lock = evm.lock().await;
1791
+ lock.view(view_ctx)
1792
+ }
1793
+
1794
+ async fn process_async(
1795
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1796
+ tx_ctx: TxContext,
1797
+ ) -> Result<TxReceipt> {
1798
+ let mut lock = evm.lock().await;
1799
+ let result = lock.process(tx_ctx);
1800
+
1801
+ match result {
1802
+ Ok(result) => Result::Ok(result),
1803
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1804
+ }
1805
+ }
1806
+
1807
+ async fn simulate_async(
1808
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1809
+ tx_ctx: TxSimulateContext,
1810
+ ) -> Result<TxReceipt> {
1811
+ let mut lock = evm.lock().await;
1812
+ let result = lock.simulate(tx_ctx);
1813
+
1814
+ match result {
1815
+ Ok(result) => Result::Ok(result),
1816
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1817
+ }
1818
+ }
1819
+
1820
+ async fn get_account_info_async(
1821
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1822
+ address: Address,
1823
+ block_number: Option<u64>,
1824
+ ) -> Result<AccountInfo> {
1825
+ let mut lock = evm.lock().await;
1826
+ let result = lock.get_account_info(address, block_number);
1827
+
1828
+ match result {
1829
+ Ok(account) => Result::Ok(account),
1830
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1831
+ }
1832
+ }
1833
+
1834
+ async fn get_account_info_extended_async(
1835
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1836
+ address: Address,
1837
+ legacy_address: Option<LegacyAddress>,
1838
+ ) -> Result<AccountInfoExtended> {
1839
+ let mut lock = evm.lock().await;
1840
+ let result = lock.get_account_info_extended(address, legacy_address);
1841
+
1842
+ match result {
1843
+ Ok(account) => Result::Ok(account),
1844
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1845
+ }
1846
+ }
1847
+
1848
+ async fn import_account_infos_async(
1849
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1850
+ infos: Vec<AccountInfoExtended>,
1851
+ ) -> Result<()> {
1852
+ let mut lock = evm.lock().await;
1853
+ let result = lock.import_account_infos(infos);
1854
+
1855
+ match result {
1856
+ Ok(_) => Result::Ok(()),
1857
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1858
+ }
1859
+ }
1860
+
1861
+ async fn import_legacy_cold_wallets_async(
1862
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1863
+ wallets: Vec<LegacyColdWallet>,
1864
+ ) -> Result<()> {
1865
+ let mut lock = evm.lock().await;
1866
+ let result = lock.import_legacy_cold_wallets(wallets);
1867
+
1868
+ match result {
1869
+ Ok(_) => Result::Ok(()),
1870
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1871
+ }
1872
+ }
1873
+
1874
+ async fn initialize_genesis_async(
1875
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1876
+ genesis_ctx: GenesisContext,
1877
+ ) -> Result<()> {
1878
+ let mut lock = evm.lock().await;
1879
+ let result = lock.initialize_genesis(genesis_ctx);
1880
+
1881
+ match result {
1882
+ Ok(_) => Result::Ok(()),
1883
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1884
+ }
1885
+ }
1886
+
1887
+ async fn prepare_next_commit_async(
1888
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1889
+ ctx: PrepareNextCommitContext,
1890
+ ) -> Result<()> {
1891
+ let mut lock = evm.lock().await;
1892
+ let result = lock.prepare_next_commit(ctx);
1893
+
1894
+ match result {
1895
+ Ok(_) => Result::Ok(()),
1896
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1897
+ }
1898
+ }
1899
+
1900
+ async fn calculate_round_validators_async(
1901
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1902
+ ctx: CalculateRoundValidatorsContext,
1903
+ ) -> Result<()> {
1904
+ let mut lock = evm.lock().await;
1905
+ let result = lock.calculate_round_validators(ctx);
1906
+
1907
+ match result {
1908
+ Ok(_) => Result::Ok(()),
1909
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1910
+ }
1911
+ }
1912
+
1913
+ async fn update_rewards_and_votes_async(
1914
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1915
+ ctx: UpdateRewardsAndVotesContext,
1916
+ ) -> Result<()> {
1917
+ let mut lock = evm.lock().await;
1918
+ let result = lock.update_rewards_and_votes(ctx);
1919
+
1920
+ match result {
1921
+ Ok(_) => Result::Ok(()),
1922
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1923
+ }
1924
+ }
1925
+
1926
+ async fn code_at_async(
1927
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1928
+ address: Address,
1929
+ block_number: Option<u64>,
1930
+ ) -> Result<String> {
1931
+ let mut lock = evm.lock().await;
1932
+ let result = lock.code_at(address, block_number);
1933
+
1934
+ match result {
1935
+ Ok(code) => Result::Ok(revm::primitives::hex::encode_prefixed(code.as_ref())),
1936
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1937
+ }
1938
+ }
1939
+
1940
+ async fn storage_at_async(
1941
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1942
+ address: Address,
1943
+ slot: U256,
1944
+ ) -> Result<String> {
1945
+ let mut lock = evm.lock().await;
1946
+ let result = lock.storage_at(address, slot);
1947
+
1948
+ match result {
1949
+ Ok(slot) => Result::Ok(revm::primitives::hex::encode_prefixed(
1950
+ slot.to_be_bytes::<32>(),
1951
+ )),
1952
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1953
+ }
1954
+ }
1955
+
1956
+ async fn commit_async(
1957
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1958
+ commit_key: CommitKey,
1959
+ commit_data: Option<CommitData>,
1960
+ ) -> Result<CommitResult> {
1961
+ let mut lock = evm.lock().await;
1962
+ let result = lock.commit(commit_key, commit_data);
1963
+
1964
+ match result {
1965
+ Ok(result) => Result::Ok(CommitResult {
1966
+ dirty_accounts: result,
1967
+ }),
1968
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1969
+ }
1970
+ }
1971
+
1972
+ async fn state_root_async(
1973
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1974
+ commit_key: CommitKey,
1975
+ current_hash: B256,
1976
+ ) -> Result<String> {
1977
+ let mut lock = evm.lock().await;
1978
+ let result = lock.state_root(commit_key, current_hash);
1979
+
1980
+ match result {
1981
+ Ok(result) => Result::Ok(result),
1982
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1983
+ }
1984
+ }
1985
+
1986
+ async fn logs_bloom_async(
1987
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
1988
+ commit_key: CommitKey,
1989
+ ) -> Result<String> {
1990
+ let mut lock = evm.lock().await;
1991
+ let result = lock.logs_bloom(commit_key);
1992
+
1993
+ match result {
1994
+ Ok(result) => Result::Ok(result),
1995
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
1996
+ }
1997
+ }
1998
+
1999
+ async fn get_accounts_async(
2000
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2001
+ offset: u64,
2002
+ limit: u64,
2003
+ ) -> Result<(Option<u64>, Vec<AccountInfoExtended>)> {
2004
+ let mut lock = evm.lock().await;
2005
+ let result = lock.get_accounts(offset, limit);
2006
+
2007
+ match result {
2008
+ Ok(result) => Result::Ok(result),
2009
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2010
+ }
2011
+ }
2012
+
2013
+ async fn get_legacy_attributes_async(
2014
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2015
+ address: Address,
2016
+ legacy_address: Option<LegacyAddress>,
2017
+ ) -> Result<Option<LegacyAccountAttributes>> {
2018
+ let mut lock = evm.lock().await;
2019
+ let result = lock.get_legacy_attributes(address, legacy_address);
2020
+
2021
+ match result {
2022
+ Ok(result) => Result::Ok(result),
2023
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2024
+ }
2025
+ }
2026
+
2027
+ async fn get_legacy_cold_wallets_async(
2028
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2029
+ offset: u64,
2030
+ limit: u64,
2031
+ ) -> Result<(Option<u64>, Vec<LegacyColdWallet>)> {
2032
+ let mut lock = evm.lock().await;
2033
+ let result = lock.get_legacy_cold_wallets(offset, limit);
2034
+
2035
+ match result {
2036
+ Ok(result) => Result::Ok(result),
2037
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2038
+ }
2039
+ }
2040
+
2041
+ async fn get_receipts_async(
2042
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2043
+ offset: u64,
2044
+ limit: u64,
2045
+ ) -> Result<(Option<u64>, Vec<(u64, Vec<(B256, TxReceipt)>)>)> {
2046
+ let mut lock = evm.lock().await;
2047
+ let result = lock.get_receipts(offset, limit);
2048
+
2049
+ match result {
2050
+ Ok(result) => Result::Ok(result),
2051
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2052
+ }
2053
+ }
2054
+
2055
+ async fn get_receipts_by_block_number_async(
2056
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2057
+ block_number: u64,
2058
+ ) -> Result<HashMap<B256, TxReceipt>> {
2059
+ let mut lock = evm.lock().await;
2060
+ let result = lock.get_receipts_by_block_number(block_number);
2061
+
2062
+ match result {
2063
+ Ok(result) => Result::Ok(result),
2064
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2065
+ }
2066
+ }
2067
+
2068
+ async fn get_receipts_by_block_range_async(
2069
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2070
+ from_block_number: u64,
2071
+ to_block_number: u64,
2072
+ ) -> Result<Vec<(u64, Vec<(B256, TxReceipt)>)>> {
2073
+ let mut lock = evm.lock().await;
2074
+ let result = lock.get_receipts_by_block_range(from_block_number, to_block_number);
2075
+
2076
+ match result {
2077
+ Ok(result) => Result::Ok(result),
2078
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2079
+ }
2080
+ }
2081
+
2082
+ async fn get_receipt_async(
2083
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2084
+ block_number: u64,
2085
+ tx_hash: B256,
2086
+ ) -> Result<Option<TxReceipt>> {
2087
+ let mut lock = evm.lock().await;
2088
+ let result = lock.get_receipt(block_number, tx_hash);
2089
+
2090
+ match result {
2091
+ Ok(result) => Result::Ok(result),
2092
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2093
+ }
2094
+ }
2095
+
2096
+ async fn is_empty_async(evm: Arc<tokio::sync::Mutex<EvmInner>>) -> Result<bool> {
2097
+ let mut lock = evm.lock().await;
2098
+ let result = lock.is_empty();
2099
+
2100
+ match result {
2101
+ Ok(result) => Result::Ok(result),
2102
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2103
+ }
2104
+ }
2105
+
2106
+ async fn get_state_async(evm: Arc<tokio::sync::Mutex<EvmInner>>) -> Result<(u64, u64)> {
2107
+ let mut lock = evm.lock().await;
2108
+ let result = lock.get_state();
2109
+
2110
+ match result {
2111
+ Ok(result) => Result::Ok(result),
2112
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2113
+ }
2114
+ }
2115
+
2116
+ async fn get_block_header_data_async(
2117
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2118
+ block_number: u64,
2119
+ ) -> Result<Option<BlockHeaderData>> {
2120
+ let mut lock = evm.lock().await;
2121
+ let result = lock.get_block_header_data(block_number);
2122
+
2123
+ match result {
2124
+ Ok(result) => Result::Ok(result),
2125
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2126
+ }
2127
+ }
2128
+
2129
+ async fn get_block_number_by_hash_async(
2130
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2131
+ block_hash: B256,
2132
+ ) -> Result<Option<u64>> {
2133
+ let mut lock = evm.lock().await;
2134
+ let result = lock.get_block_number_by_hash(block_hash);
2135
+
2136
+ match result {
2137
+ Ok(result) => Result::Ok(result),
2138
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2139
+ }
2140
+ }
2141
+
2142
+ async fn get_commit_data_async(
2143
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2144
+ block_number: u64,
2145
+ ) -> Result<Option<(ProofData, BlockHeaderData, Vec<TransactionData>)>> {
2146
+ let mut lock = evm.lock().await;
2147
+ let result = lock.get_commit_data(block_number);
2148
+
2149
+ match result {
2150
+ Ok(result) => Result::Ok(result),
2151
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2152
+ }
2153
+ }
2154
+
2155
+ async fn get_commits_by_block_range_async(
2156
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2157
+ from_block_number: u64,
2158
+ to_block_number: u64,
2159
+ max_bytes: u64,
2160
+ ) -> Result<Vec<(ProofData, BlockHeaderData, Vec<TransactionData>)>> {
2161
+ let mut lock = evm.lock().await;
2162
+ let result = lock.get_commits_by_block_range(from_block_number, to_block_number, max_bytes);
2163
+
2164
+ match result {
2165
+ Ok(result) => Result::Ok(result),
2166
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2167
+ }
2168
+ }
2169
+
2170
+ async fn get_transaction_data_async(
2171
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2172
+ key: String,
2173
+ ) -> Result<Option<TransactionData>> {
2174
+ let mut lock = evm.lock().await;
2175
+ let result = lock.get_transaction_data(key);
2176
+
2177
+ match result {
2178
+ Ok(result) => Result::Ok(result),
2179
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2180
+ }
2181
+ }
2182
+
2183
+ async fn get_transaction_key_by_hash_async(
2184
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2185
+ tx_hash: B256,
2186
+ ) -> Result<Option<String>> {
2187
+ let mut lock = evm.lock().await;
2188
+ let result = lock.get_transaction_key_by_hash(tx_hash);
2189
+
2190
+ match result {
2191
+ Ok(result) => Result::Ok(result),
2192
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2193
+ }
2194
+ }
2195
+
2196
+ async fn snapshot_async(
2197
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2198
+ commit_key: CommitKey,
2199
+ ) -> Result<()> {
2200
+ let mut lock = evm.lock().await;
2201
+ let result = lock.snapshot(commit_key);
2202
+
2203
+ match result {
2204
+ Ok(result) => Result::Ok(result),
2205
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2206
+ }
2207
+ }
2208
+
2209
+ async fn rollback_async(
2210
+ evm: Arc<tokio::sync::Mutex<EvmInner>>,
2211
+ commit_key: CommitKey,
2212
+ ) -> Result<()> {
2213
+ let mut lock = evm.lock().await;
2214
+ let result = lock.rollback(commit_key);
2215
+
2216
+ match result {
2217
+ Ok(result) => Result::Ok(result),
2218
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2219
+ }
2220
+ }
2221
+
2222
+ async fn dispose_async(evm: Arc<tokio::sync::Mutex<EvmInner>>) -> Result<()> {
2223
+ let mut lock = evm.lock().await;
2224
+ let result = lock.dispose();
2225
+
2226
+ match result {
2227
+ Ok(result) => Result::Ok(result),
2228
+ Err(err) => Result::Err(serde::de::Error::custom(err)),
2229
+ }
2230
+ }
2231
+ }