diff --git a/bin/sozo/src/commands/migrate.rs b/bin/sozo/src/commands/migrate.rs index ebc37ae0c2..30331257d3 100644 --- a/bin/sozo/src/commands/migrate.rs +++ b/bin/sozo/src/commands/migrate.rs @@ -1,7 +1,9 @@ -use anyhow::{Context, Result}; +use std::sync::Arc; + +use anyhow::{anyhow, Context, Result}; use clap::Args; use colored::*; -use dojo_utils::{self, TxnConfig}; +use dojo_utils::{self, provider as provider_utils, TxnConfig}; use dojo_world::contracts::WorldContract; use dojo_world::services::IpfsService; use scarb::core::{Config, Workspace}; @@ -12,13 +14,14 @@ use starknet::core::utils::parse_cairo_short_string; use starknet::providers::Provider; use tabled::settings::Style; use tabled::{Table, Tabled}; -use tracing::trace; +use tracing::{error, trace}; use super::options::account::AccountOptions; use super::options::ipfs::IpfsOptions; use super::options::starknet::StarknetOptions; use super::options::transaction::TransactionOptions; use super::options::world::WorldOptions; +use crate::commands::LOG_TARGET; use crate::utils; #[derive(Debug, Clone, Args)] @@ -141,6 +144,12 @@ async fn print_banner(ws: &Workspace<'_>, starknet: &StarknetOptions) -> Result< let profile_config = ws.load_profile_config()?; let (provider, rpc_url) = starknet.provider(profile_config.env.as_ref())?; + let provider = Arc::new(provider); + if let Err(e) = provider_utils::health_check_provider(provider.clone()).await { + error!(target: LOG_TARGET,"Provider health check failed during sozo migrate."); + return Err(e); + } + let provider = Arc::try_unwrap(provider).map_err(|_| anyhow!("Failed to unwrap Arc"))?; let chain_id = provider.chain_id().await?; let chain_id = parse_cairo_short_string(&chain_id).with_context(|| "Cannot parse chain_id as string")?; diff --git a/bin/sozo/src/commands/mod.rs b/bin/sozo/src/commands/mod.rs index 6ee218b2da..9ca42277f3 100644 --- a/bin/sozo/src/commands/mod.rs +++ b/bin/sozo/src/commands/mod.rs @@ -34,6 +34,8 @@ use migrate::MigrateArgs; use model::ModelArgs; use test::TestArgs; +pub(crate) const LOG_TARGET: &str = "sozo::cli"; + #[derive(Debug, Subcommand)] pub enum Commands { #[command(about = "Grant or revoke a contract permission to write to a resource")] diff --git a/bin/sozo/src/utils.rs b/bin/sozo/src/utils.rs index cc108a55cc..818b5ad7ec 100644 --- a/bin/sozo/src/utils.rs +++ b/bin/sozo/src/utils.rs @@ -1,10 +1,12 @@ use std::collections::HashMap; use std::io::{self, Write}; use std::str::FromStr; +use std::sync::Arc; use anyhow::{anyhow, Context, Result}; use camino::Utf8PathBuf; use colored::*; +use dojo_utils::provider as provider_utils; use dojo_world::config::ProfileConfig; use dojo_world::contracts::ContractInfo; use dojo_world::diff::WorldDiff; @@ -19,11 +21,12 @@ use starknet::core::types::Felt; use starknet::core::utils as snutils; use starknet::providers::jsonrpc::HttpTransport; use starknet::providers::{JsonRpcClient, Provider}; -use tracing::trace; +use tracing::{error, trace}; use crate::commands::options::account::{AccountOptions, SozoAccount}; use crate::commands::options::starknet::StarknetOptions; use crate::commands::options::world::WorldOptions; +use crate::commands::LOG_TARGET; /// Computes the world address based on the provided options. pub fn get_world_address( @@ -113,6 +116,12 @@ pub async fn get_world_diff_and_provider( let world_address = get_world_address(&profile_config, &world, &world_local)?; let (provider, rpc_url) = starknet.provider(env)?; + let provider = Arc::new(provider); + if let Err(e) = provider_utils::health_check_provider(provider.clone()).await { + error!(target: LOG_TARGET,"Provider health check failed during sozo inspect."); + return Err(e); + } + let provider = Arc::try_unwrap(provider).map_err(|_| anyhow!("Failed to unwrap Arc"))?; trace!(?provider, "Provider initialized."); let spec_version = provider.spec_version().await?; diff --git a/crates/dojo/utils/src/lib.rs b/crates/dojo/utils/src/lib.rs index 96524d1805..71435ba34c 100644 --- a/crates/dojo/utils/src/lib.rs +++ b/crates/dojo/utils/src/lib.rs @@ -12,5 +12,5 @@ pub use tx::*; pub mod env; pub mod keystore; - +pub mod provider; pub mod signal; diff --git a/crates/dojo/utils/src/provider.rs b/crates/dojo/utils/src/provider.rs new file mode 100644 index 0000000000..9e7eadfd6a --- /dev/null +++ b/crates/dojo/utils/src/provider.rs @@ -0,0 +1,26 @@ +use starknet::core::types::{BlockId, BlockTag}; +use starknet::providers::Provider; +use tracing::trace; + +/// Check if the provider is healthy. +/// +/// This function will check if the provider is healthy by getting the latest block, +/// and returns an error otherwise. +pub async fn health_check_provider( + provider: P, +) -> anyhow::Result<(), anyhow::Error> { + match provider.get_block_with_tx_hashes(BlockId::Tag(BlockTag::Latest)).await { + Ok(block) => { + trace!( + latest_block = ?block, + "Provider health check." + ); + Ok(()) + } + Err(_) => { + let error_info = + format!("Unhealthy provider {:?}, please check your configuration.", provider); + Err(anyhow::anyhow!(error_info)) + } + } +} diff --git a/crates/torii/core/Cargo.toml b/crates/torii/core/Cargo.toml index 09b25d8cca..b9c90fa17e 100644 --- a/crates/torii/core/Cargo.toml +++ b/crates/torii/core/Cargo.toml @@ -18,6 +18,7 @@ chrono.workspace = true crypto-bigint.workspace = true data-url.workspace = true dojo-types.workspace = true +dojo-utils.workspace = true dojo-world.workspace = true futures-channel = "0.3.0" futures-util.workspace = true diff --git a/crates/torii/core/src/engine.rs b/crates/torii/core/src/engine.rs index f5b483f6e2..a51b593844 100644 --- a/crates/torii/core/src/engine.rs +++ b/crates/torii/core/src/engine.rs @@ -6,6 +6,7 @@ use std::time::Duration; use anyhow::Result; use bitflags::bitflags; +use dojo_utils::provider as provider_utils; use dojo_world::contracts::world::WorldContractReader; use futures_util::future::{join_all, try_join_all}; use hashlink::LinkedHashMap; @@ -45,7 +46,6 @@ use crate::processors::{ }; use crate::sql::{Cursors, Sql}; use crate::types::{Contract, ContractType}; -use crate::utils::health_check_provider; type EventProcessorMap

