diff --git a/crates/dojo-world/src/contracts/model.rs b/crates/dojo-world/src/contracts/model.rs index f6c1ec6c84..b41c63071d 100644 --- a/crates/dojo-world/src/contracts/model.rs +++ b/crates/dojo-world/src/contracts/model.rs @@ -1,5 +1,6 @@ use std::vec; +use async_trait::async_trait; use dojo_types::packing::{parse_ty, unpack, PackingError, ParseError}; use dojo_types::primitive::PrimitiveError; use dojo_types::schema::Ty; @@ -46,7 +47,16 @@ pub enum ModelError

{ Packing(#[from] PackingError), } -pub struct ModelReader<'a, P> { +#[async_trait] +pub trait ModelReader { + fn class_hash(&self) -> FieldElement; + async fn schema(&self) -> Result; + async fn packed_size(&self) -> Result; + async fn unpacked_size(&self) -> Result; + async fn layout(&self) -> Result, E>; +} + +pub struct ModelRPCReader<'a, P: Sync + Send> { /// The name of the model name: FieldElement, /// The class hash of the model @@ -55,14 +65,14 @@ pub struct ModelReader<'a, P> { world_reader: &'a WorldContractReader

, } -impl<'a, P> ModelReader<'a, P> +impl<'a, P> ModelRPCReader<'a, P> where - P: Provider, + P: Provider + Sync + Send, { pub async fn new( name: &str, world: &'a WorldContractReader

, - ) -> Result, ModelError> { + ) -> Result, ModelError> { let name = cairo_short_string_to_felt(name)?; let class_hash = world @@ -88,11 +98,59 @@ where Ok(Self { world_reader: world, class_hash, name }) } - pub fn class_hash(&self) -> FieldElement { + pub async fn entity_storage( + &self, + keys: &[FieldElement], + ) -> Result, ModelError> { + let packed_size: u8 = + self.packed_size().await?.try_into().map_err(ParseError::ValueOutOfRange)?; + + let key = poseidon_hash_many(keys); + let key = poseidon_hash_many(&[short_string!("dojo_storage"), self.name, key]); + + let mut packed = Vec::with_capacity(packed_size as usize); + for slot in 0..packed_size { + let value = self + .world_reader + .provider() + .get_storage_at( + self.world_reader.address(), + key + slot.into(), + self.world_reader.block_id(), + ) + .await?; + + packed.push(value); + } + + Ok(packed) + } + + pub async fn entity(&self, keys: &[FieldElement]) -> Result> { + let mut schema = self.schema().await?; + + let layout = self.layout().await?; + let raw_values = self.entity_storage(keys).await?; + + let unpacked = unpack(raw_values, layout)?; + let mut keys_and_unpacked = [keys, &unpacked].concat(); + + schema.deserialize(&mut keys_and_unpacked)?; + + Ok(schema) + } +} + +#[async_trait] +impl<'a, P> ModelReader> for ModelRPCReader<'a, P> +where + P: Provider + Sync + Send, +{ + fn class_hash(&self) -> FieldElement { self.class_hash } - pub async fn schema(&self) -> Result> { + async fn schema(&self) -> Result> { let entrypoint = get_selector_from_name(SCHEMA_SELECTOR_STR).unwrap(); let res = self @@ -103,7 +161,7 @@ where Ok(parse_ty(&res[1..])?) } - pub async fn packed_size(&self) -> Result> { + async fn packed_size(&self) -> Result> { let entrypoint = get_selector_from_name(PACKED_SIZE_SELECTOR_STR).unwrap(); let res = self @@ -114,7 +172,7 @@ where Ok(res[1]) } - pub async fn unpacked_size(&self) -> Result> { + async fn unpacked_size(&self) -> Result> { let entrypoint = get_selector_from_name(UNPACKED_SIZE_SELECTOR_STR).unwrap(); let res = self @@ -125,7 +183,7 @@ where Ok(res[1]) } - pub async fn layout(&self) -> Result, ModelError> { + async fn layout(&self) -> Result, ModelError> { let entrypoint = get_selector_from_name(LAYOUT_SELECTOR_STR).unwrap(); let res = self @@ -135,46 +193,4 @@ where Ok(res[2..].into()) } - - pub async fn entity_storage( - &self, - keys: &[FieldElement], - ) -> Result, ModelError> { - let packed_size: u8 = - self.packed_size().await?.try_into().map_err(ParseError::ValueOutOfRange)?; - - let key = poseidon_hash_many(keys); - let key = poseidon_hash_many(&[short_string!("dojo_storage"), self.name, key]); - - let mut packed = Vec::with_capacity(packed_size as usize); - for slot in 0..packed_size { - let value = self - .world_reader - .provider() - .get_storage_at( - self.world_reader.address(), - key + slot.into(), - self.world_reader.block_id(), - ) - .await?; - - packed.push(value); - } - - Ok(packed) - } - - pub async fn entity(&self, keys: &[FieldElement]) -> Result> { - let mut schema = self.schema().await?; - - let layout = self.layout().await?; - let raw_values = self.entity_storage(keys).await?; - - let unpacked = unpack(raw_values, layout)?; - let mut keys_and_unpacked = [keys, &unpacked].concat(); - - schema.deserialize(&mut keys_and_unpacked)?; - - Ok(schema) - } } diff --git a/crates/dojo-world/src/contracts/model_test.rs b/crates/dojo-world/src/contracts/model_test.rs index 300ac6ede2..6b4b5e1981 100644 --- a/crates/dojo-world/src/contracts/model_test.rs +++ b/crates/dojo-world/src/contracts/model_test.rs @@ -7,6 +7,7 @@ use dojo_types::schema::{Enum, EnumOption, Member, Struct, Ty}; use starknet::accounts::ConnectedAccount; use starknet::core::types::FieldElement; +use crate::contracts::model::ModelReader; use crate::contracts::world::test::deploy_world; use crate::contracts::world::WorldContractReader; diff --git a/crates/dojo-world/src/contracts/world.rs b/crates/dojo-world/src/contracts/world.rs index 1f9440ff7a..9421d97bb9 100644 --- a/crates/dojo-world/src/contracts/world.rs +++ b/crates/dojo-world/src/contracts/world.rs @@ -11,7 +11,7 @@ use starknet::core::utils::{ use starknet::macros::selector; use starknet::providers::{Provider, ProviderError}; -use super::model::{ModelError, ModelReader}; +use super::model::{ModelError, ModelRPCReader}; #[cfg(test)] #[path = "world_test.rs"] @@ -177,7 +177,7 @@ where pub async fn model( &'a self, name: &str, - ) -> Result, ModelError<::Error>> + ) -> Result, ModelError<::Error>> { self.reader.model(name).await } @@ -340,9 +340,12 @@ where impl<'a, P> WorldContractReader

where - P: Provider, + P: Provider + Sync + Send, { - pub async fn model(&'a self, name: &str) -> Result, ModelError> { - ModelReader::new(name, self).await + pub async fn model( + &'a self, + name: &str, + ) -> Result, ModelError> { + ModelRPCReader::new(name, self).await } } diff --git a/crates/sozo/src/ops/model.rs b/crates/sozo/src/ops/model.rs index aba6fa548d..d567f1b230 100644 --- a/crates/sozo/src/ops/model.rs +++ b/crates/sozo/src/ops/model.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use dojo_world::contracts::world::WorldContractReader; +use dojo_world::contracts::{world::WorldContractReader, model::ModelReader}; use dojo_world::metadata::Environment; use starknet::core::types::{BlockId, BlockTag}; diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index 2d63014c93..f632f6e437 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -1,5 +1,6 @@ use anyhow::{Error, Ok, Result}; use async_trait::async_trait; +use dojo_world::contracts::model::ModelReader; use dojo_world::contracts::world::WorldContractReader; use starknet::core::types::{BlockWithTxs, Event, InvokeTransactionReceipt}; use starknet::core::utils::parse_cairo_short_string;