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
513#[derive(Debug, Clone)]
514pub struct EntryPointFilter {
515 pub protocol_system: ProtocolSystem,
516 pub component_ids: Option<Vec<ComponentId>>,
517}
518
519impl EntryPointFilter {
520 pub fn new(protocol: ProtocolSystem) -> Self {
521 Self { protocol_system: protocol, component_ids: None }
522 }
523
524 pub fn with_component_ids(mut self, component_ids: Vec<ComponentId>) -> Self {
525 self.component_ids = Some(component_ids);
526 self
527 }
528}
529
530// Trait for entry point gateway operations.
531#[async_trait]
532pub trait EntryPointGateway {
533 /// Inserts a list of entry points into the database.
534 ///
535 /// # Arguments
536 /// * `entry_points` - The map of component ids to their entry points to insert.
537 ///
538 /// Note: This function ignores conflicts on inserts.
539 async fn insert_entry_points(
540 &self,
541 entry_points: &HashMap<ComponentId, HashSet<EntryPoint>>,
542 ) -> Result<(), StorageError>;
543
544 /// Inserts a list of entry points with their tracing params into the database.
545 ///
546 /// # Arguments
547 /// * `entry_points_params` - The map of entry points to their tracing params to insert and
548 /// component id for the component linked to the params.
549 ///
550 /// Note: This function ignores conflicts on inserts.
551 async fn insert_entry_point_tracing_params(
552 &self,
553 entry_points_params: &HashMap<EntryPointId, HashSet<(TracingParams, ComponentId)>>,
554 ) -> Result<(), StorageError>;
555
556 /// Retrieves a map of component ids to a set of entry points from the database.
557 ///
558 /// # Arguments
559 /// * `filter` - The EntryPointFilter to apply to the query.
560 /// * `pagination_params` - The pagination parameters to apply to the query, if None, all
561 /// results are returned.
562 ///
563 /// # Returns
564 /// A map of component ids to a set of entry points.
565 async fn get_entry_points(
566 &self,
567 filter: EntryPointFilter,
568 pagination_params: Option<&PaginationParams>,
569 ) -> Result<WithTotal<HashMap<ComponentId, HashSet<EntryPoint>>>, StorageError>;
570
571 /// Retrieves a map of component ids to a set of entry points with their tracing data from the
572 /// database.
573 ///
574 /// # Arguments
575 /// * `filter` - The EntryPointFilter to apply to the query.
576 /// * `pagination_params` - The pagination parameters to apply to the query, if None, all
577 /// results are returned.
578 ///
579 /// # Returns
580 /// A map of component ids to a set of entry points with their tracing params.
581 async fn get_entry_points_tracing_params(
582 &self,
583 filter: EntryPointFilter,
584 pagination_params: Option<&PaginationParams>,
585 ) -> Result<WithTotal<HashMap<ComponentId, HashSet<EntryPointWithTracingParams>>>, StorageError>;
586
587 /// Upserts a list of traced entry points into the database. Updates the result if it already
588 /// exists for the same entry point and tracing params.
589 ///
590 /// # Arguments
591 /// * `traced_entry_points` - The list of traced entry points to upsert.
592 async fn upsert_traced_entry_points(
593 &self,
594 traced_entry_points: &[TracedEntryPoint],
595 ) -> Result<(), StorageError>;
596
597 /// Retrieves all tracing results for a set of entry points from the database.
598 ///
599 /// # Arguments
600 /// * `entry_points` - The set of entry points to retrieve tracing results for.
601 ///
602 /// # Returns
603 /// A map of entry point ids to a map of tracing params to tracing results.
604 async fn get_traced_entry_points(
605 &self,
606 entry_points: &HashSet<EntryPointId>,
607 ) -> Result<HashMap<EntryPointId, HashMap<TracingParams, TracingResult>>, StorageError>;
608}
609
610/// Manage contracts and their state in storage.
611///
612/// Specifies how to retrieve, add and update contracts in storage.
613#[async_trait]
614pub trait ContractStateGateway {
615 /// Get a contracts state from storage
616 ///
617 /// This method retrieves a single contract from the database.
618 ///
619 /// # Parameters
620 /// - `id` The identifier for the contract.
621 /// - `version` Version at which to retrieve state for. None retrieves the latest state.
622 /// - `include_slots`: Flag to determine whether to include slot changes. If set to `true`, it
623 /// includes storage slot.
624 async fn get_contract(
625 &self,
626 id: &ContractId,
627 version: Option<&Version>,
628 include_slots: bool,
629 ) -> Result<Account, StorageError>;
630
631 /// Get multiple contracts' states from storage.
632 ///
633 /// This method retrieves balance and code, and optionally storage, of
634 /// multiple contracts in a chain. It can optionally filter by given
635 /// addresses and retrieve state for specific versions.
636 ///
637 /// # Parameters:
638 /// - `chain`: The blockchain where the contracts reside.
639 /// - `addresses`: Filter for specific addresses. If set to `None`, it retrieves all indexed
640 /// contracts in the chain.
641 /// - `version`: Version at which to retrieve state for. If set to `None`, it retrieves the
642 /// latest state.
643 /// - `include_slots`: Flag to determine whether to include slot changes. If set to `true`, it
644 /// includes storage slot.
645 /// - `pagination_params`: Optional pagination parameters to control the number of results.
646 ///
647 /// # Returns:
648 /// A `Result` with a list of contract states if the operation is
649 /// successful, or a `StorageError` if the operation fails.
650 async fn get_contracts(
651 &self,
652 chain: &Chain,
653 addresses: Option<&[Address]>,
654 version: Option<&Version>,
655 include_slots: bool,
656 pagination_params: Option<&PaginationParams>,
657 ) -> Result<WithTotal<Vec<Account>>, StorageError>;
658
659 /// Inserts a new contract into the database.
660 ///
661 /// Inserts only the static values of the contract. To insert the contract slots, balance and
662 /// code please use the `update_contracts` method.
663 ///
664 /// # Arguments
665 /// - `new`: A reference to the new contract state to be inserted.
666 ///
667 /// # Returns
668 /// - A Result with Ok if the operation was successful, and an Err containing `StorageError` if
669 /// there was an issue inserting the contract into the database. E.g. if the contract already
670 /// existed.
671 async fn insert_contract(&self, new: &Account) -> Result<(), StorageError>;
672
673 /// Update multiple contracts
674 ///
675 /// Given contract deltas, this method will batch all updates to contracts across a single
676 /// chain.
677 ///
678 /// As changes are versioned by transaction, each changeset needs to be associated with a
679 /// transaction hash. All references transaction are assumed to be already persisted.
680 ///
681 /// # Arguments
682 ///
683 /// - `new`: A reference to a slice of tuples where each tuple has a transaction hash (`TxHash`)
684 /// and a reference to the state delta (`&Self::Delta`) for that transaction.
685 ///
686 /// # Returns
687 ///
688 /// A Result with `Ok` if the operation was successful, and an `Err` containing
689 /// `StorageError` if there was an issue updating the contracts in the database. E.g. if a
690 /// transaction can't be located by it's reference or accounts refer to a different chain then
691 /// the one specified.
692 async fn update_contracts(&self, new: &[(TxHash, AccountDelta)]) -> Result<(), StorageError>;
693
694 /// Mark a contract as deleted
695 ///
696 /// Issues a soft delete of the contract.
697 ///
698 /// # Parameters
699 /// - `id` The identifier for the contract.
700 /// - `at_tx` The transaction hash which deleted the contract. This transaction is assumed to be
701 /// in storage already. None retrieves the latest state.
702 ///
703 /// # Returns
704 /// Ok if the deletion was successful, might Err if:
705 /// - Contract is not present in storage.
706 /// - Deletion transaction is not present in storage.
707 /// - Contract was already deleted.
708 async fn delete_contract(&self, id: &ContractId, at_tx: &TxHash) -> Result<(), StorageError>;
709
710 /// Retrieve a account delta between two versions.
711 ///
712 /// Given start version V1 and end version V2, this method will return the
713 /// changes necessary to move from V1 to V2. So if V1 < V2, it will contain
714 /// the changes of all accounts that changed between the two versions with the
715 /// values corresponding to V2. If V2 < V1 then it will contain all the
716 /// slots that changed between the two versions with the values corresponding to V1.
717 ///
718 /// This method is mainly meant to handle reverts, but can also be used to create delta changes
719 /// between two historical version thus providing the basis for creating a backtestable stream
720 /// of messages.
721 ///
722 /// # Parameters
723 ///
724 /// - `chain` The chain for which to generate the delta changes.
725 /// - `start_version` The deltas start version, given a block uses VersionKind::Last behaviour.
726 /// If None the latest version is assumed.
727 /// - `end_version` The deltas end version, given a block uses VersionKind::Last behaviour.
728 ///
729 /// # Note
730 ///
731 /// A choice to utilize `BlockOrTimestamp` has been made intentionally in
732 /// this scenario as passing a `Version` by user isn't quite logical.
733 /// Support for deltas is limited to the states at the start or end of
734 /// blocks because blockchain reorganization at the transaction level is not
735 /// common.
736 ///
737 /// The decision to use either the beginning or end state of a block is
738 /// automatically determined by the underlying logic. For example, if we are
739 /// tracing back, `VersionKind::First` retrieval mode will be used.
740 /// Conversely, if we're progressing forward, we would apply the
741 /// `VersionKind::Last` semantics.
742 ///
743 /// # Returns
744 /// A map containing the necessary changes to update a state from start_version to end_version.
745 /// Errors if:
746 /// - The versions can't be located in storage.
747 /// - There was an error with the database
748 async fn get_accounts_delta(
749 &self,
750 chain: &Chain,
751 start_version: Option<&BlockOrTimestamp>,
752 end_version: &BlockOrTimestamp,
753 ) -> Result<Vec<AccountDelta>, StorageError>;
754
755 /// Saves multiple account balances to storage.
756 ///
757 /// # Parameters
758 /// - `account_balances` The account balances to insert.
759 ///
760 /// # Return
761 /// Ok if all account balances could be inserted, Err if at least one token failed to insert.
762 async fn add_account_balances(
763 &self,
764 account_balances: &[AccountBalance],
765 ) -> Result<(), StorageError>;
766
767 /// Retrieve account balances
768 ///
769 /// # Parameters
770 /// - `chain` The chain of the account balances
771 /// - `accounts` The accounts to query for. If set to `None`, it retrieves balances for all
772 /// indexed
773 /// accounts in the chain.
774 /// - `version` Version at which to retrieve balances for. If set to `None`, it retrieves the
775 /// latest balances.
776 async fn get_account_balances(
777 &self,
778 chain: &Chain,
779 accounts: Option<&[Address]>,
780 version: Option<&Version>,
781 ) -> Result<HashMap<Address, HashMap<Address, AccountBalance>>, StorageError>;
782}
783
784pub trait Gateway:
785 ChainGateway
786 + ContractStateGateway
787 + ExtractionStateGateway
788 + ProtocolGateway
789 + ContractStateGateway
790 + EntryPointGateway
791 + Send
792 + Sync
793{
794}