anvil_zksync_core/node/
in_memory_ext.rs

1use super::pool::TxBatch;
2use super::sealer::BlockSealerMode;
3use super::InMemoryNode;
4use anvil_zksync_types::api::{DetailedTransaction, ResetRequest};
5use anyhow::{anyhow, Context};
6use std::str::FromStr;
7use std::time::Duration;
8use url::Url;
9use zksync_types::api::{Block, TransactionVariant};
10use zksync_types::bytecode::BytecodeHash;
11use zksync_types::u256_to_h256;
12use zksync_types::{AccountTreeId, Address, L2BlockNumber, StorageKey, H256, U256, U64};
13
14type Result<T> = anyhow::Result<T>;
15
16/// The maximum number of [Snapshot]s to store. Each snapshot represents the node state
17/// and can be used to revert the node to an earlier point in time.
18const MAX_SNAPSHOTS: u8 = 100;
19
20impl InMemoryNode {
21    /// Increase the current timestamp for the node
22    ///
23    /// # Parameters
24    /// - `time_delta`: The number of seconds to increase time by
25    ///
26    /// # Returns
27    /// The applied time delta to `current_timestamp` value for the InMemoryNodeInner.
28    pub async fn increase_time(&self, time_delta_seconds: u64) -> Result<u64> {
29        self.node_handle
30            .increase_time_sync(time_delta_seconds)
31            .await?;
32        Ok(time_delta_seconds)
33    }
34
35    /// Set the current timestamp for the node. The timestamp must be in the future.
36    ///
37    /// # Parameters
38    /// - `timestamp`: The timestamp to set the time to
39    ///
40    /// # Returns
41    /// The new timestamp value for the InMemoryNodeInner.
42    pub async fn set_next_block_timestamp(&self, timestamp: u64) -> Result<()> {
43        self.node_handle
44            .enforce_next_timestamp_sync(timestamp)
45            .await?;
46        Ok(())
47    }
48
49    /// Set the current timestamp for the node.
50    /// Warning: This will allow you to move backwards in time, which may cause new blocks to appear to be
51    /// mined before old blocks. This will result in an invalid state.
52    ///
53    /// # Parameters
54    /// - `time`: The timestamp to set the time to
55    ///
56    /// # Returns
57    /// The difference between the `current_timestamp` and the new timestamp for the InMemoryNodeInner.
58    pub async fn set_time(&self, timestamp: u64) -> Result<i128> {
59        self.node_handle.set_current_timestamp_sync(timestamp).await
60    }
61
62    /// Force a single block to be mined.
63    ///
64    /// Will mine an empty block (containing zero transactions)
65    ///
66    /// # Returns
67    /// The string "0x0".
68    pub async fn mine_block(&self) -> Result<L2BlockNumber> {
69        // TODO: Remove locking once `TestNodeConfig` is refactored into mutable/immutable components
70        let max_transactions = self.inner.read().await.config.max_transactions;
71        let tx_batch = self.pool.take_uniform(max_transactions).unwrap_or(TxBatch {
72            impersonating: false,
73            txs: Vec::new(),
74        });
75
76        let block_number = self.node_handle.seal_block_sync(tx_batch).await?;
77        tracing::info!("Mined block #{}", block_number);
78        Ok(block_number)
79    }
80
81    pub async fn mine_detailed(&self) -> Result<Block<DetailedTransaction>> {
82        let block_number = self.mine_block().await?;
83        let mut block = self
84            .blockchain
85            .get_block_by_number(block_number)
86            .await
87            .expect("freshly mined block is missing from storage");
88        let mut detailed_txs = Vec::with_capacity(block.transactions.len());
89        for tx in std::mem::take(&mut block.transactions) {
90            let detailed_tx = match tx {
91                TransactionVariant::Full(tx) => self
92                    .blockchain
93                    .get_detailed_tx(tx)
94                    .await
95                    .expect("freshly executed tx is missing from storage"),
96                TransactionVariant::Hash(_) => {
97                    unreachable!("we only store full txs in blocks")
98                }
99            };
100            detailed_txs.push(detailed_tx);
101        }
102        Ok(block.with_transactions(detailed_txs))
103    }
104
105    /// Snapshot the state of the blockchain at the current block. Takes no parameters. Returns the id of the snapshot
106    /// that was created. A snapshot can only be reverted once. After a successful evm_revert, the same snapshot id cannot
107    /// be used again. Consider creating a new snapshot after each evm_revert if you need to revert to the same
108    /// point multiple times.
109    ///
110    /// # Returns
111    /// The `U64` identifier for this snapshot.
112    pub async fn snapshot(&self) -> Result<U64> {
113        let snapshots = self.snapshots.clone();
114        let reader = self.inner.read().await;
115        // FIXME: TOCTOU with below
116        // validate max snapshots
117        if snapshots.read().await.len() >= MAX_SNAPSHOTS as usize {
118            return Err(anyhow!(
119                "maximum number of '{}' snapshots exceeded",
120                MAX_SNAPSHOTS
121            ));
122        };
123
124        // snapshot the node
125        let snapshot = reader.snapshot().await.map_err(|err| anyhow!("{}", err))?;
126        let mut snapshots = snapshots.write().await;
127        snapshots.push(snapshot);
128        tracing::debug!("Created snapshot '{}'", snapshots.len());
129        Ok(U64::from(snapshots.len()))
130    }
131
132    /// Revert the state of the blockchain to a previous snapshot. Takes a single parameter,
133    /// which is the snapshot id to revert to. This deletes the given snapshot, as well as any snapshots
134    /// taken after (e.g.: reverting to id 0x1 will delete snapshots with ids 0x1, 0x2, etc.)
135    ///
136    /// # Parameters
137    /// - `snapshot_id`: The snapshot id to revert.
138    ///
139    /// # Returns
140    /// `true` if a snapshot was reverted, otherwise `false`.
141    pub async fn revert_snapshot(&self, snapshot_id: U64) -> Result<bool> {
142        let snapshots = self.snapshots.clone();
143        let mut writer = self.inner.write().await;
144        let mut snapshots = snapshots.write().await;
145        let snapshot_id_index = snapshot_id.as_usize().saturating_sub(1);
146        if snapshot_id_index >= snapshots.len() {
147            return Err(anyhow!("no snapshot exists for the id '{}'", snapshot_id));
148        }
149
150        // remove all snapshots following the index and use the first snapshot for restore
151        let selected_snapshot = snapshots
152            .drain(snapshot_id_index..)
153            .next()
154            .expect("unexpected failure, value must exist");
155
156        tracing::debug!("Reverting node to snapshot '{snapshot_id:?}'");
157        writer
158            .restore_snapshot(selected_snapshot)
159            .await
160            .map(|_| {
161                tracing::debug!("Reverting node to snapshot '{snapshot_id:?}'");
162                true
163            })
164            .map_err(|err| anyhow!("{}", err))
165    }
166
167    pub async fn set_balance(&self, address: Address, balance: U256) -> anyhow::Result<bool> {
168        self.node_handle.set_balance_sync(address, balance).await?;
169        tracing::info!(
170            "Balance for address {:?} has been manually set to {} Wei",
171            address,
172            balance
173        );
174        Ok(true)
175    }
176
177    pub async fn set_nonce(&self, address: Address, nonce: U256) -> anyhow::Result<bool> {
178        self.node_handle.set_nonce_sync(address, nonce).await?;
179        tracing::info!(
180            "Nonces for address {:?} have been set to {}",
181            address,
182            nonce
183        );
184        Ok(true)
185    }
186
187    pub async fn mine_blocks(&self, num_blocks: Option<U64>, interval: Option<U64>) -> Result<()> {
188        let num_blocks = num_blocks.map_or(1, |x| x.as_u64());
189        let interval_sec = interval.map_or(1, |x| x.as_u64());
190
191        if num_blocks == 0 {
192            return Ok(());
193        }
194        if num_blocks > 1 && interval_sec == 0 {
195            anyhow::bail!("Provided interval is `0`; unable to produce {num_blocks} blocks with the same timestamp");
196        }
197
198        // TODO: Remove locking once `TestNodeConfig` is refactored into mutable/immutable components
199        let max_transactions = self.inner.read().await.config.max_transactions;
200        let mut tx_batches = Vec::with_capacity(num_blocks as usize);
201        for _ in 0..num_blocks {
202            let tx_batch = self.pool.take_uniform(max_transactions).unwrap_or(TxBatch {
203                impersonating: false,
204                txs: Vec::new(),
205            });
206            tx_batches.push(tx_batch);
207        }
208        self.node_handle
209            .seal_blocks_sync(tx_batches, interval_sec)
210            .await?;
211        tracing::info!("Mined {} blocks", num_blocks);
212
213        Ok(())
214    }
215
216    // @dev This function is necessary for Hardhat Ignite compatibility with `evm_emulator`.
217    // It always returns `true`, as each new transaction automatically mines a new block by default.
218    // Disabling auto mining would require adding functionality to mine blocks with pending transactions.
219    // This feature is not yet implemented and should be deferred until `run_l2_tx` and `run_l2_tx_raw` are
220    // refactored to handle pending transactions and modularized into smaller functions for maintainability.
221    pub fn get_automine(&self) -> Result<bool> {
222        Ok(true)
223    }
224
225    pub async fn reset_network(&self, reset_spec: Option<ResetRequest>) -> Result<bool> {
226        if let Some(spec) = reset_spec {
227            if let Some(to) = spec.to {
228                if spec.forking.is_some() {
229                    return Err(anyhow!(
230                        "Only one of 'to' and 'forking' attributes can be specified"
231                    ));
232                }
233                self.node_handle
234                    .reset_fork_block_number_sync(L2BlockNumber(to.as_u32()))
235                    .await?;
236            } else if let Some(forking) = spec.forking {
237                let url = Url::from_str(&forking.json_rpc_url).context("malformed fork URL")?;
238                let block_number = forking.block_number.map(|n| L2BlockNumber(n.as_u32()));
239                self.node_handle.reset_fork_sync(url, block_number).await?;
240            } else {
241                self.node_handle.remove_fork_sync().await?;
242            }
243        } else {
244            self.node_handle.remove_fork_sync().await?;
245        }
246
247        self.snapshots.write().await.clear();
248
249        tracing::debug!("Network reset");
250
251        Ok(true)
252    }
253
254    pub fn auto_impersonate_account(&self, enabled: bool) {
255        self.impersonation.set_auto_impersonation(enabled);
256    }
257
258    pub fn impersonate_account(&self, address: Address) -> Result<bool> {
259        if self.impersonation.impersonate(address) {
260            tracing::debug!("Account {:?} has been impersonated", address);
261            Ok(true)
262        } else {
263            tracing::debug!("Account {:?} was already impersonated", address);
264            Ok(false)
265        }
266    }
267
268    pub fn stop_impersonating_account(&self, address: Address) -> Result<bool> {
269        if self.impersonation.stop_impersonating(&address) {
270            tracing::debug!("Stopped impersonating account {:?}", address);
271            Ok(true)
272        } else {
273            tracing::debug!(
274                "Account {:?} was not impersonated, nothing to stop",
275                address
276            );
277            Ok(false)
278        }
279    }
280
281    pub async fn set_code(&self, address: Address, code: String) -> Result<()> {
282        let code_slice = code
283            .strip_prefix("0x")
284            .ok_or_else(|| anyhow!("code must be 0x-prefixed"))?;
285        let bytecode = hex::decode(code_slice)?;
286        zksync_types::bytecode::validate_bytecode(&bytecode).context("Invalid bytecode")?;
287        tracing::info!(
288            ?address,
289            bytecode_hash = ?BytecodeHash::for_bytecode(&bytecode).value(),
290            "set code"
291        );
292        self.node_handle.set_code_sync(address, bytecode).await?;
293        Ok(())
294    }
295
296    pub async fn set_storage_at(&self, address: Address, slot: U256, value: U256) -> Result<bool> {
297        let key = StorageKey::new(AccountTreeId::new(address), u256_to_h256(slot));
298        self.node_handle.set_storage_sync(key, value).await?;
299        Ok(true)
300    }
301
302    pub fn set_logging_enabled(&self, enable: bool) -> Result<()> {
303        let Some(observability) = &self.observability else {
304            anyhow::bail!("Node's logging is not set up");
305        };
306        if enable {
307            observability.enable_logging()
308        } else {
309            observability.disable_logging()
310        }
311    }
312
313    pub fn get_immediate_sealing(&self) -> Result<bool> {
314        Ok(self.sealer_state.is_immediate())
315    }
316
317    pub async fn set_block_timestamp_interval(&self, seconds: u64) -> Result<()> {
318        self.node_handle
319            .set_block_timestamp_interval(seconds)
320            .await?;
321        Ok(())
322    }
323
324    pub async fn remove_block_timestamp_interval(&self) -> Result<bool> {
325        self.node_handle
326            .remove_block_timestamp_interval_sync()
327            .await
328    }
329
330    pub async fn set_immediate_sealing(&self, enable: bool) -> Result<()> {
331        if enable {
332            let listener = self.pool.add_tx_listener();
333            self.sealer_state.set_mode(BlockSealerMode::immediate(
334                self.inner.read().await.config.max_transactions,
335                listener,
336            ))
337        } else {
338            self.sealer_state.set_mode(BlockSealerMode::Noop)
339        }
340        Ok(())
341    }
342
343    pub async fn set_interval_sealing(&self, seconds: u64) -> Result<()> {
344        let sealing_mode = if seconds == 0 {
345            BlockSealerMode::noop()
346        } else {
347            let block_time = Duration::from_secs(seconds);
348
349            BlockSealerMode::fixed_time(self.inner.read().await.config.max_transactions, block_time)
350        };
351        self.sealer_state.set_mode(sealing_mode);
352        Ok(())
353    }
354
355    pub fn drop_transaction(&self, hash: H256) -> Result<Option<H256>> {
356        Ok(self.pool.drop_transaction(hash).map(|tx| tx.hash()))
357    }
358
359    pub fn drop_all_transactions(&self) -> Result<()> {
360        self.pool.clear();
361        Ok(())
362    }
363
364    pub fn remove_pool_transactions(&self, address: Address) -> Result<()> {
365        self.pool
366            .drop_transactions(|tx| tx.transaction.initiator_account() == address);
367        Ok(())
368    }
369
370    pub async fn set_next_block_base_fee_per_gas(&self, base_fee: U256) -> Result<()> {
371        self.node_handle
372            .enforce_next_base_fee_per_gas_sync(base_fee)
373            .await
374    }
375
376    pub async fn set_rpc_url(&self, url: String) -> Result<()> {
377        let url = Url::from_str(&url).context("malformed fork URL")?;
378        if let Some(old_url) = self.node_handle.set_fork_url_sync(url.clone()).await? {
379            tracing::info!("Updated fork rpc from \"{}\" to \"{}\"", old_url, url);
380        } else {
381            tracing::info!("Non-forking node tried to switch RPC URL to '{url}'. Call `anvil_reset` instead if you wish to switch to forking mode");
382        }
383        Ok(())
384    }
385
386    pub async fn set_chain_id(&self, id: u32) -> Result<()> {
387        let mut inner = self.inner.write().await;
388
389        inner.config.update_chain_id(Some(id));
390        inner.fork_storage.set_chain_id(id.into());
391        Ok(())
392    }
393}
394
395#[cfg(test)]
396mod tests {
397    use super::*;
398    use crate::node::InMemoryNode;
399    use crate::testing::TransactionBuilder;
400    use std::str::FromStr;
401    use zksync_multivm::interface::storage::ReadStorage;
402    use zksync_types::{api, L1BatchNumber, Transaction};
403    use zksync_types::{h256_to_u256, L2ChainId, H256};
404
405    #[tokio::test]
406    async fn test_set_balance() {
407        let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap();
408        let node = InMemoryNode::test(None);
409
410        let balance_before = node.get_balance_impl(address, None).await.unwrap();
411
412        let result = node.set_balance(address, U256::from(1337)).await.unwrap();
413        assert!(result);
414
415        let balance_after = node.get_balance_impl(address, None).await.unwrap();
416        assert_eq!(balance_after, U256::from(1337));
417        assert_ne!(balance_before, balance_after);
418    }
419
420    #[tokio::test]
421    async fn test_set_nonce() {
422        let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap();
423        let node = InMemoryNode::test(None);
424
425        let nonce_before = node
426            .get_transaction_count_impl(address, None)
427            .await
428            .unwrap();
429
430        let result = node.set_nonce(address, U256::from(1337)).await.unwrap();
431        assert!(result);
432
433        let nonce_after = node
434            .get_transaction_count_impl(address, None)
435            .await
436            .unwrap();
437        assert_eq!(nonce_after, U256::from(1337));
438        assert_ne!(nonce_before, nonce_after);
439
440        let result = node.set_nonce(address, U256::from(1336)).await.unwrap();
441        assert!(result);
442
443        let nonce_after = node
444            .get_transaction_count_impl(address, None)
445            .await
446            .unwrap();
447        assert_eq!(nonce_after, U256::from(1336));
448    }
449
450    #[tokio::test]
451    async fn test_mine_blocks_default() {
452        let node = InMemoryNode::test(None);
453
454        let start_block = node
455            .get_block_impl(api::BlockId::Number(api::BlockNumber::Latest), false)
456            .await
457            .unwrap()
458            .expect("block exists");
459
460        // test with defaults
461        node.mine_blocks(None, None).await.expect("mine_blocks");
462
463        let current_block = node
464            .get_block_impl(api::BlockId::Number(api::BlockNumber::Latest), false)
465            .await
466            .unwrap()
467            .expect("block exists");
468
469        assert_eq!(start_block.number + 1, current_block.number);
470        assert_eq!(start_block.timestamp + 1, current_block.timestamp);
471        node.mine_blocks(None, None).await.expect("mine_blocks");
472
473        let current_block = node
474            .get_block_impl(api::BlockId::Number(api::BlockNumber::Latest), false)
475            .await
476            .unwrap()
477            .expect("block exists");
478
479        assert_eq!(start_block.number + 2, current_block.number);
480        assert_eq!(start_block.timestamp + 2, current_block.timestamp);
481    }
482
483    #[tokio::test]
484    async fn test_mine_blocks() {
485        let node = InMemoryNode::test(None);
486
487        let start_block = node
488            .get_block_impl(api::BlockId::Number(api::BlockNumber::Latest), false)
489            .await
490            .unwrap()
491            .expect("block exists");
492
493        let num_blocks = 5;
494        let interval = 3;
495        let start_timestamp = start_block.timestamp + 1;
496
497        node.mine_blocks(Some(U64::from(num_blocks)), Some(U64::from(interval)))
498            .await
499            .expect("mine blocks");
500
501        for i in 0..num_blocks {
502            let current_block = node
503                .get_block_impl(
504                    api::BlockId::Number(api::BlockNumber::Number(start_block.number + i + 1)),
505                    false,
506                )
507                .await
508                .unwrap()
509                .expect("block exists");
510            assert_eq!(start_block.number + i + 1, current_block.number);
511            assert_eq!(start_timestamp + i * interval, current_block.timestamp);
512        }
513    }
514
515    #[tokio::test]
516    async fn test_reset() {
517        let node = InMemoryNode::test(None);
518        // Seal a few blocks to create non-trivial local state
519        for _ in 0..10 {
520            node.node_handle
521                .seal_block_sync(TxBatch {
522                    impersonating: false,
523                    txs: vec![],
524                })
525                .await
526                .unwrap();
527        }
528
529        let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap();
530        let nonce_before = node
531            .get_transaction_count_impl(address, None)
532            .await
533            .unwrap();
534        assert!(node.set_nonce(address, U256::from(1337)).await.unwrap());
535
536        assert!(node.reset_network(None).await.unwrap());
537
538        let nonce_after = node
539            .get_transaction_count_impl(address, None)
540            .await
541            .unwrap();
542        assert_eq!(nonce_before, nonce_after);
543
544        assert_eq!(node.snapshots.read().await.len(), 0);
545        assert_eq!(node.time.current_timestamp(), 1000);
546        assert_eq!(node.blockchain.current_batch().await, L1BatchNumber(0));
547        assert_eq!(
548            node.blockchain.current_block_number().await,
549            L2BlockNumber(0)
550        );
551        assert_ne!(node.blockchain.current_block_hash().await, H256::random());
552    }
553
554    #[tokio::test]
555    async fn test_impersonate_account() {
556        let node = InMemoryNode::test(None);
557        let to_impersonate =
558            Address::from_str("0xd8da6bf26964af9d7eed9e03e53415d37aa96045").unwrap();
559
560        // give impersonated account some balance
561        let result = node
562            .set_balance(to_impersonate, U256::exp10(18))
563            .await
564            .unwrap();
565        assert!(result);
566
567        // construct a random tx each time to avoid hash collision
568        let generate_tx =
569            || Transaction::from(TransactionBuilder::new().impersonate(to_impersonate));
570
571        // try to execute the tx- should fail without signature
572        assert!(node.apply_txs([generate_tx()]).await.is_err());
573
574        // impersonate the account
575        let result = node
576            .impersonate_account(to_impersonate)
577            .expect("impersonate_account");
578
579        // result should be true
580        assert!(result);
581
582        // impersonating the same account again should return false
583        let result = node
584            .impersonate_account(to_impersonate)
585            .expect("impersonate_account");
586        assert!(!result);
587
588        // execution should now succeed
589        assert!(node.apply_txs([generate_tx()]).await.is_ok());
590
591        // stop impersonating the account
592        let result = node
593            .stop_impersonating_account(to_impersonate)
594            .expect("stop_impersonating_account");
595
596        // result should be true
597        assert!(result);
598
599        // stop impersonating the same account again should return false
600        let result = node
601            .stop_impersonating_account(to_impersonate)
602            .expect("stop_impersonating_account");
603        assert!(!result);
604
605        // execution should now fail again
606        assert!(node.apply_txs([generate_tx()]).await.is_err());
607    }
608
609    #[tokio::test]
610    async fn test_set_code() {
611        let address = Address::repeat_byte(0x1);
612        let node = InMemoryNode::test(None);
613        let new_code = vec![0x1u8; 32];
614
615        let code_before = node
616            .get_code_impl(address, None)
617            .await
618            .expect("failed getting code")
619            .0;
620        assert_eq!(Vec::<u8>::default(), code_before);
621
622        node.set_code(address, format!("0x{}", hex::encode(new_code.clone())))
623            .await
624            .expect("failed setting code");
625
626        let code_after = node
627            .get_code_impl(address, None)
628            .await
629            .expect("failed getting code")
630            .0;
631        assert_eq!(new_code, code_after);
632    }
633
634    #[tokio::test]
635    async fn test_set_storage_at() {
636        let node = InMemoryNode::test(None);
637        let address = Address::repeat_byte(0x1);
638        let slot = U256::from(37);
639        let value = U256::from(42);
640
641        let key = StorageKey::new(AccountTreeId::new(address), u256_to_h256(slot));
642        let value_before = node.inner.write().await.fork_storage.read_value(&key);
643        assert_eq!(H256::default(), value_before);
644
645        let result = node.set_storage_at(address, slot, value).await.unwrap();
646        assert!(result);
647
648        let value_after = node.inner.write().await.fork_storage.read_value(&key);
649        assert_eq!(value, h256_to_u256(value_after));
650    }
651
652    #[tokio::test]
653    async fn test_increase_time_zero_value() {
654        let node = InMemoryNode::test(None);
655
656        let increase_value_seconds = 0u64;
657        let timestamp_before = node.time.current_timestamp();
658        let expected_response = increase_value_seconds;
659
660        let actual_response = node
661            .increase_time(increase_value_seconds)
662            .await
663            .expect("failed increasing timestamp");
664        let timestamp_after = node.time.current_timestamp();
665
666        assert_eq!(expected_response, actual_response, "erroneous response");
667        assert_eq!(
668            increase_value_seconds.saturating_mul(1000u64),
669            timestamp_after.saturating_sub(timestamp_before),
670            "timestamp did not increase by the specified amount",
671        );
672    }
673
674    #[tokio::test]
675    async fn test_increase_time_max_value() {
676        let node = InMemoryNode::test(None);
677
678        let increase_value_seconds = u64::MAX;
679        let timestamp_before = node.time.current_timestamp();
680        assert_ne!(0, timestamp_before, "initial timestamp must be non zero",);
681        let expected_response = increase_value_seconds;
682
683        let actual_response = node
684            .increase_time(increase_value_seconds)
685            .await
686            .expect("failed increasing timestamp");
687        let timestamp_after = node.time.current_timestamp();
688
689        assert_eq!(expected_response, actual_response, "erroneous response");
690        assert_eq!(
691            u64::MAX,
692            timestamp_after,
693            "timestamp did not saturate upon increase",
694        );
695    }
696
697    #[tokio::test(flavor = "multi_thread", worker_threads = 3)]
698    async fn test_increase_time() {
699        let node = InMemoryNode::test(None);
700
701        let increase_value_seconds = 100u64;
702        let timestamp_before = node.time.current_timestamp();
703        let expected_response = increase_value_seconds;
704
705        let actual_response = node
706            .increase_time(increase_value_seconds)
707            .await
708            .expect("failed increasing timestamp");
709        let timestamp_after = node.time.current_timestamp();
710
711        assert_eq!(expected_response, actual_response, "erroneous response");
712        assert_eq!(
713            increase_value_seconds,
714            timestamp_after.saturating_sub(timestamp_before),
715            "timestamp did not increase by the specified amount",
716        );
717    }
718
719    #[tokio::test]
720    async fn test_set_next_block_timestamp_future() {
721        let node = InMemoryNode::test(None);
722
723        let new_timestamp = 10_000u64;
724        let timestamp_before = node.time.current_timestamp();
725        assert_ne!(
726            timestamp_before, new_timestamp,
727            "timestamps must be different"
728        );
729
730        node.set_next_block_timestamp(new_timestamp)
731            .await
732            .expect("failed setting timestamp");
733        node.mine_block().await.expect("failed to mine a block");
734        let timestamp_after = node.time.current_timestamp();
735
736        assert_eq!(
737            new_timestamp, timestamp_after,
738            "timestamp was not set correctly",
739        );
740    }
741
742    #[tokio::test]
743    async fn test_set_next_block_timestamp_past_fails() {
744        let node = InMemoryNode::test(None);
745
746        let timestamp_before = node.time.current_timestamp();
747
748        let new_timestamp = timestamp_before + 500;
749        node.set_next_block_timestamp(new_timestamp)
750            .await
751            .expect("failed setting timestamp");
752
753        node.mine_block().await.expect("failed to mine a block");
754
755        let result = node.set_next_block_timestamp(timestamp_before).await;
756
757        assert!(result.is_err(), "expected an error for timestamp in past");
758    }
759
760    #[tokio::test]
761    async fn test_set_next_block_timestamp_same_value() {
762        let node = InMemoryNode::test(None);
763
764        let new_timestamp = 1000u64;
765        let timestamp_before = node.time.current_timestamp();
766        assert_eq!(timestamp_before, new_timestamp, "timestamps must be same");
767
768        let response = node.set_next_block_timestamp(new_timestamp).await;
769        assert!(response.is_err());
770
771        let timestamp_after = node.time.current_timestamp();
772        assert_eq!(
773            timestamp_before, timestamp_after,
774            "timestamp must not change",
775        );
776    }
777
778    #[tokio::test]
779    async fn test_set_time_future() {
780        let node = InMemoryNode::test(None);
781
782        let new_time = 10_000u64;
783        let timestamp_before = node.time.current_timestamp();
784        assert_ne!(timestamp_before, new_time, "timestamps must be different");
785        let expected_response = 9000;
786
787        let actual_response = node
788            .set_time(new_time)
789            .await
790            .expect("failed setting timestamp");
791        let timestamp_after = node.time.current_timestamp();
792
793        assert_eq!(expected_response, actual_response, "erroneous response");
794        assert_eq!(new_time, timestamp_after, "timestamp was not set correctly",);
795    }
796
797    #[tokio::test]
798    async fn test_set_time_past() {
799        let node = InMemoryNode::test(None);
800
801        let new_time = 10u64;
802        let timestamp_before = node.time.current_timestamp();
803        assert_ne!(timestamp_before, new_time, "timestamps must be different");
804        let expected_response = -990;
805
806        let actual_response = node
807            .set_time(new_time)
808            .await
809            .expect("failed setting timestamp");
810        let timestamp_after = node.time.current_timestamp();
811
812        assert_eq!(expected_response, actual_response, "erroneous response");
813        assert_eq!(new_time, timestamp_after, "timestamp was not set correctly",);
814    }
815
816    #[tokio::test]
817    async fn test_set_time_same_value() {
818        let node = InMemoryNode::test(None);
819
820        let new_time = 1000u64;
821        let timestamp_before = node.time.current_timestamp();
822        assert_eq!(timestamp_before, new_time, "timestamps must be same");
823        let expected_response = 0;
824
825        let actual_response = node
826            .set_time(new_time)
827            .await
828            .expect("failed setting timestamp");
829        let timestamp_after = node.time.current_timestamp();
830
831        assert_eq!(expected_response, actual_response, "erroneous response");
832        assert_eq!(
833            timestamp_before, timestamp_after,
834            "timestamp must not change",
835        );
836    }
837
838    #[tokio::test]
839    async fn test_set_time_edges() {
840        let node = InMemoryNode::test(None);
841
842        for new_time in [0, u64::MAX] {
843            let timestamp_before = node.time.current_timestamp();
844            assert_ne!(
845                timestamp_before, new_time,
846                "case {new_time}: timestamps must be different"
847            );
848            let expected_response = (new_time as i128).saturating_sub(timestamp_before as i128);
849
850            let actual_response = node
851                .set_time(new_time)
852                .await
853                .expect("failed setting timestamp");
854            let timestamp_after = node.time.current_timestamp();
855
856            assert_eq!(
857                expected_response, actual_response,
858                "case {new_time}: erroneous response"
859            );
860            assert_eq!(
861                new_time, timestamp_after,
862                "case {new_time}: timestamp was not set correctly",
863            );
864        }
865    }
866
867    #[tokio::test]
868    async fn test_mine_block() {
869        let node = InMemoryNode::test(None);
870
871        let start_block = node
872            .get_block_impl(api::BlockId::Number(api::BlockNumber::Latest), false)
873            .await
874            .unwrap()
875            .expect("block exists");
876        let result = node.mine_block().await.expect("mine_block");
877        assert_eq!(result, L2BlockNumber(1));
878
879        let current_block = node
880            .get_block_impl(api::BlockId::Number(api::BlockNumber::Latest), false)
881            .await
882            .unwrap()
883            .expect("block exists");
884
885        assert_eq!(start_block.number + 1, current_block.number);
886        assert_eq!(start_block.timestamp + 1, current_block.timestamp);
887
888        let result = node.mine_block().await.expect("mine_block");
889        assert_eq!(result, L2BlockNumber(start_block.number.as_u32() + 2));
890
891        let current_block = node
892            .get_block_impl(api::BlockId::Number(api::BlockNumber::Latest), false)
893            .await
894            .unwrap()
895            .expect("block exists");
896
897        assert_eq!(start_block.number + 2, current_block.number);
898        assert_eq!(start_block.timestamp + 2, current_block.timestamp);
899    }
900
901    #[tokio::test]
902    async fn test_evm_snapshot_creates_incrementing_ids() {
903        let node = InMemoryNode::test(None);
904
905        let snapshot_id_1 = node.snapshot().await.expect("failed creating snapshot 1");
906        let snapshot_id_2 = node.snapshot().await.expect("failed creating snapshot 2");
907
908        assert_eq!(snapshot_id_1, U64::from(1));
909        assert_eq!(snapshot_id_2, U64::from(2));
910    }
911
912    #[tokio::test]
913    async fn test_evm_revert_snapshot_restores_state() {
914        let node = InMemoryNode::test(None);
915
916        let initial_block = node
917            .get_block_number_impl()
918            .await
919            .expect("failed fetching block number");
920        let snapshot_id = node.snapshot().await.expect("failed creating snapshot");
921        node.mine_block().await.expect("mine_block");
922        let current_block = node
923            .get_block_number_impl()
924            .await
925            .expect("failed fetching block number");
926        assert_eq!(current_block, initial_block + 1);
927
928        let reverted = node
929            .revert_snapshot(snapshot_id)
930            .await
931            .expect("failed reverting snapshot");
932        assert!(reverted);
933
934        let restored_block = node
935            .get_block_number_impl()
936            .await
937            .expect("failed fetching block number");
938        assert_eq!(restored_block, initial_block);
939    }
940
941    #[tokio::test]
942    async fn test_evm_revert_snapshot_removes_all_snapshots_following_the_reverted_one() {
943        let node = InMemoryNode::test(None);
944
945        let _snapshot_id_1 = node.snapshot().await.expect("failed creating snapshot");
946        let snapshot_id_2 = node.snapshot().await.expect("failed creating snapshot");
947        let _snapshot_id_3 = node.snapshot().await.expect("failed creating snapshot");
948        assert_eq!(3, node.snapshots.read().await.len());
949
950        let reverted = node
951            .revert_snapshot(snapshot_id_2)
952            .await
953            .expect("failed reverting snapshot");
954        assert!(reverted);
955
956        assert_eq!(1, node.snapshots.read().await.len());
957    }
958
959    #[tokio::test]
960    async fn test_evm_revert_snapshot_fails_for_invalid_snapshot_id() {
961        let node = InMemoryNode::test(None);
962
963        let result = node.revert_snapshot(U64::from(100)).await;
964        assert!(result.is_err());
965    }
966
967    #[tokio::test]
968    async fn test_node_set_chain_id() {
969        let node = InMemoryNode::test(None);
970        let new_chain_id = 261;
971
972        let _ = node.set_chain_id(new_chain_id).await;
973
974        let node_inner = node.inner.read().await;
975        assert_eq!(new_chain_id, node_inner.config.chain_id.unwrap());
976        assert_eq!(
977            L2ChainId::from(new_chain_id),
978            node_inner.fork_storage.chain_id
979        );
980    }
981}