Skip to content

Commit

Permalink
fix(sozo): use Provider trait and avoid manifest read when possible (
Browse files Browse the repository at this point in the history
…#2197)

* fix: avoid reading manifest when possible for sozo model commands

* fix: use Provider trait instead of JsonRpcProvider + add tests

* fix: fmt and clippy

* fix: ensure scarb manifest is not read on valid tag
  • Loading branch information
glihm authored Jul 20, 2024
1 parent 8f3cbab commit 8a1a652
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 45 deletions.
29 changes: 15 additions & 14 deletions bin/sozo/src/commands/model.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use anyhow::Result;
use clap::{Args, Subcommand};
use dojo_world::contracts::naming::ensure_namespace;
use dojo_world::metadata::get_default_namespace_from_ws;
use scarb::core::Config;
use sozo_ops::model;
use starknet::core::types::Felt;
Expand Down Expand Up @@ -111,46 +109,49 @@ hashes, called 'hash' in the following documentation.
impl ModelArgs {
pub fn run(self, config: &Config) -> Result<()> {
trace!(args = ?self);
let ws = scarb::ops::read_workspace(config.manifest_path(), config)?;
let env_metadata = utils::load_metadata_from_config(config)?;
let default_namespace = get_default_namespace_from_ws(&ws)?;

config.tokio_handle().block_on(async {
match self.command {
ModelCommand::ClassHash { tag_or_name, starknet, world } => {
let tag = ensure_namespace(&tag_or_name, &default_namespace);
let tag = model::check_tag_or_read_default_namespace(&tag_or_name, config)?;

let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_class_hash(tag, world_address, provider).await
model::model_class_hash(tag, world_address, &provider).await?;
Ok(())
}
ModelCommand::ContractAddress { tag_or_name, starknet, world } => {
let tag = ensure_namespace(&tag_or_name, &default_namespace);
let tag = model::check_tag_or_read_default_namespace(&tag_or_name, config)?;

let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_contract_address(tag, world_address, provider).await
model::model_contract_address(tag, world_address, &provider).await?;
Ok(())
}
ModelCommand::Layout { tag_or_name, starknet, world } => {
let tag = ensure_namespace(&tag_or_name, &default_namespace);
let tag = model::check_tag_or_read_default_namespace(&tag_or_name, config)?;

let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_layout(tag, world_address, provider).await
model::model_layout(tag, world_address, provider).await?;
Ok(())
}
ModelCommand::Schema { tag_or_name, to_json, starknet, world } => {
let tag = ensure_namespace(&tag_or_name, &default_namespace);
let tag = model::check_tag_or_read_default_namespace(&tag_or_name, config)?;

let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_schema(tag, world_address, provider, to_json).await
model::model_schema(tag, world_address, provider, to_json).await?;
Ok(())
}
ModelCommand::Get { tag_or_name, keys, starknet, world } => {
let tag = ensure_namespace(&tag_or_name, &default_namespace);
let tag = model::check_tag_or_read_default_namespace(&tag_or_name, config)?;

let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_get(tag, keys, world_address, provider).await
model::model_get(tag, keys, world_address, provider).await?;
Ok(())
}
}
})
Expand Down
87 changes: 56 additions & 31 deletions crates/sozo/ops/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,55 @@
use anyhow::Result;
use cainome::cairo_serde::{ByteArray, CairoSerde};
use dojo_types::schema::Ty;
use dojo_world::contracts::abi::model::Layout;
use dojo_world::contracts::model::ModelReader;
use dojo_world::contracts::naming;
use dojo_world::contracts::world::WorldContractReader;
use dojo_world::metadata::get_default_namespace_from_ws;
use num_traits::ToPrimitive;
use scarb::core::Config;
use starknet::core::types::{BlockId, BlockTag, Felt};
use starknet::core::utils::get_selector_from_name;
use starknet::providers::jsonrpc::HttpTransport;
use starknet::providers::JsonRpcClient;
use starknet::providers::Provider;

const INDENT: &str = " ";

pub async fn model_class_hash(
tag: String,
world_address: Felt,
provider: JsonRpcClient<HttpTransport>,
) -> Result<()> {
let mut world_reader = WorldContractReader::new(world_address, &provider);
pub async fn model_class_hash<P>(tag: String, world_address: Felt, provider: P) -> Result<Felt>
where
P: Provider + Send + Sync,
{
let mut world_reader = WorldContractReader::new(world_address, provider);
world_reader.set_block(BlockId::Tag(BlockTag::Pending));

let model = world_reader.model_reader_with_tag(&tag).await?;

println!("{:#x}", model.class_hash());

Ok(())
Ok(model.class_hash())
}

pub async fn model_contract_address(
pub async fn model_contract_address<P>(
tag: String,
world_address: Felt,
provider: JsonRpcClient<HttpTransport>,
) -> Result<()> {
let mut world_reader = WorldContractReader::new(world_address, &provider);
provider: P,
) -> Result<Felt>
where
P: Provider + Send + Sync,
{
let mut world_reader = WorldContractReader::new(world_address, provider);
world_reader.set_block(BlockId::Tag(BlockTag::Pending));

let model = world_reader.model_reader_with_tag(&tag).await?;

println!("{:#x}", model.contract_address());

Ok(())
Ok(model.contract_address())
}

pub async fn model_layout(
tag: String,
world_address: Felt,
provider: JsonRpcClient<HttpTransport>,
) -> Result<()> {
pub async fn model_layout<P>(tag: String, world_address: Felt, provider: P) -> Result<Layout>
where
P: Provider + Send + Sync,
{
let mut world_reader = WorldContractReader::new(world_address, &provider);
world_reader.set_block(BlockId::Tag(BlockTag::Pending));

Expand All @@ -61,15 +65,18 @@ pub async fn model_layout(

deep_print_layout(&tag, &layout, &schema);

Ok(())
Ok(layout)
}

pub async fn model_schema(
pub async fn model_schema<P>(
tag: String,
world_address: Felt,
provider: JsonRpcClient<HttpTransport>,
provider: P,
to_json: bool,
) -> Result<()> {
) -> Result<Ty>
where
P: Provider + Send + Sync,
{
let mut world_reader = WorldContractReader::new(world_address, &provider);
world_reader.set_block(BlockId::Tag(BlockTag::Pending));

Expand All @@ -79,18 +86,21 @@ pub async fn model_schema(
if to_json {
println!("{}", serde_json::to_string_pretty(&schema)?)
} else {
deep_print_ty(schema);
deep_print_ty(&schema);
}

Ok(())
Ok(schema)
}

pub async fn model_get(
pub async fn model_get<P>(
tag: String,
keys: Vec<Felt>,
world_address: Felt,
provider: JsonRpcClient<HttpTransport>,
) -> Result<()> {
provider: P,
) -> Result<(Ty, Vec<Felt>)>
where
P: Provider + Send + Sync,
{
if keys.is_empty() {
anyhow::bail!("Models always have at least one key. Please provide it (or them).");
}
Expand All @@ -104,7 +114,7 @@ pub async fn model_get(

deep_print_record(&schema, &keys, &values);

Ok(())
Ok((schema, values))
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -649,11 +659,26 @@ pub fn print_ty(ty: &Ty) {
}

// print the full Ty tree
pub fn deep_print_ty(root: Ty) {
pub fn deep_print_ty(root: &Ty) {
let mut ty_list = vec![];
get_printable_ty_list(&root, &mut ty_list);
get_printable_ty_list(root, &mut ty_list);

for ty in ty_list {
print_ty(&ty);
}
}

/// Checks if the tag is a valid tag, if not, return the default namespace. This allows
/// sozo model commands to be run even without a Scarb.toml file in the current directory
/// if a valid tag is provided.
/// TODO: This may be removed in the future once SDKs are updated to use the new bindgen.
pub fn check_tag_or_read_default_namespace(tag_or_name: &str, config: &Config) -> Result<String> {
if naming::is_valid_tag(tag_or_name) {
Ok(tag_or_name.to_string())
} else {
let ws = scarb::ops::read_workspace(config.manifest_path(), config)?;
let default_namespace = get_default_namespace_from_ws(&ws)?;
let tag = naming::ensure_namespace(tag_or_name, &default_namespace);
Ok(tag)
}
}
1 change: 1 addition & 0 deletions crates/sozo/ops/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod auth;
pub mod call;
pub mod migration;
pub mod model;
pub mod setup;
pub mod utils;
Loading

0 comments on commit 8a1a652

Please sign in to comment.