tycho_common/
storage.rs

1//! Storage traits used by Tycho
2use std::{
3    collections::{HashMap, HashSet},
4    fmt::Display,
5};
6
7use async_trait::async_trait;
8use chrono::NaiveDateTime;
9use thiserror::Error;
10
11use crate::{
12    dto,
13    models::{
14        blockchain::{
15            Block, EntryPoint, EntryPointWithTracingParams, TracedEntryPoint, TracingParams,
16            TracingResult, Transaction,
17        },
18        contract::{Account, AccountBalance, AccountDelta},
19        protocol::{
20            ComponentBalance, ProtocolComponent, ProtocolComponentState,
21            ProtocolComponentStateDelta, QualityRange,
22        },
23        token::Token,
24        Address, BlockHash, Chain, ComponentId, ContractId, EntryPointId, ExtractionState,
25        PaginationParams, ProtocolSystem, ProtocolType, TxHash,
26    },
27    Bytes,
28};
29
30/// Identifies a block in storage.
31#[derive(Debug, Clone, PartialEq, Hash, Eq)]
32pub enum BlockIdentifier {
33    /// Identifies the block by its position on a specified chain.
34    ///
35    /// This form of identification has potential risks as it may become
36    /// ambiguous in certain situations. For example, if the block has not been
37    /// finalised, there exists a possibility of forks occurring. As a result,
38    /// the same number could refer to different blocks on different forks.
39    Number((Chain, i64)),
40
41    /// Identifies a block by its hash.
42    ///
43    /// The hash should be unique across multiple chains. Preferred method if
44    /// the block is very recent.
45    Hash(BlockHash),
46
47    /// Latest stored block for the target chain
48    ///
49    /// Returns the block with the highest block number on the target chain.
50    Latest(Chain),
51}
52
53impl Display for BlockIdentifier {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        write!(f, "{self:?}")
56    }
57}
58
59#[derive(Error, Debug, PartialEq, Clone)]
60pub enum StorageError {
61    #[error("Could not find {0} with id `{1}`!")]
62    NotFound(String, String),
63    #[error("The entity {0} with id {1} was already present!")]
64    DuplicateEntry(String, String),
65    #[error("Could not find related {0} for {1} with id `{2}`!")]
66    NoRelatedEntity(String, String, String),
67    #[error("DecodeError: {0}")]
68    DecodeError(String),
69    #[error("Unexpected storage error: {0}")]
70    Unexpected(String),
71    #[error("Currently unsupported operation: {0}")]
72    Unsupported(String),
73    #[error("Write cache unexpectedly dropped notification channel!")]
74    WriteCacheGoneAway(),
75    #[error("Invalid block range encountered")]
76    InvalidBlockRange(),
77}
78
79/// Storage methods for chain specific objects.
80///
81/// This trait abstracts the specific implementation details of a blockchain's
82/// entities, allowing the user to add and retrieve blocks and transactions in a
83/// generic way.
84///
85/// For traceability protocol components and contracts changes are linked to
86/// blocks of their respective chain if applicable. This means while indexing we
87/// need to keep a lightweight and cross chain compatible representation of
88/// blocks and transactions in storage.
89///
90/// It's defined generically over two associated types:
91///
92/// * `Block`: represents a block in the blockchain.
93/// * `Transaction`: represents a transaction within a block.
94#[async_trait]
95pub trait ChainGateway {
96    /// Upserts a new block to the blockchain's storage.
97    ///
98    /// Ignores any existing tx, if the new entry has different attributes
99    /// no error is raised and the old entry is kept.
100    ///
101    /// # Parameters
102    /// - `new`: An instance of `Self::Block`, representing the new block to be stored.
103    ///
104    /// # Returns
105    /// - Empty ok result indicates success. Failure might occur if the block is already present.
106    async fn upsert_block(&self, new: &[Block]) -> Result<(), StorageError>;
107    /// Retrieves a block from storage.
108    ///
109    /// # Parameters
110    /// - `id`: Block's unique identifier of type `BlockIdentifier`.
111    ///
112    /// # Returns
113    /// - An Ok result containing the block. Might fail if the block does not exist yet.
114    async fn get_block(&self, id: &BlockIdentifier) -> Result<Block, StorageError>;
115    /// Upserts a transaction to storage.
116    ///
117    /// Ignores any existing tx, if the new entry has different attributes
118    /// no error is raised and the old entry is kept.
119    ///
120    /// # Parameters
121    /// - `new`: An instance of `Self::Transaction`, representing the new transaction to be stored.
122    ///
123    /// # Returns
124    /// - Empty ok result indicates success. Failure might occur if the
125    /// corresponding block does not exists yet, or if the transaction already
126    /// exists.
127    async fn upsert_tx(&self, new: &[Transaction]) -> Result<(), StorageError>;
128
129    /// Tries to retrieve a transaction from the blockchain's storage using its
130    /// hash.
131    ///
132    /// # Parameters
133    /// - `hash`: The byte slice representing the hash of the transaction to be retrieved.
134    ///
135    /// # Returns
136    /// - An Ok result containing the transaction. Might fail if the transaction does not exist yet.
137    async fn get_tx(&self, hash: &TxHash) -> Result<Transaction, StorageError>;
138
139    /// Reverts the blockchain storage to a previous version.
140    ///
141    /// Reverting state signifies deleting database history. Only the main branch will be kept.
142    ///
143    /// Blocks that are greater than the provided block (`to`) are deleted and any versioned rows
144    /// which were invalidated in the deleted blocks are updated to be valid again.
145    ///
146    /// # Parameters
147    /// - `to` The version to revert to. Given a block uses VersionKind::Last behaviour.
148    /// - `db` The database gateway.
149    ///
150    /// # Returns
151    /// - An Ok if the revert is successful, or a `StorageError` if not.
152    async fn revert_state(&self, to: &BlockIdentifier) -> Result<(), StorageError>;
153}
154
155/// Store and retrieve state of Extractors.
156///
157/// Sometimes extractors may wish to persist their state across restart. E.g.
158/// substreams based extractors need to store the cursor, so they can continue
159/// processing where they left off.
160///
161/// Extractors are uniquely identified by a name and the respective chain which
162/// they are indexing.
163#[async_trait]
164pub trait ExtractionStateGateway {
165    /// Retrieves the state of an extractor instance from a storage.
166    ///
167    /// # Parameters
168    /// - `name` A unique name for the extractor instance.
169    /// - `chain` The chain this extractor is indexing.
170    ///
171    /// # Returns
172    /// Ok if the corrsponding state was retrieved successfully, Err in
173    /// case the state was not found.
174    async fn get_state(&self, name: &str, chain: &Chain) -> Result<ExtractionState, StorageError>;
175
176    /// Saves the state of an extractor instance to a storage.
177    ///
178    /// Creates an entry if not present yet, or updates an already existing
179    /// entry.
180    ///
181    /// # Parameters
182    /// - `state` The state of the extractor that needs to be saved.
183    ///
184    /// # Returns
185    /// Ok, if state was stored successfully, Err if the state is not valid.
186    async fn save_state(&self, state: &ExtractionState) -> Result<(), StorageError>;
187}
188
189/// Point in time as either block or timestamp. If a block is chosen it
190/// timestamp attribute is used.
191#[derive(Debug, Clone, PartialEq, Hash, Eq)]
192pub enum BlockOrTimestamp {
193    Block(BlockIdentifier),
194    Timestamp(NaiveDateTime),
195}
196
197// TODO: remove once deprecated chain field is removed from VersionParam
198#[allow(deprecated)]
199impl TryFrom<&dto::VersionParam> for BlockOrTimestamp {
200    type Error = anyhow::Error;
201
202    fn try_from(version: &dto::VersionParam) -> Result<Self, Self::Error> {
203        match (&version.timestamp, &version.block) {
204            (_, Some(block)) => {
205                // If a full block is provided, we prioritize hash over number and chain
206                let block_identifier = match (&block.hash, &block.chain, &block.number) {
207                    (Some(hash), _, _) => BlockIdentifier::Hash(hash.clone()),
208                    (_, Some(chain), Some(number)) => {
209                        BlockIdentifier::Number((Chain::from(*chain), *number))
210                    }
211                    _ => {
212                        return Err(anyhow::format_err!("Insufficient block information".to_owned()))
213                    }
214                };
215                Ok(BlockOrTimestamp::Block(block_identifier))
216            }
217            (Some(timestamp), None) => Ok(BlockOrTimestamp::Timestamp(*timestamp)),
218            (None, None) => {
219                Err(anyhow::format_err!("Missing timestamp or block identifier".to_owned()))
220            }
221        }
222    }
223}
224
225/// References certain states within a single block.
226///
227/// **Note:** Not all methods that take a version will support all version kinds,
228/// the versions here are included for completeness and to document the
229/// retrieval behaviour that is possible with the storage layout. Please refer
230/// to the individual implementation for information about which version kinds
231/// it supports.
232#[derive(Debug, Clone, Default)]
233pub enum VersionKind {
234    /// Represents the final state within a specific block. Essentially, it
235    /// retrieves the state subsequent to the execution of the last transaction
236    /// executed in that block.
237    #[default]
238    Last,
239    /// Represents the initial state of a specific block. In other words,
240    /// it is the state before any transaction has been executed within that block.
241    First,
242    /// Represents a specific transactions indexed position within a block.
243    /// It includes the state after executing the transaction at that index.
244    Index(i64),
245}
246
247/// A version desribes the state of the DB at a exact point in time.
248/// See the module level docs for more information on how versioning works.
249#[derive(Debug, Clone)]
250pub struct Version(pub BlockOrTimestamp, pub VersionKind);
251
252impl Version {
253    pub fn from_block_number(chain: Chain, number: i64) -> Self {
254        Self(BlockOrTimestamp::Block(BlockIdentifier::Number((chain, number))), VersionKind::Last)
255    }
256    pub fn from_ts(ts: NaiveDateTime) -> Self {
257        Self(BlockOrTimestamp::Timestamp(ts), VersionKind::Last)
258    }
259}
260
261// Helper type to retrieve entities with their total retrievable count.
262#[derive(Debug)]
263pub struct WithTotal<T> {
264    pub entity: T,
265    pub total: Option<i64>,
266}
267
268/// Store and retrieve protocol related structs.
269///
270/// This trait defines how to retrieve protocol components, state as well as
271/// tokens from storage.
272#[async_trait]
273pub trait ProtocolGateway {
274    /// Retrieve ProtocolComponent from the db
275    ///
276    /// # Parameters
277    /// - `chain` The chain of the component
278    /// - `system` Allows to optionally filter by system.
279    /// - `ids` Allows to optionally filter by id.
280    /// - `min_tvl` Allows to optionally filter by min tvl.
281    /// - `pagination_params` Optional pagination parameters to control the number of results.
282    ///
283    /// # Returns
284    /// Ok, if found else Err
285    async fn get_protocol_components(
286        &self,
287        chain: &Chain,
288        system: Option<String>,
289        ids: Option<&[&str]>,
290        min_tvl: Option<f64>,
291        pagination_params: Option<&PaginationParams>,
292    ) -> Result<WithTotal<Vec<ProtocolComponent>>, StorageError>;
293
294    /// Retrieves owners of tokens
295    ///
296    /// Queries for owners (protocol components) of tokens that have a certain minimum
297    /// balance and returns a maximum aggregate of those in case there are multiple
298    /// owners.
299    ///
300    /// # Parameters
301    /// - `chain` The chain of the component
302    /// - `tokens` The tokens to query for, any component with at least one of these tokens is
303    ///   returned.
304    /// - `min_balance` A minimum balance we expect the component to have on any of the tokens
305    ///   mentioned in `tokens`.
306    async fn get_token_owners(
307        &self,
308        chain: &Chain,
309        tokens: &[Address],
310        min_balance: Option<f64>,
311    ) -> Result<HashMap<Address, (ComponentId, Bytes)>, StorageError>;
312
313    async fn add_protocol_components(&self, new: &[ProtocolComponent]) -> Result<(), StorageError>;
314
315    async fn delete_protocol_components(
316        &self,
317        to_delete: &[ProtocolComponent],
318        block_ts: NaiveDateTime,
319    ) -> Result<(), StorageError>;
320
321    /// Stores new found ProtocolTypes.
322    ///
323    /// # Parameters
324    /// - `new_protocol_types`  The new protocol types.
325    ///
326    /// # Returns
327    /// Ok if stored successfully.
328    async fn add_protocol_types(
329        &self,
330        new_protocol_types: &[ProtocolType],
331    ) -> Result<(), StorageError>;
332
333    /// Retrieve protocol component states
334    ///
335    /// This resource is versioned, the version can be specified by either block
336    /// or timestamp, for off-chain components, a block version will error.
337    ///
338    /// As the state is retained on a transaction basis on blockchain systems, a
339    /// single version may relate to more than one state. In these cases a
340    /// versioned result is returned, if requesting `Version:All` with the
341    /// latest entry being the state at the end of the block and the first entry
342    /// represents the first change to the state within the block.
343    ///
344    /// # Parameters
345    /// - `chain` The chain of the component
346    /// - `at` The version at which the state is valid at.
347    /// - `system` The protocol system this component belongs to
348    /// - `ids` The external ids of the components e.g. addresses, or the pairs
349    /// - `retrieve_balances` Whether to retrieve the balances for the components.
350    /// - `pagination_params` Optional pagination parameters to control the number of results.
351    async fn get_protocol_states(
352        &self,
353        chain: &Chain,
354        at: Option<Version>,
355        system: Option<String>,
356        ids: Option<&[&str]>,
357        retrieve_balances: bool,
358        pagination_params: Option<&PaginationParams>,
359    ) -> Result<WithTotal<Vec<ProtocolComponentState>>, StorageError>;
360
361    async fn update_protocol_states(
362        &self,
363        new: &[(TxHash, ProtocolComponentStateDelta)],
364    ) -> Result<(), StorageError>;
365
366    /// Retrieves a tokens from storage
367    ///
368    /// # Parameters
369    /// - `chain` The chain this token is implemented on.
370    /// - `address` The address for the token within the chain.
371    /// - `quality` The quality of the token.
372    /// - `traded_n_days_ago` The number of days ago the token was traded.
373    /// - `pagination_params` Optional pagination parameters to control the number of results.
374    ///
375    /// # Returns
376    /// Ok if the results could be retrieved from the storage, else errors.
377    async fn get_tokens(
378        &self,
379        chain: Chain,
380        address: Option<&[&Address]>,
381        quality: QualityRange,
382        traded_n_days_ago: Option<NaiveDateTime>,
383        pagination_params: Option<&PaginationParams>,
384    ) -> Result<WithTotal<Vec<Token>>, StorageError>;
385
386    /// Saves multiple component balances to storage.
387    ///
388    /// # Parameters
389    /// - `component_balances` The component balances to insert.
390    ///
391    /// # Return
392    /// Ok if all component balances could be inserted, Err if at least one token failed to
393    /// insert.
394    async fn add_component_balances(
395        &self,
396        component_balances: &[ComponentBalance],
397    ) -> Result<(), StorageError>;
398
399    /// Saves multiple tokens to storage.
400    ///
401    /// Inserts token into storage. Tokens and their properties are assumed to
402    /// be immutable.
403    ///
404    /// # Parameters
405    /// - `tokens` The tokens to insert.
406    ///
407    /// # Return
408    /// Ok if all tokens could be inserted, Err if at least one token failed to
409    /// insert.
410    async fn add_tokens(&self, tokens: &[Token]) -> Result<(), StorageError>;
411
412    /// Updates multiple tokens in storage.
413    ///
414    /// Updates token in storage. Will warn if one of the tokens does not exist in the
415    /// database. Currently assumes that token addresses are unique across chains.
416    ///
417    /// # Parameters
418    /// - `tokens` The tokens to update.
419    ///
420    /// # Return
421    /// Ok if all tokens could be inserted, Err if at least one token failed to
422    /// insert.
423    async fn update_tokens(&self, tokens: &[Token]) -> Result<(), StorageError>;
424
425    /// Retrieve protocol state changes
426    ///
427    /// Fetches all state changes that occurred for the given chain
428    ///
429    /// # Parameters
430    /// - `chain` The chain of the component
431    /// - `start_version` The version at which to start looking for changes at.
432    /// - `end_version` The version at which to stop looking for changes.
433    ///
434    /// # Return
435    /// A list of ProtocolStateDeltas containing all state changes, Err if no changes were found.
436    async fn get_protocol_states_delta(
437        &self,
438        chain: &Chain,
439        start_version: Option<&BlockOrTimestamp>,
440        end_version: &BlockOrTimestamp,
441    ) -> Result<Vec<ProtocolComponentStateDelta>, StorageError>;
442
443    /// Retrieve protocol component balance changes
444    ///
445    /// Fetches all balance changes that occurred for the given protocol system
446    ///
447    /// # Parameters
448    /// - `chain` The chain of the component
449    /// - `start_version` The version at which to start looking for changes at.
450    /// - `target_version` The version at which to stop looking for changes.
451    ///
452    /// # Return
453    /// A vec containing ComponentBalance objects for changed components.
454    async fn get_balance_deltas(
455        &self,
456        chain: &Chain,
457        start_version: Option<&BlockOrTimestamp>,
458        target_version: &BlockOrTimestamp,
459    ) -> Result<Vec<ComponentBalance>, StorageError>;
460
461    async fn get_component_balances(
462        &self,
463        chain: &Chain,
464        ids: Option<&[&str]>,
465        version: Option<&Version>,
466    ) -> Result<HashMap<String, HashMap<Bytes, ComponentBalance>>, StorageError>;
467
468    async fn get_token_prices(&self, chain: &Chain) -> Result<HashMap<Bytes, f64>, StorageError>;
469
470    async fn upsert_component_tvl(
471        &self,
472        chain: &Chain,
473        tvl_values: &HashMap<String, f64>,
474    ) -> Result<(), StorageError>;
475
476    /// Retrieve a list of actively supported protocol systems
477    ///
478    /// Fetches the list of protocol systems supported by the Tycho indexing service.
479    ///
480    /// # Parameters
481    /// - `chain` The chain for which to retrieve supported protocol systems.
482    /// - `pagination_params` Optional pagination parameters to control the number of results.
483    ///
484    /// # Return
485    /// A paginated list of supported protocol systems, along with the total count.
486    async fn get_protocol_systems(
487        &self,
488        chain: &Chain,
489        pagination_params: Option<&PaginationParams>,
490    ) -> Result<WithTotal<Vec<String>>, StorageError>;
491
492    /// Retrieve the components total value locked (TVL).
493    ///
494    /// # Parameters
495    /// - `chain` The chain for which to retrieve the total value locked
496    /// - `system` The protocol system for which to retrieve the total value locked
497    /// - `ids` The ids of the components to retrieve the total value locked for
498    /// - `pagination_params` Optional pagination parameters to control the number of results.
499    ///
500    /// # Return
501    /// A result with a map of component ids to their TVL. Err if storage access failed.
502    async fn get_component_tvls(
503        &self,
504        chain: &Chain,
505        system: Option<String>,
506        ids: Option<&[&str]>,
507        pagination_params: Option<&PaginationParams>,
508    ) -> Result<WithTotal<HashMap<String, f64>>, StorageError>;
509}
510
511/// Filters for entry points queries in the database.
512// Shalow but can be used to add more filters without breaking backwards compatibility in the future
513pub struct EntryPointFilter {
514    pub protocol_system: ProtocolSystem,
515    pub component_ids: Option<Vec<ComponentId>>,
516}
517
518impl EntryPointFilter {
519    pub fn new(protocol: ProtocolSystem) -> Self {
520        Self { protocol_system: protocol, component_ids: None }
521    }
522
523    pub fn with_component_ids(mut self, component_ids: Vec<ComponentId>) -> Self {
524        self.component_ids = Some(component_ids);
525        self
526    }
527}
528
529// Trait for entry point gateway operations.
530#[async_trait]
531pub trait EntryPointGateway {
532    /// Inserts a list of entry points into the database.
533    ///
534    /// # Arguments
535    /// * `entry_points` - The map of component ids to their entry points to insert.
536    ///
537    /// Note: This function ignores conflicts on inserts.
538    async fn insert_entry_points(
539        &self,
540        entry_points: &HashMap<ComponentId, HashSet<EntryPoint>>,
541    ) -> Result<(), StorageError>;
542
543    /// Inserts a list of entry points with their tracing params into the database.
544    ///
545    /// # Arguments
546    /// * `entry_points_params` - The map of entry points to their tracing params to insert and
547    ///   optionally a component id used for debugging only.
548    ///
549    /// Note: This function ignores conflicts on inserts.
550    async fn insert_entry_point_tracing_params(
551        &self,
552        entry_points_params: &HashMap<EntryPointId, HashSet<(TracingParams, Option<ComponentId>)>>,
553    ) -> Result<(), StorageError>;
554
555    /// Retrieves a map of component ids to a set of entry points from the database.
556    ///
557    /// # Arguments
558    /// * `filter` - The EntryPointFilter to apply to the query.
559    /// * `pagination_params` - The pagination parameters to apply to the query, if None, all
560    ///   results are returned.
561    ///
562    /// # Returns
563    /// A map of component ids to a set of entry points.
564    async fn get_entry_points(
565        &self,
566        filter: EntryPointFilter,
567        pagination_params: Option<&PaginationParams>,
568    ) -> Result<WithTotal<HashMap<ComponentId, HashSet<EntryPoint>>>, StorageError>;
569
570    /// Retrieves a map of component ids to a set of entry points with their tracing data from the
571    /// database.
572    ///
573    /// # Arguments
574    /// * `filter` - The EntryPointFilter to apply to the query.
575    /// * `pagination_params` - The pagination parameters to apply to the query, if None, all
576    ///   results are returned.
577    ///
578    /// # Returns
579    /// A map of component ids to a set of entry points with their tracing params.
580    async fn get_entry_points_tracing_params(
581        &self,
582        filter: EntryPointFilter,
583        pagination_params: Option<&PaginationParams>,
584    ) -> Result<WithTotal<HashMap<ComponentId, HashSet<EntryPointWithTracingParams>>>, StorageError>;
585
586    /// Upserts a list of traced entry points into the database. Updates the result if it already
587    /// exists for the same entry point and tracing params.
588    ///
589    /// # Arguments
590    /// * `traced_entry_points` - The list of traced entry points to upsert.
591    async fn upsert_traced_entry_points(
592        &self,
593        traced_entry_points: &[TracedEntryPoint],
594    ) -> Result<(), StorageError>;
595
596    /// Retrieves all tracing results for a set of entry points from the database.
597    ///
598    /// # Arguments
599    /// * `entry_points` - The set of entry points to retrieve tracing results for.
600    ///
601    /// # Returns
602    /// A map of entry point ids to a map of tracing params to tracing results.
603    async fn get_traced_entry_points(
604        &self,
605        entry_points: &HashSet<EntryPointId>,
606    ) -> Result<HashMap<EntryPointId, HashMap<TracingParams, TracingResult>>, StorageError>;
607}
608
609/// Manage contracts and their state in storage.
610///
611/// Specifies how to retrieve, add and update contracts in storage.
612#[async_trait]
613pub trait ContractStateGateway {
614    /// Get a contracts state from storage
615    ///
616    /// This method retrieves a single contract from the database.
617    ///
618    /// # Parameters
619    /// - `id` The identifier for the contract.
620    /// - `version` Version at which to retrieve state for. None retrieves the latest state.
621    /// - `include_slots`: Flag to determine whether to include slot changes. If set to `true`, it
622    ///   includes storage slot.
623    async fn get_contract(
624        &self,
625        id: &ContractId,
626        version: Option<&Version>,
627        include_slots: bool,
628    ) -> Result<Account, StorageError>;
629
630    /// Get multiple contracts' states from storage.
631    ///
632    /// This method retrieves balance and code, and optionally storage, of
633    /// multiple contracts in a chain. It can optionally filter by given
634    /// addresses and retrieve state for specific versions.
635    ///
636    /// # Parameters:
637    /// - `chain`: The blockchain where the contracts reside.
638    /// - `addresses`: Filter for specific addresses. If set to `None`, it retrieves all indexed
639    ///   contracts in the chain.
640    /// - `version`: Version at which to retrieve state for. If set to `None`, it retrieves the
641    ///   latest state.
642    /// - `include_slots`: Flag to determine whether to include slot changes. If set to `true`, it
643    ///   includes storage slot.
644    /// - `pagination_params`: Optional pagination parameters to control the number of results.
645    ///
646    /// # Returns:
647    /// A `Result` with a list of contract states if the operation is
648    /// successful, or a `StorageError` if the operation fails.
649    async fn get_contracts(
650        &self,
651        chain: &Chain,
652        addresses: Option<&[Address]>,
653        version: Option<&Version>,
654        include_slots: bool,
655        pagination_params: Option<&PaginationParams>,
656    ) -> Result<WithTotal<Vec<Account>>, StorageError>;
657
658    /// Inserts a new contract into the database.
659    ///
660    /// Inserts only the static values of the contract. To insert the contract slots, balance and
661    /// code please use the `update_contracts` method.
662    ///
663    /// # Arguments
664    /// - `new`: A reference to the new contract state to be inserted.
665    ///
666    /// # Returns
667    /// - A Result with Ok if the operation was successful, and an Err containing `StorageError` if
668    ///   there was an issue inserting the contract into the database. E.g. if the contract already
669    ///   existed.
670    async fn insert_contract(&self, new: &Account) -> Result<(), StorageError>;
671
672    /// Update multiple contracts
673    ///
674    /// Given contract deltas, this method will batch all updates to contracts across a single
675    /// chain.
676    ///
677    /// As changes are versioned by transaction, each changeset needs to be associated with a
678    /// transaction hash. All references transaction are assumed to be already persisted.
679    ///
680    /// # Arguments
681    ///
682    /// - `new`: A reference to a slice of tuples where each tuple has a transaction hash (`TxHash`)
683    ///   and a reference to the state delta (`&Self::Delta`) for that transaction.
684    ///
685    /// # Returns
686    ///
687    /// A Result with `Ok` if the operation was successful, and an `Err` containing
688    /// `StorageError` if there was an issue updating the contracts in the database. E.g. if a
689    /// transaction can't be located by it's reference or accounts refer to a different chain then
690    /// the one specified.
691    async fn update_contracts(&self, new: &[(TxHash, AccountDelta)]) -> Result<(), StorageError>;
692
693    /// Mark a contract as deleted
694    ///
695    /// Issues a soft delete of the contract.
696    ///
697    /// # Parameters
698    /// - `id` The identifier for the contract.
699    /// - `at_tx` The transaction hash which deleted the contract. This transaction is assumed to be
700    ///   in storage already. None retrieves the latest state.
701    ///
702    /// # Returns
703    /// Ok if the deletion was successful, might Err if:
704    ///  - Contract is not present in storage.
705    ///  - Deletion transaction is not present in storage.
706    ///  - Contract was already deleted.
707    async fn delete_contract(&self, id: &ContractId, at_tx: &TxHash) -> Result<(), StorageError>;
708
709    /// Retrieve a account delta between two versions.
710    ///
711    /// Given start version V1 and end version V2, this method will return the
712    /// changes necessary to move from V1 to V2. So if V1 < V2, it will contain
713    /// the changes of all accounts that changed between the two versions with the
714    /// values corresponding to V2. If V2 < V1 then it will contain all the
715    /// slots that changed between the two versions with the values corresponding to V1.
716    ///
717    /// This method is mainly meant to handle reverts, but can also be used to create delta changes
718    /// between two historical version thus providing the basis for creating a backtestable stream
719    /// of messages.
720    ///
721    /// # Parameters
722    ///
723    /// - `chain` The chain for which to generate the delta changes.
724    /// - `start_version` The deltas start version, given a block uses VersionKind::Last behaviour.
725    ///   If None the latest version is assumed.
726    /// - `end_version` The deltas end version, given a block uses VersionKind::Last behaviour.
727    ///
728    /// # Note
729    ///
730    /// A choice to utilize `BlockOrTimestamp` has been made intentionally in
731    /// this scenario as passing a `Version` by user isn't quite logical.
732    /// Support for deltas is limited to the states at the start or end of
733    /// blocks because blockchain reorganization at the transaction level is not
734    /// common.
735    ///
736    /// The decision to use either the beginning or end state of a block is
737    /// automatically determined by the underlying logic. For example, if we are
738    /// tracing back, `VersionKind::First` retrieval mode will be used.
739    /// Conversely, if we're progressing forward, we would apply the
740    /// `VersionKind::Last` semantics.
741    ///
742    /// # Returns
743    /// A map containing the necessary changes to update a state from start_version to end_version.
744    /// Errors if:
745    ///     - The versions can't be located in storage.
746    ///     - There was an error with the database
747    async fn get_accounts_delta(
748        &self,
749        chain: &Chain,
750        start_version: Option<&BlockOrTimestamp>,
751        end_version: &BlockOrTimestamp,
752    ) -> Result<Vec<AccountDelta>, StorageError>;
753
754    /// Saves multiple account balances to storage.
755    ///
756    /// # Parameters
757    /// - `account_balances` The account balances to insert.
758    ///
759    /// # Return
760    /// Ok if all account balances could be inserted, Err if at least one token failed to insert.
761    async fn add_account_balances(
762        &self,
763        account_balances: &[AccountBalance],
764    ) -> Result<(), StorageError>;
765
766    /// Retrieve account balances
767    ///
768    /// # Parameters
769    /// - `chain` The chain of the account balances
770    /// - `accounts` The accounts to query for. If set to `None`, it retrieves balances for all
771    ///   indexed
772    ///  accounts in the chain.
773    /// - `version` Version at which to retrieve balances for. If set to `None`, it retrieves the
774    ///   latest balances.
775    async fn get_account_balances(
776        &self,
777        chain: &Chain,
778        accounts: Option<&[Address]>,
779        version: Option<&Version>,
780    ) -> Result<HashMap<Address, HashMap<Address, AccountBalance>>, StorageError>;
781}
782
783pub trait Gateway:
784    ChainGateway
785    + ContractStateGateway
786    + ExtractionStateGateway
787    + ProtocolGateway
788    + ContractStateGateway
789    + EntryPointGateway
790    + Send
791    + Sync
792{
793}