= HashMap>>>; @@ -253,7 +253,7 @@ impl Engine

{ } pub async fn start(&mut self) -> Result<()> { - if let Err(e) = health_check_provider(self.provider.clone()).await { + if let Err(e) = provider_utils::health_check_provider(self.provider.clone()).await { error!(target: LOG_TARGET,"Provider health check failed during engine start"); return Err(e); } diff --git a/crates/torii/core/src/utils.rs b/crates/torii/core/src/utils.rs index 27f68f62d8..a0f0fac94c 100644 --- a/crates/torii/core/src/utils.rs +++ b/crates/torii/core/src/utils.rs @@ -4,10 +4,8 @@ use anyhow::Result; use chrono::{DateTime, Utc}; use futures_util::TryStreamExt; use ipfs_api_backend_hyper::{IpfsApi, IpfsClient, TryFromUri}; -use starknet::core::types::{BlockId, BlockTag}; -use starknet::providers::Provider; use tokio_util::bytes::Bytes; -use tracing::{info, trace}; +use tracing::info; use crate::constants::{ IPFS_CLIENT_MAX_RETRY, IPFS_CLIENT_PASSWORD, IPFS_CLIENT_URL, IPFS_CLIENT_USERNAME, @@ -48,25 +46,6 @@ pub async fn fetch_content_from_ipfs(cid: &str, mut retries: u8) -> Result( - provider: P, -) -> Result<(), anyhow::Error> { - match provider.get_block_with_tx_hashes(BlockId::Tag(BlockTag::Latest)).await { - Ok(block) => { - trace!( - latest_block = ?block, - "Provider health check." - ); - Ok(()) - } - Err(_) => { - let error_info = - format!("Unhealthy provider {:?}, please check your configuration.", provider); - Err(anyhow::anyhow!(error_info)) - } - } -} - // tests #[cfg(test)] mod tests {