From 0b491abebca99448e3e517a77c6c9acd1c3f2619 Mon Sep 17 00:00:00 2001 From: Tarrence van As Date: Sat, 10 Jun 2023 14:01:44 -0400 Subject: [PATCH] Load entity values --- Cargo.lock | 1 + Cargo.toml | 29 ++++++++++----- crates/dojo-core/src/storage/kv.cairo | 2 +- crates/dojo-core/src/storage/query.cairo | 3 +- crates/dojo-world/Cargo.toml | 1 + crates/dojo-world/src/component.rs | 45 +++++++++++++++++++++--- crates/dojo-world/src/system_test.rs | 32 +++++++++++++---- examples/ecs/src/systems.cairo | 12 +++---- 8 files changed, 96 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ef30d88be..49d521d26c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2990,6 +2990,7 @@ dependencies = [ "serde_with", "smol_str", "starknet 0.2.0 (git+/~https://github.com/xJonathanLEI/starknet-rs?branch=dev/jsonrpc_0_3_0)", + "starknet-crypto 0.5.1", "thiserror", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index d2260c45eb..003c0d3d1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,19 @@ resolver = "2" -members = [ "crates/bevy-dojo", "crates/dojo-lang", "crates/dojo-language-server", "crates/dojo-world", "crates/dojo-test-utils", "crates/dojo-signers", "crates/katana", "crates/katana-core", "crates/katana-rpc", "crates/sozo", "crates/torii" ] +members = [ + "crates/bevy-dojo", + "crates/dojo-lang", + "crates/dojo-language-server", + "crates/dojo-world", + "crates/dojo-test-utils", + "crates/dojo-signers", + "crates/katana", + "crates/katana-core", + "crates/katana-rpc", + "crates/sozo", + "crates/torii", +] [workspace.package] version = "0.1.0" @@ -27,7 +39,7 @@ cairo-lang-lowering = "1.1.0" cairo-lang-parser = "1.1.0" cairo-lang-plugins = "1.1.0" cairo-lang-project = "1.1.0" -cairo-lang-semantic = { version = "1.1.0", features = [ "testing" ] } +cairo-lang-semantic = { version = "1.1.0", features = ["testing"] } cairo-lang-sierra-generator = "1.1.0" cairo-lang-sierra = "1.1.0" cairo-lang-sierra-to-casm = "1.1.0" @@ -36,9 +48,9 @@ cairo-lang-syntax = "1.1.0" cairo-lang-test-utils = "1.1.0" cairo-lang-test-runner = "1.1.0" cairo-lang-utils = "1.1.0" -camino = { version = "1.1.2", features = [ "serde1" ] } -chrono = { version = "0.4.24", features = [ "serde" ] } -clap = { version = "4.2", features = [ "derive" ] } +camino = { version = "1.1.2", features = ["serde1"] } +chrono = { version = "0.4.24", features = ["serde"] } +clap = { version = "4.2", features = ["derive"] } colored = "2" env_logger = "0.10.0" indoc = "1.0.7" @@ -50,15 +62,16 @@ rayon = "0.9.0" salsa = "0.16.1" scarb = { git = "/~https://github.com/software-mansion/scarb", rev = "0aa0f97b89a2e6f38f3b005cad2817dcaee7bf51" } semver = "1.0.5" -serde = { version = "1.0.156", features = [ "derive" ] } +serde = { version = "1.0.156", features = ["derive"] } serde_json = "1.0" serde_with = "2.3.1" -smol_str = { version = "0.2.0", features = [ "serde" ] } +smol_str = { version = "0.2.0", features = ["serde"] } starknet = { git = "/~https://github.com/xJonathanLEI/starknet-rs", branch = "dev/jsonrpc_0_3_0" } +starknet-crypto = { git = "/~https://github.com/xJonathanLEI/starknet-rs", branch = "dev/jsonrpc_0_3_0" } starknet_api = { git = "/~https://github.com/starkware-libs/starknet-api" } test-log = "0.2.11" thiserror = "1.0.32" -tokio = { version = "1.16", features = [ "full" ] } +tokio = { version = "1.16", features = ["full"] } toml = "0.7.4" tracing = "0.1" tracing-subscriber = "0.3.16" diff --git a/crates/dojo-core/src/storage/kv.cairo b/crates/dojo-core/src/storage/kv.cairo index a33421d45f..16884ceaa7 100644 --- a/crates/dojo-core/src/storage/kv.cairo +++ b/crates/dojo-core/src/storage/kv.cairo @@ -7,7 +7,7 @@ mod KeyValueStore { use dojo_core::{integer::u250, serde::SpanSerde}; fn address(table: u250, key: u250) -> starknet::StorageBaseAddress { - starknet::storage_base_address_from_felt252(hash::LegacyHash::hash(0x420, (table, key))) + starknet::storage_base_address_from_felt252(hash::LegacyHash::hash(table.into(), key)) } #[view] diff --git a/crates/dojo-core/src/storage/query.cairo b/crates/dojo-core/src/storage/query.cairo index 403180686c..edcfe3916e 100644 --- a/crates/dojo-core/src/storage/query.cairo +++ b/crates/dojo-core/src/storage/query.cairo @@ -38,12 +38,11 @@ impl QueryImpl of QueryTrait { fn hash(self: @Query) -> u250 { let keys = *self.keys; - if keys.len() == 1 & *self.partition == 0.into() { + if keys.len() == 1 { return *keys.at(0); } let mut serialized = ArrayTrait::new(); - self.partition.serialize(ref serialized); self.keys.serialize(ref serialized); poseidon_hash_span(serialized.span()).into() } diff --git a/crates/dojo-world/Cargo.toml b/crates/dojo-world/Cargo.toml index 8ea9e948e2..a1b0f1c321 100644 --- a/crates/dojo-world/Cargo.toml +++ b/crates/dojo-world/Cargo.toml @@ -20,6 +20,7 @@ serde_json.workspace = true serde_with.workspace = true smol_str.workspace = true starknet.workspace = true +starknet-crypto.workspace = true thiserror.workspace = true tracing.workspace = true url = "2.2.2" diff --git a/crates/dojo-world/src/component.rs b/crates/dojo-world/src/component.rs index 7b3dcb5fa6..987f028ed6 100644 --- a/crates/dojo-world/src/component.rs +++ b/crates/dojo-world/src/component.rs @@ -1,9 +1,13 @@ +use std::vec; + +use starknet::core::crypto::pedersen_hash; use starknet::core::types::{BlockId, FieldElement, FunctionCall}; use starknet::core::utils::{ cairo_short_string_to_felt, get_selector_from_name, parse_cairo_short_string, CairoShortStringToFeltError, ParseCairoShortStringError, }; use starknet::providers::{Provider, ProviderError}; +use starknet_crypto::{poseidon_hash, poseidon_hash_many}; use crate::manifest::Member; use crate::world::{ContractReaderError, WorldContractReader}; @@ -31,6 +35,7 @@ pub enum ComponentError

{ pub struct ComponentReader<'a, P: Provider + Sync> { world: &'a WorldContractReader<'a, P>, class_hash: FieldElement, + name: FieldElement, } impl<'a, P: Provider + Sync> ComponentReader<'a, P> { @@ -39,15 +44,14 @@ impl<'a, P: Provider + Sync> ComponentReader<'a, P> { name: String, block_id: BlockId, ) -> Result, ComponentError> { + let name = cairo_short_string_to_felt(&name) + .map_err(ComponentError::CairoShortStringToFeltError)?; let res = world .provider .call( FunctionCall { contract_address: world.address, - calldata: vec![ - cairo_short_string_to_felt(&name) - .map_err(ComponentError::CairoShortStringToFeltError)?, - ], + calldata: vec![name], entry_point_selector: get_selector_from_name("component").unwrap(), }, block_id, @@ -55,7 +59,7 @@ impl<'a, P: Provider + Sync> ComponentReader<'a, P> { .await .map_err(ComponentError::ProviderError)?; - Ok(Self { world, class_hash: res[0] }) + Ok(Self { world, class_hash: res[0], name }) } pub fn class_hash(&self) -> FieldElement { @@ -93,4 +97,35 @@ impl<'a, P: Provider + Sync> ComponentReader<'a, P> { Ok(members) } + + pub async fn entity( + &self, + partition_id: FieldElement, + keys: Vec, + block_id: BlockId, + ) -> Result, ComponentError> { + let members = self.schema(block_id).await?; + + let table = if partition_id == FieldElement::ZERO { + self.name + } else { + poseidon_hash(self.name, partition_id) + }; + let keys_hash = if keys.len() == 1 { keys[0] } else { poseidon_hash_many(&keys) }; + let key = pedersen_hash(&table, &keys_hash); + + let mut values = vec![]; + for member in members { + let value = self + .world + .provider + .get_storage_at(self.world.address, key + member.slot.into(), block_id) + .await + .map_err(ComponentError::ProviderError)?; + + values.push(value); + } + + Ok(values) + } } diff --git a/crates/dojo-world/src/system_test.rs b/crates/dojo-world/src/system_test.rs index 3ea0f46371..daa57fd3b5 100644 --- a/crates/dojo-world/src/system_test.rs +++ b/crates/dojo-world/src/system_test.rs @@ -1,17 +1,17 @@ use camino::Utf8PathBuf; use dojo_test_utils::sequencer::TestSequencer; -use starknet::accounts::ConnectedAccount; +use starknet::accounts::Account; use starknet::core::types::{BlockId, BlockTag}; +use starknet_crypto::FieldElement; use crate::manifest::Dependency; use crate::world::test::deploy_world; -use crate::world::WorldContractReader; +use crate::world::WorldContract; #[tokio::test] async fn test_system() { let sequencer = TestSequencer::start().await; let account = sequencer.account(); - let provider = account.provider(); let (world_address, _) = deploy_world( &sequencer, Utf8PathBuf::from_path_buf("../../examples/ecs/target/dev".into()).unwrap(), @@ -19,9 +19,9 @@ async fn test_system() { .await; let block_id: BlockId = BlockId::Tag(BlockTag::Latest); - let world = WorldContractReader::new(world_address, provider); - let system = world.system("Spawn", block_id).await.unwrap(); - let dependencies = system.dependencies(block_id).await.unwrap(); + let world = WorldContract::new(world_address, &account); + let spawn = world.system("Spawn", block_id).await.unwrap(); + let dependencies = spawn.dependencies(block_id).await.unwrap(); assert_eq!( dependencies, vec![ @@ -29,4 +29,24 @@ async fn test_system() { Dependency { name: "Position".into(), read: false, write: true } ] ); + + let _ = spawn.execute(vec![]).await.unwrap(); + + let component = world.component("Moves", block_id).await.unwrap(); + let moves = + component.entity(FieldElement::ZERO, vec![account.address()], block_id).await.unwrap(); + + assert_eq!(moves, vec![10_u8.into()]); + + // let move_system = world.system("Move", block_id).await.unwrap(); + + // let _ = move_system.execute(vec![FieldElement::ONE]).await.unwrap(); + // let _ = move_system.execute(vec![FieldElement::THREE]).await.unwrap(); + + // let moves = + // component.entity(FieldElement::ZERO, vec![account.address()], block_id).await.unwrap(); + + // assert_eq!(moves, vec![8_u8.into()]); + + // let position_component = world.component("Position", block_id).await.unwrap(); } diff --git a/examples/ecs/src/systems.cairo b/examples/ecs/src/systems.cairo index caec7f5d87..6cf63d41fd 100644 --- a/examples/ecs/src/systems.cairo +++ b/examples/ecs/src/systems.cairo @@ -6,10 +6,9 @@ mod Spawn { use dojo_examples::components::Position; use dojo_examples::components::Moves; - fn execute() { - let caller = starknet::get_caller_address(); + fn execute(ctx: Context) { let player = commands::set_entity( - caller.into(), (Moves { remaining: 10 }, Position { x: 0, y: 0 }, ) + ctx.caller_account.into(), (Moves { remaining: 10 }, Position { x: 0, y: 0 }, ) ); return (); } @@ -42,12 +41,11 @@ mod Move { } } - fn execute(direction: Direction) { - let caller = starknet::get_caller_address(); - let (position, moves) = commands::::entity(caller.into()); + fn execute(ctx: Context, direction: Direction) { + let (position, moves) = commands::::entity(ctx.caller_account.into()); let next = next_position(position, direction); let uh = commands::set_entity( - caller.into(), + ctx.caller_account.into(), (Moves { remaining: moves.remaining - 1 }, Position { x: next.x, y: next.y }, ) ); return ();