Skip to main content

tycho_simulation/evm/engine_db/
tycho_db.rs

1use std::{
2    collections::HashMap,
3    sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
4};
5
6use alloy::primitives::{Address, Bytes as AlloyBytes, B256, U256};
7use revm::{
8    context::DBErrorMarker,
9    primitives::KECCAK_EMPTY,
10    state::{AccountInfo, Bytecode},
11    DatabaseRef,
12};
13use thiserror::Error;
14use tracing::{debug, error, instrument, warn};
15use tycho_client::feed::BlockHeader;
16
17use crate::evm::{
18    account_storage::{AccountStorage, StateUpdate},
19    engine_db::engine_db_interface::EngineDatabaseInterface,
20    tycho_models::{AccountUpdate, ChangeType},
21};
22
23#[derive(Error, Debug)]
24pub enum TychoClientError {
25    #[error("Failed to parse URI: {0}. Error: {1}")]
26    UriParsing(String, String),
27    #[error("Failed to format request: {0}")]
28    FormatRequest(String),
29    #[error("Unexpected HTTP client error: {0}")]
30    HttpClient(String),
31    #[error("Failed to parse response: {0}")]
32    ParseResponse(String),
33}
34
35#[derive(Error, Debug)]
36pub enum PreCachedDBError {
37    #[error("Account {0} not found")]
38    MissingAccount(Address),
39    #[error("Bad account update: {0} - {1:?}")]
40    BadUpdate(String, Box<AccountUpdate>),
41    #[error("Block needs to be set")]
42    BlockNotSet(),
43    #[error("Tycho Client error: {0}")]
44    TychoClientError(#[from] TychoClientError),
45    #[error("{0}")]
46    Fatal(String),
47}
48
49impl DBErrorMarker for PreCachedDBError {}
50
51#[derive(Clone, Debug)]
52pub struct PreCachedDBInner {
53    /// Storage for accounts
54    accounts: AccountStorage,
55    /// Current block
56    block: Option<BlockHeader>,
57}
58
59#[derive(Clone, Debug)]
60pub struct PreCachedDB {
61    /// Cached inner data
62    ///
63    /// `inner` encapsulates `PreCachedDBInner` using `RwLock` for safe concurrent read or
64    /// exclusive write access to the data and `Arc` for shared ownership of the lock across
65    /// threads.
66    pub inner: Arc<RwLock<PreCachedDBInner>>,
67}
68
69impl PreCachedDB {
70    /// Create a new PreCachedDB instance
71    pub fn new() -> Result<Self, PreCachedDBError> {
72        Ok(PreCachedDB {
73            inner: Arc::new(RwLock::new(PreCachedDBInner {
74                accounts: AccountStorage::new(),
75                block: None,
76            })),
77        })
78    }
79
80    #[instrument(skip_all)]
81    pub fn update(
82        &self,
83        account_updates: Vec<AccountUpdate>,
84        block: Option<BlockHeader>,
85    ) -> Result<(), PreCachedDBError> {
86        // Hold the write lock for the duration of the function so that no other thread can
87        // write to the storage.
88        let mut write_guard = self.write_inner()?;
89
90        write_guard.block = block;
91
92        for update in account_updates {
93            match update.change {
94                ChangeType::Update => {
95                    debug!(%update.address, "Updating account");
96
97                    // If the account is not present, the internal storage will handle throwing
98                    // an exception.
99                    write_guard.accounts.update_account(
100                        &update.address,
101                        &StateUpdate {
102                            storage: Some(update.slots.clone()),
103                            balance: update.balance,
104                        },
105                    );
106                }
107                ChangeType::Deletion => {
108                    debug!(%update.address, "Deleting account");
109
110                    warn!(%update.address, "Deletion not implemented");
111                }
112                ChangeType::Creation => {
113                    debug!(%update.address, "Creating account");
114
115                    // We expect the code to be present.
116                    let code = Bytecode::new_raw(AlloyBytes::from(
117                        update.code.clone().ok_or_else(|| {
118                            error!(%update.address, "MissingCode");
119                            PreCachedDBError::BadUpdate(
120                                "MissingCode".into(),
121                                Box::new(update.clone()),
122                            )
123                        })?,
124                    ));
125                    // If the balance is not present, we set it to zero.
126                    let balance = update.balance.unwrap_or(U256::ZERO);
127
128                    // Initialize the account.
129                    write_guard.accounts.init_account(
130                        update.address,
131                        AccountInfo::new(balance, 0, code.hash_slow(), code),
132                        Some(update.slots.clone()),
133                        true, /* Flag all accounts in TychoDB mocked to sign that we cannot
134                               * call an RPC provider for an update */
135                    );
136                }
137                ChangeType::Unspecified => {
138                    warn!(%update.address, "Unspecified change type");
139                }
140            }
141        }
142        Ok(())
143    }
144
145    /// Like [`update()`](Self::update) but unconditionally overwrites existing accounts on
146    /// `Creation` updates.
147    ///
148    /// Use only for authoritative proxy-token accounts that must win over placeholder entries
149    /// inserted by other decoders' snapshot loops. Generic callers should use
150    /// [`update()`](Self::update).
151    pub fn force_update_accounts(
152        &self,
153        account_updates: Vec<AccountUpdate>,
154    ) -> Result<(), PreCachedDBError> {
155        let mut write_guard = self.write_inner()?;
156
157        for update in account_updates {
158            if matches!(update.change, ChangeType::Creation) {
159                let code =
160                    Bytecode::new_raw(AlloyBytes::from(update.code.clone().ok_or_else(|| {
161                        error!(%update.address, "MissingCode");
162                        PreCachedDBError::BadUpdate("MissingCode".into(), Box::new(update.clone()))
163                    })?));
164                let balance = update.balance.unwrap_or(U256::ZERO);
165
166                write_guard.accounts.overwrite_account(
167                    update.address,
168                    AccountInfo::new(balance, 0, code.hash_slow(), code),
169                    Some(update.slots.clone()),
170                    true,
171                );
172            } else {
173                warn!(%update.address, "force_update_accounts called with non-Creation update; ignoring");
174            }
175        }
176        Ok(())
177    }
178
179    /// Retrieves the storage value at the specified index for the given account, if it exists.
180    ///
181    /// If the account exists in the storage, the storage value at the specified `index` is returned
182    /// as a reference. Temp storage takes priority over permanent storage.
183    /// If the account does not exist, `None` is returned.
184    ///
185    /// # Arguments
186    ///
187    /// * `address`: A reference to the address of the account to retrieve the storage value from.
188    /// * `index`: A reference to the index of the storage value to retrieve.
189    ///
190    /// # Returns
191    ///
192    /// Returns an `Option` containing a reference to the storage value if it exists, otherwise
193    /// returns `None`.
194    pub fn get_storage(&self, address: &Address, index: &U256) -> Option<U256> {
195        self.inner
196            .read()
197            .unwrap()
198            .accounts
199            .get_storage(address, index)
200    }
201
202    /// Update the simulation state.
203    ///
204    /// This method modifies the current state of the simulation by applying the provided updates to
205    /// the accounts in the smart contract storage. These changes correspond to a particular
206    /// block in the blockchain.
207    ///
208    /// # Arguments
209    ///
210    /// * `new_state`: A struct containing all the state changes for a particular block.
211    pub fn update_state(
212        &mut self,
213        updates: &HashMap<Address, StateUpdate>,
214        block: BlockHeader,
215    ) -> Result<HashMap<Address, StateUpdate>, PreCachedDBError> {
216        // Hold the write lock for the duration of the function so that no other thread can
217        // write to the storage.
218        let mut write_guard = self.write_inner()?;
219
220        let mut revert_updates = HashMap::new();
221        write_guard.block = Some(block);
222
223        for (address, update_info) in updates.iter() {
224            let mut revert_entry = StateUpdate::default();
225
226            if let Some(current_account) = write_guard
227                .accounts
228                .get_account_info(address)
229            {
230                revert_entry.balance = Some(current_account.balance);
231            }
232
233            if let Some(storage) = &update_info.storage {
234                let mut revert_storage = HashMap::default();
235                for index in storage.keys() {
236                    if let Some(s) = write_guard
237                        .accounts
238                        .get_storage(address, index)
239                    {
240                        revert_storage.insert(*index, s);
241                    }
242                }
243                revert_entry.storage = Some(revert_storage);
244            }
245            revert_updates.insert(*address, revert_entry);
246            write_guard
247                .accounts
248                .update_account(address, update_info);
249        }
250
251        Ok(revert_updates)
252    }
253
254    #[cfg(test)]
255    pub fn get_account_storage(&self) -> Result<AccountStorage, PreCachedDBError> {
256        self.read_inner()
257            .map(|guard| guard.accounts.clone())
258    }
259
260    /// If block is set, returns the number. Otherwise returns None.
261    pub fn block_number(&self) -> Result<Option<u64>, PreCachedDBError> {
262        self.read_inner().map(|guard| {
263            guard
264                .block
265                .as_ref()
266                .map(|header| header.number)
267        })
268    }
269
270    /// Clear all state from the database.
271    pub fn clear(&self) -> Result<(), PreCachedDBError> {
272        let mut write_guard = self.write_inner()?;
273        write_guard.accounts.clear();
274        write_guard.block = None;
275        Ok(())
276    }
277
278    fn read_inner(&self) -> Result<RwLockReadGuard<'_, PreCachedDBInner>, PreCachedDBError> {
279        self.inner
280            .read()
281            .map_err(|_| PreCachedDBError::Fatal("Tycho state db lock poisoned".into()))
282    }
283
284    fn write_inner(&self) -> Result<RwLockWriteGuard<'_, PreCachedDBInner>, PreCachedDBError> {
285        self.inner
286            .write()
287            .map_err(|_| PreCachedDBError::Fatal("Tycho state db lock poisoned".into()))
288    }
289}
290
291impl EngineDatabaseInterface for PreCachedDB {
292    type Error = PreCachedDBError;
293
294    /// Sets up a single account
295    ///
296    /// Full control over setting up an accounts. Allows to set up EOAs as well as smart contracts.
297    ///
298    /// # Arguments
299    ///
300    /// * `address` - Address of the account
301    /// * `account` - The account information
302    /// * `permanent_storage` - Storage to init the account with, this storage can only be updated
303    ///   manually
304    fn init_account(
305        &self,
306        address: Address,
307        account: AccountInfo,
308        permanent_storage: Option<HashMap<U256, U256>>,
309        _mocked: bool,
310    ) -> Result<(), <Self as EngineDatabaseInterface>::Error> {
311        if account.code.is_none() && account.code_hash != KECCAK_EMPTY {
312            warn!("Code is None for account {address} but code hash is not KECCAK_EMPTY");
313        } else if account.code.is_some() && account.code_hash == KECCAK_EMPTY {
314            warn!("Code is Some for account {address} but code hash is KECCAK_EMPTY");
315        }
316
317        self.write_inner()?
318            .accounts
319            .init_account(address, account, permanent_storage, true);
320
321        Ok(())
322    }
323
324    /// Deprecated in TychoDB
325    fn clear_temp_storage(&mut self) -> Result<(), <Self as EngineDatabaseInterface>::Error> {
326        debug!("Temp storage in TychoDB is never set, nothing to clear");
327
328        Ok(())
329    }
330
331    fn get_current_block(&self) -> Option<BlockHeader> {
332        self.inner.read().unwrap().block.clone()
333    }
334}
335
336impl DatabaseRef for PreCachedDB {
337    type Error = PreCachedDBError;
338    /// Retrieves basic information about an account.
339    ///
340    /// This function retrieves the basic account information for the specified address.
341    ///
342    /// # Arguments
343    ///
344    /// * `address`: The address of the account to retrieve the information for.
345    ///
346    /// # Returns
347    ///
348    /// Returns a `Result` containing the account information or an error if the account is not
349    /// found.
350    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
351        self.read_inner()?
352            .accounts
353            .get_account_info(&address)
354            .map(|acc| Some(acc.clone()))
355            .ok_or(PreCachedDBError::MissingAccount(address))
356    }
357
358    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
359        Err(PreCachedDBError::Fatal(format!("Code by hash not supported: {code_hash}")))
360    }
361
362    /// Retrieves the storage value at the specified address and index.
363    ///
364    /// # Arguments
365    ///
366    /// * `address`: The address of the contract to retrieve the storage value from.
367    /// * `index`: The index of the storage value to retrieve.
368    ///
369    /// # Returns
370    ///
371    /// Returns a `Result` containing the storage value if it exists.
372    ///
373    /// # Errors
374    ///
375    /// Returns an error if the storage value is not found.
376    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
377        debug!(%address, %index, "Requested storage of account");
378        let read_guard = self.read_inner()?;
379        if let Some(storage_value) = read_guard
380            .accounts
381            .get_storage(&address, &index)
382        {
383            debug!(%address, %index, %storage_value, "Got value locally");
384            Ok(storage_value)
385        } else {
386            // At this point we either don't know this address or we don't have anything at this
387            if read_guard
388                .accounts
389                .account_present(&address)
390            {
391                // As we only store non-zero values, if the account is present it means this
392                // slot is zero.
393                debug!(%address, %index, "Account found, but slot is zero");
394                Ok(U256::ZERO)
395            } else {
396                // At this point we know we don't have data for this address.
397                debug!(%address, %index, "Account not found");
398                Err(PreCachedDBError::MissingAccount(address))
399            }
400        }
401    }
402
403    /// If block header is set, returns the hash. Otherwise, returns a zero hash.
404    fn block_hash_ref(&self, _number: u64) -> Result<B256, Self::Error> {
405        match self.read_inner()?.block.clone() {
406            Some(header) => Ok(B256::from_slice(&header.hash)),
407            None => Ok(B256::default()),
408        }
409    }
410}
411
412#[cfg(test)]
413mod tests {
414    use std::{error::Error, str::FromStr};
415
416    use revm::primitives::U256;
417    use rstest::{fixture, rstest};
418    use tycho_common::Bytes;
419
420    use super::*;
421    use crate::evm::tycho_models::{AccountUpdate, Chain, ChangeType};
422
423    #[fixture]
424    pub fn mock_db() -> PreCachedDB {
425        PreCachedDB {
426            inner: Arc::new(RwLock::new(PreCachedDBInner {
427                accounts: AccountStorage::new(),
428                block: None,
429            })),
430        }
431    }
432
433    #[rstest]
434    #[tokio::test]
435    async fn test_account_get_acc_info(mock_db: PreCachedDB) -> Result<(), Box<dyn Error>> {
436        // Tests if the provider has not been queried.
437        // Querying the mocked provider would cause a panic, therefore no assert is needed.
438        let mock_acc_address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?;
439        mock_db
440            .init_account(mock_acc_address, AccountInfo::default(), None, false)
441            .expect("Account init should succeed");
442
443        let acc_info = mock_db
444            .basic_ref(mock_acc_address)
445            .unwrap()
446            .unwrap();
447
448        assert_eq!(
449            mock_db
450                .basic_ref(mock_acc_address)
451                .unwrap()
452                .unwrap(),
453            acc_info
454        );
455        Ok(())
456    }
457
458    #[rstest]
459    fn test_account_storage(mock_db: PreCachedDB) -> Result<(), Box<dyn Error>> {
460        let mock_acc_address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?;
461        let storage_address = U256::from(1);
462        let mut permanent_storage: HashMap<U256, U256> = HashMap::new();
463        permanent_storage.insert(storage_address, U256::from(10));
464        mock_db
465            .init_account(mock_acc_address, AccountInfo::default(), Some(permanent_storage), false)
466            .expect("Account init should succeed");
467
468        let storage = mock_db
469            .storage_ref(mock_acc_address, storage_address)
470            .unwrap();
471
472        assert_eq!(storage, U256::from(10));
473        Ok(())
474    }
475
476    #[rstest]
477    fn test_account_storage_zero(mock_db: PreCachedDB) -> Result<(), Box<dyn Error>> {
478        let mock_acc_address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?;
479        let storage_address = U256::from(1);
480        mock_db
481            .init_account(mock_acc_address, AccountInfo::default(), None, false)
482            .expect("Account init should succeed");
483
484        let storage = mock_db
485            .storage_ref(mock_acc_address, storage_address)
486            .unwrap();
487
488        assert_eq!(storage, U256::ZERO);
489        Ok(())
490    }
491
492    #[rstest]
493    #[should_panic(
494        expected = "called `Result::unwrap()` on an `Err` value: MissingAccount(0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc)"
495    )]
496    fn test_account_storage_missing(mock_db: PreCachedDB) {
497        let mock_acc_address =
498            Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
499        let storage_address = U256::from(1);
500
501        // This will panic because this account isn't initialized
502        mock_db
503            .storage_ref(mock_acc_address, storage_address)
504            .unwrap();
505    }
506
507    #[rstest]
508    #[tokio::test]
509    async fn test_update_state(mut mock_db: PreCachedDB) -> Result<(), Box<dyn Error>> {
510        let address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?;
511        mock_db
512            .init_account(address, AccountInfo::default(), None, false)
513            .expect("Account init should succeed");
514
515        let mut new_storage = HashMap::default();
516        let new_storage_value_index = U256::from_limbs_slice(&[123]);
517        new_storage.insert(new_storage_value_index, new_storage_value_index);
518        let new_balance = U256::from_limbs_slice(&[500]);
519        let update = StateUpdate { storage: Some(new_storage), balance: Some(new_balance) };
520        let new_block = BlockHeader {
521            number: 1,
522            hash: Bytes::from_str(
523                "0xc6b994ec855fb2b31013c7ae65074406fac46679b5b963469104e0bfeddd66d9",
524            )
525            .unwrap(),
526            timestamp: 123,
527            ..Default::default()
528        };
529        let mut updates = HashMap::default();
530        updates.insert(address, update);
531
532        mock_db
533            .update_state(&updates, new_block)
534            .expect("State update should succeed");
535
536        assert_eq!(
537            mock_db
538                .get_storage(&address, &new_storage_value_index)
539                .unwrap(),
540            new_storage_value_index
541        );
542        let account_info = mock_db
543            .basic_ref(address)
544            .unwrap()
545            .unwrap();
546        assert_eq!(account_info.balance, new_balance);
547        let block = mock_db
548            .inner
549            .read()
550            .unwrap()
551            .block
552            .clone()
553            .expect("block is Some");
554        assert_eq!(block.number, 1);
555
556        Ok(())
557    }
558
559    #[rstest]
560    #[tokio::test]
561    async fn test_block_number_getter(mut mock_db: PreCachedDB) -> Result<(), Box<dyn Error>> {
562        let address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?;
563        mock_db
564            .init_account(address, AccountInfo::default(), None, false)
565            .expect("Account init should succeed");
566
567        let new_block = BlockHeader {
568            number: 1,
569            hash: Bytes::from_str(
570                "0xc6b994ec855fb2b31013c7ae65074406fac46679b5b963469104e0bfeddd66d9",
571            )
572            .unwrap(),
573            timestamp: 123,
574            ..Default::default()
575        };
576        let updates = HashMap::default();
577
578        mock_db
579            .update_state(&updates, new_block)
580            .expect("State update should succeed");
581
582        let block_number = mock_db.block_number();
583        assert_eq!(block_number.unwrap().unwrap(), 1);
584
585        Ok(())
586    }
587
588    #[rstest]
589    #[tokio::test]
590    async fn test_update() {
591        let mock_db = PreCachedDB {
592            inner: Arc::new(RwLock::new(PreCachedDBInner {
593                accounts: AccountStorage::new(),
594                block: None,
595            })),
596        };
597
598        let account_update = AccountUpdate::new(
599            Address::from_str("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D").unwrap(),
600            Chain::Ethereum,
601            HashMap::new(),
602            Some(U256::from(500)),
603            Some(Vec::<u8>::new()),
604            ChangeType::Creation,
605        );
606
607        let new_block = BlockHeader {
608            number: 1,
609            hash: Bytes::from_str(
610                "0xc6b994ec855fb2b31013c7ae65074406fac46679b5b963469104e0bfeddd66d9",
611            )
612            .unwrap(),
613            timestamp: 123,
614            ..Default::default()
615        };
616
617        mock_db
618            .update(vec![account_update], Some(new_block))
619            .unwrap();
620
621        let account_info = mock_db
622            .basic_ref(Address::from_str("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D").unwrap())
623            .unwrap()
624            .unwrap();
625
626        assert_eq!(
627            account_info,
628            AccountInfo {
629                nonce: 0,
630                balance: U256::from(500),
631                code_hash: B256::from_str(
632                    "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
633                )
634                .unwrap(),
635                code: Some(Bytecode::default()),
636            }
637        );
638
639        assert_eq!(
640            mock_db
641                .inner
642                .read()
643                .unwrap()
644                .block
645                .clone()
646                .expect("block is Some")
647                .number,
648            1
649        );
650    }
651
652    #[rstest]
653    fn test_force_update_accounts_overwrites_existing(mock_db: PreCachedDB) {
654        let address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
655
656        // Simulate a placeholder proxy inserted by another decoder's snapshot loop.
657        mock_db
658            .init_account(address, AccountInfo::default(), None, true)
659            .expect("placeholder init should succeed");
660
661        // Now force-overwrite with the real proxy (authoritative vm_storage data).
662        let storage_slot = U256::from(1);
663        let storage_value = U256::from(42);
664        let mut slots = HashMap::new();
665        slots.insert(storage_slot, storage_value);
666        let update = AccountUpdate::new(
667            address,
668            Chain::Ethereum,
669            slots,
670            Some(U256::from(100)),
671            Some(Vec::<u8>::new()),
672            ChangeType::Creation,
673        );
674        mock_db
675            .force_update_accounts(vec![update])
676            .expect("force update should succeed");
677
678        let info = mock_db
679            .basic_ref(address)
680            .unwrap()
681            .unwrap();
682        assert_eq!(info.balance, U256::from(100));
683        assert_eq!(
684            mock_db
685                .get_storage(&address, &storage_slot)
686                .unwrap(),
687            storage_value
688        );
689    }
690
691    #[rstest]
692    fn test_force_update_accounts_non_creation_ignored(mock_db: PreCachedDB) {
693        let address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
694        let original_balance = U256::from(10);
695
696        mock_db
697            .init_account(
698                address,
699                AccountInfo { balance: original_balance, ..Default::default() },
700                None,
701                true,
702            )
703            .expect("init should succeed");
704
705        // A non-Creation update should be ignored by force_update_accounts.
706        let update = AccountUpdate::new(
707            address,
708            Chain::Ethereum,
709            HashMap::new(),
710            Some(U256::from(999)),
711            None,
712            ChangeType::Update,
713        );
714        mock_db
715            .force_update_accounts(vec![update])
716            .expect("force update should succeed");
717
718        // Balance must remain unchanged.
719        let info = mock_db
720            .basic_ref(address)
721            .unwrap()
722            .unwrap();
723        assert_eq!(info.balance, original_balance);
724    }
725
726    /// This test requires a running TychoDB instance.
727    ///
728    /// To run this test, start TychoDB with the following command:
729    /// ```bash
730    /// cargo run --release -- \
731    //     --endpoint https://mainnet.eth.streamingfast.io:443 \
732    //     --module map_changes \
733    //     --spkg substreams/ethereum-ambient/substreams-ethereum-ambient-v0.3.0.spkg
734    /// ```
735    /// 
736    /// Then run the test with:
737    /// ```bash
738    /// cargo test --package src --lib -- --ignored --exact --nocapture
739    /// evm::engine_db::tycho_db::tests::test_tycho_db_connection
740    /// ```
741    #[ignore]
742    #[rstest]
743    fn test_tycho_db_connection() {
744        tracing_subscriber::fmt()
745            .with_env_filter("debug")
746            .init();
747
748        let ambient_contract =
749            Address::from_str("0xaaaaaaaaa24eeeb8d57d431224f73832bc34f688").unwrap();
750
751        let db = PreCachedDB::new().expect("db should initialize");
752
753        let acc_info = db
754            .basic_ref(ambient_contract)
755            .unwrap()
756            .unwrap();
757
758        debug!(?acc_info, "Account info");
759    }
760}