diff --git a/Cargo.lock b/Cargo.lock index 1423c6f9e..07a9c8959 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,7 +294,9 @@ dependencies = [ name = "ark-storage" version = "0.1.0" dependencies = [ + "log", "num-bigint", + "serde", "starknet", ] diff --git a/crates/ark-core/src/lib.rs b/crates/ark-core/src/lib.rs index 59d11320e..b3c617c49 100644 --- a/crates/ark-core/src/lib.rs +++ b/crates/ark-core/src/lib.rs @@ -3,8 +3,8 @@ mod managers; use anyhow::Result; use ark_starknet::client::{StarknetClient, StarknetClientHttp}; use ark_storage::storage_manager::StorageManager; +use ark_storage::types::ContractType; use dotenv::dotenv; -use managers::collection_manager::ContractType; use managers::{BlockManager, CollectionManager, EventManager, TokenManager}; use starknet::core::types::*; use std::env; diff --git a/crates/ark-core/src/managers/block_manager.rs b/crates/ark-core/src/managers/block_manager.rs index f4f3dc4e5..ef969fd98 100644 --- a/crates/ark-core/src/managers/block_manager.rs +++ b/crates/ark-core/src/managers/block_manager.rs @@ -1,5 +1,6 @@ use ark_starknet::client::StarknetClient; use ark_storage::storage_manager::StorageManager; +use ark_storage::types::{BlockIndexingStatus, BlockInfo}; use starknet::core::types::*; use std::env; @@ -11,20 +12,6 @@ pub struct BlockManager<'a, T: StorageManager, C: StarknetClient> { indexer_version: u64, } -// TODO: this struct must come from Storage crate. -#[derive(Debug, PartialEq)] -pub enum BlockIndexingStatus { - None, - Processing, - Terminated, -} - -// TODO: this struct must come from Storage crate. -pub struct BlockInfo { - pub indexer_version: u64, - pub status: BlockIndexingStatus, -} - impl<'a, T: StorageManager, C: StarknetClient> BlockManager<'a, T, C> { pub fn new(storage: &'a T, client: &'a C) -> Self { let v: &u64 = &env::var("INDEXER_VERSION") @@ -69,28 +56,43 @@ impl<'a, T: StorageManager, C: StarknetClient> BlockManager<'a, T, C> { .unwrap_or(false); if *do_force { - log::debug!("Block #{} forced", block_number); - // TODO: self.storage.clean_block(block_number); + match self.storage.clean_block(block_number) { + Ok(_) => log::debug!("Block cleaned successfully!"), + Err(e) => log::debug!("Error cleaning block: {:?}", e), + } return true; } - // TODO: self.storage.get_block_info(...); - let info = BlockInfo { - indexer_version: 0, - status: BlockIndexingStatus::None, + let info = match self.storage.get_block_info(block_number) { + Ok(block_info) => { + log::debug!("Retrieved block info: {:?}", block_info); + Some(block_info) // Assign the value of block_info to `info` + } + Err(e) => { + log::debug!("Error retrieving block info: {:?}", e); + None // Assigns None to `info` in case of error + } }; - if info.status == BlockIndexingStatus::None { - return true; - } + // Use the retrieved info to determine some actions + if let Some(actual_info) = info { + if actual_info.status == BlockIndexingStatus::None { + return true; + } - if info.indexer_version > self.indexer_version { - log::debug!("Block #{} new version", block_number); - // TODO: self.storage.clean_block(block_number); - return true; + if actual_info.indexer_version > self.indexer_version { + log::debug!("Block #{} new version", block_number); + match self.storage.clean_block(block_number) { + Ok(_) => log::debug!("Block cleaned successfully!"), + Err(e) => log::debug!("Error cleaning block: {:?}", e), + } + return true; + } + } else { + log::debug!("Info is not available for the block."); } - log::debug!("Block #{} not candidate", block_number); + // If no conditions are met, return false or whatever default you want false } } diff --git a/crates/ark-core/src/managers/collection_manager.rs b/crates/ark-core/src/managers/collection_manager.rs index 570a7992e..bcfabb54c 100644 --- a/crates/ark-core/src/managers/collection_manager.rs +++ b/crates/ark-core/src/managers/collection_manager.rs @@ -1,39 +1,12 @@ use anyhow::{anyhow, Result}; use ark_starknet::client::StarknetClient; use ark_storage::storage_manager::StorageManager; - -use serde::{Deserialize, Serialize}; +use ark_storage::types::StorageError; +use ark_storage::types::{ContractInfo, ContractType}; use starknet::core::types::{BlockId, BlockTag, FieldElement}; use starknet::core::utils::{get_selector_from_name, parse_cairo_short_string}; - use std::collections::HashMap; -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "snake_case")] -pub enum ContractType { - Other, - ERC721, - ERC1155, -} - -impl ToString for ContractType { - fn to_string(&self) -> String { - match self { - ContractType::Other => "other".to_string(), - ContractType::ERC721 => "erc721".to_string(), - ContractType::ERC1155 => "erc1155".to_string(), - } - } -} - -// TODO: this struct must come from Storage crate. -#[derive(Debug, Clone)] -pub struct ContractInfo { - pub name: String, - pub symbol: String, - pub r#type: ContractType, -} - pub struct CollectionManager<'a, T: StorageManager, C: StarknetClient> { storage: &'a T, client: &'a C, @@ -52,18 +25,20 @@ impl<'a, T: StorageManager, C: StarknetClient> CollectionManager<'a, T, C> { } /// Gets the contract info from local cache, or fetch is from the DB. - fn get_cached_or_fetch_info(&mut self, address: FieldElement) -> Result { - match self.cache.get(&address) { - Some(info) => Ok(info.clone()), - None => { - log::trace!("Cache miss for contract {address}"); - // TODO: self.storage.get_contract_info(); - // If no info available -> return error. - // For now, return error to simulate it's not available. - Err(anyhow!("Info not found in storage for contract {address}")) - } + fn get_cached_or_fetch_info(&mut self, address: FieldElement) -> Result { + if let Some(info) = self.cache.get(&address) { + return Ok(info.clone()); } + + log::trace!("Cache miss for contract {}", address); + + let info = self.storage.get_contract_info(&address)?; + + self.cache.insert(address, info.clone()); // Adding to the cache + + Ok(info) } + /// Identifies a contract from it's address only. pub async fn identify_contract(&mut self, address: FieldElement) -> Result { @@ -87,7 +62,11 @@ impl<'a, T: StorageManager, C: StarknetClient> CollectionManager<'a, T, C> { }; self.cache.insert(address, info.clone()); - // TODO: self.storage.register_contract_info(...); + + match self.storage.register_contract_info(&address, &info) { + Ok(_) => log::debug!("Contract info registered successfully!"), + Err(e) => log::debug!("Error registering contract info: {:?}", e), + } Ok(info) } diff --git a/crates/ark-core/src/managers/event_manager.rs b/crates/ark-core/src/managers/event_manager.rs index 467ef8c66..693dbbc75 100644 --- a/crates/ark-core/src/managers/event_manager.rs +++ b/crates/ark-core/src/managers/event_manager.rs @@ -57,10 +57,11 @@ impl<'a, T: StorageManager, C: StarknetClient> EventManager<'a, T, C> { let (from, to, token_id) = event_info; // TODO: why do we need this entry 2 times for the felt and the string? + // TODO move that to storage + // self.token_event.from_address = format!("{:#064x}", from); + // self.token_event.to_address = format!("{:#064x}", to); self.token_event.from_address_field_element = from; - self.token_event.from_address = format!("{:#064x}", from); self.token_event.to_address_field_element = to; - self.token_event.to_address = format!("{:#064x}", to); self.token_event.contract_address = format!("{:#064x}", event.from_address); self.token_event.transaction_hash = format!("{:#064x}", event.transaction_hash); self.token_event.token_id = token_id.clone(); @@ -72,7 +73,10 @@ impl<'a, T: StorageManager, C: StarknetClient> EventManager<'a, T, C> { info!("Event identified: {:?}", self.token_event.event_type); - // TODO: self.storage.register_event(self.token_event); + match self.storage.register_event(&self.token_event) { + Ok(_) => log::debug!("Event registered successfully!"), + Err(e) => log::debug!("Error registering event: {:?}", e), + } // TODO: check depending on event type if it's a create/update etc...? Ok(self.token_event.clone()) diff --git a/crates/ark-core/src/managers/token_manager.rs b/crates/ark-core/src/managers/token_manager.rs index b9fe3f4bf..1d5d1fb4c 100644 --- a/crates/ark-core/src/managers/token_manager.rs +++ b/crates/ark-core/src/managers/token_manager.rs @@ -63,7 +63,17 @@ impl<'a, T: StorageManager, C: StarknetClient> TokenManager<'a, T, C> { event.contract_address ); - // TODO: self.storage.register_token(self.token.clone()).await?; + match self.storage.register_token(&self.token) { + Ok(_) => log::debug!("Token registered successfully!"), + Err(e) => log::debug!("Error registering token: {:?}", e), + } + + if event.event_type == EventType::Mint { + match self.storage.register_mint(&self.token) { + Ok(_) => log::debug!("Mint registered successfully!"), + Err(e) => log::debug!("Error registering mint: {:?}", e), + } + } Ok(()) } diff --git a/crates/ark-storage/Cargo.toml b/crates/ark-storage/Cargo.toml index bd2e3d8e1..810e5d6c3 100644 --- a/crates/ark-storage/Cargo.toml +++ b/crates/ark-storage/Cargo.toml @@ -5,4 +5,6 @@ edition = "2021" [dependencies] starknet = "0.5.0" -num-bigint = { version = "0.4.3", default-features = false } \ No newline at end of file +num-bigint = { version = "0.4.3", default-features = false } +serde = { version = "1.0.130", features = ["derive"] } +log = "0.4.14" \ No newline at end of file diff --git a/crates/ark-storage/src/storage_manager.rs b/crates/ark-storage/src/storage_manager.rs index 903c5e93e..7b8b37134 100644 --- a/crates/ark-storage/src/storage_manager.rs +++ b/crates/ark-storage/src/storage_manager.rs @@ -1,17 +1,37 @@ -use crate::types::{TokenEvent, TokenFromEvent}; +use crate::types::{ + BlockIndexing, BlockIndexingStatus, BlockInfo, ContractInfo, StorageError, + TokenEvent, TokenFromEvent, +}; +use log; +use starknet::core::types::FieldElement; pub trait StorageManager { - // Store a new token in the storage - fn create_token(&self, token: &TokenFromEvent); + fn register_mint(&self, token: &TokenFromEvent) -> Result<(), StorageError>; - // Update an existing token's owner in the storage - fn update_token_owner(&self, token: &TokenFromEvent, new_owner: &str); + fn register_token(&self, token: &TokenFromEvent) -> Result<(), StorageError>; - // Log or store a token-related event - fn create_event(&self, event: &TokenEvent); + fn clean_block(&self, block_number: u64) -> Result<(), StorageError>; + + fn get_block_info(&self, block_number: u64) -> Result; + + fn get_contract_info( + &self, + contract_address: &FieldElement, + ) -> Result; + + fn register_contract_info( + &self, + contract_address: &FieldElement, + info: &ContractInfo, + ) -> Result<(), StorageError>; + + fn register_event(&self, event: &TokenEvent) -> Result<(), StorageError>; + + fn set_block_info(&self, block_number: u64, info: BlockInfo) -> Result<(), StorageError>; + + fn set_indexer_progress(&self, progress: BlockIndexing) -> Result<(), StorageError>; } -// Default implementation (Logging for this example) pub struct DefaultStorage; impl DefaultStorage { @@ -21,18 +41,83 @@ impl DefaultStorage { } impl StorageManager for DefaultStorage { - fn create_event(&self, event: &TokenEvent) { - println!("STORAGE MANAGER: Event created: {:?}", event); + fn register_token(&self, token: &TokenFromEvent) -> Result<(), StorageError> { + log::debug!("Registering token {:?}", token); + // TODO: In future, handle and return potential errors + // Err(StorageError::DuplicateToken) + Ok(()) + } + + fn register_mint(&self, token: &TokenFromEvent) -> Result<(), StorageError> { + log::debug!("Registering mint {:?}", token); + // TODO: In future, handle and return potential errors + // Err(StorageError::InvalidMintData) + Ok(()) + } + + fn clean_block(&self, block_number: u64) -> Result<(), StorageError> { + log::debug!("Cleaning block #{}", block_number); + // TODO: In future, handle and return potential errors + // Err(StorageError::DatabaseError) + Ok(()) + } + + fn get_block_info(&self, block_number: u64) -> Result { + log::debug!("Getting block info for block #{}", block_number); + // TODO: In future, handle and return potential errors + // Err(StorageError::NotFound) + Ok(BlockInfo { + indexer_version: 0, + indexer_indentifier: "42".to_string(), + status: BlockIndexingStatus::None, + }) + } + + fn get_contract_info( + &self, + contract_address: &FieldElement, + ) -> Result { + log::debug!("Getting contract info for contract {}", contract_address); + // TODO: In future, handle and return potential errors + Err(StorageError::NotFound) + } + + fn register_contract_info( + &self, + contract_address: &FieldElement, + info: &ContractInfo, + ) -> Result<(), StorageError> { + log::debug!( + "Registering contract info {:?} for contract {}", + info, + contract_address + ); + // TODO: In future, handle and return potential errors + // Err(StorageError::DuplicateToken) + Ok(()) + } + + fn register_event(&self, event: &TokenEvent) -> Result<(), StorageError> { + log::debug!("Registering event {:?}", event); + // TODO: In future, handle and return potential errors + // Err(StorageError::DatabaseError) + Ok(()) } - fn create_token(&self, token: &TokenFromEvent) { - println!("STORAGE MANAGER: Token created: {:?}", token); + fn set_block_info(&self, block_number: u64, info: BlockInfo) -> Result<(), StorageError> { + log::debug!("Setting block info {:?} for block #{}", info, block_number); + // TODO: In future, handle and return potential errors + // Err(StorageError::DatabaseError) + Ok(()) } - fn update_token_owner(&self, token: &TokenFromEvent, new_owner: &str) { - println!( - "STORAGE MANAGER: Token updated. Previous Owner: {}, New Owner: {}", - token.owner, new_owner + fn set_indexer_progress(&self, indexer_progress: BlockIndexing) -> Result<(), StorageError> { + log::debug!( + "Setting indexer progress to block #{}", + indexer_progress.percentage ); + // TODO: In future, handle and return potential errors + // Err(StorageError::DatabaseError) + Ok(()) } } diff --git a/crates/ark-storage/src/types.rs b/crates/ark-storage/src/types.rs index 9e170218e..5c97bc1a8 100644 --- a/crates/ark-storage/src/types.rs +++ b/crates/ark-storage/src/types.rs @@ -1,7 +1,16 @@ use crate::utils::format_token_id; use num_bigint::BigUint; +use serde::{Deserialize, Serialize}; use starknet::core::types::FieldElement; +#[derive(Debug)] +pub enum StorageError { + DatabaseError, + NotFound, + DuplicateToken, + InvalidMintData, +} + #[derive(Debug, PartialEq, Clone)] pub enum EventType { Mint, @@ -119,3 +128,60 @@ impl TokenId { } } } + +#[derive(Debug, PartialEq)] +pub enum BlockIndexingStatus { + None, + Processing, + Terminated, +} + +pub enum IndexerStatus { + Running, + Stopped, +} + +pub struct Range { + pub start: u64, + pub end: u64, +} + +pub struct BlockIndexing { + pub range: Range, + pub percentage: u64, + pub status: IndexerStatus, + pub indentifier: String, + pub indexer_version: u64, +} + +#[derive(Debug)] +pub struct BlockInfo { + pub indexer_version: u64, + pub indexer_indentifier: String, + pub status: BlockIndexingStatus, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ContractType { + Other, + ERC721, + ERC1155, +} + +impl ToString for ContractType { + fn to_string(&self) -> String { + match self { + ContractType::Other => "other".to_string(), + ContractType::ERC721 => "erc721".to_string(), + ContractType::ERC1155 => "erc1155".to_string(), + } + } +} + +#[derive(Debug, Clone)] +pub struct ContractInfo { + pub name: String, + pub symbol: String, + pub r#type: ContractType, +}