Skip to content

Commit

Permalink
Namespace feature
Browse files Browse the repository at this point in the history
  • Loading branch information
remybar committed Jun 17, 2024
1 parent 88848ef commit 8d98dc7
Show file tree
Hide file tree
Showing 168 changed files with 5,399 additions and 14,045 deletions.
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@
"apply"
]
},
{
"name": "Sozo",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/target/debug/sozo",
"args": [
"--manifest-path",
"examples/spawn-and-move/Scarb.toml",
"events",
"--world",
"0x04c972a756d796d716f665a8079dbf9aff05bbba41a2b8194553073f31d7d393",
"--chunk-size",
"100"
]
},
{
"type": "lldb",
"request": "launch",
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 47 additions & 10 deletions bin/sozo/src/commands/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::Result;
use clap::{Args, Subcommand};
use scarb::core::Config;
use sozo_ops::model;
use sozo_ops::utils::get_default_namespace_from_ws;
use starknet::core::types::FieldElement;
use tracing::trace;

Expand All @@ -22,6 +23,10 @@ pub enum ModelCommand {
#[arg(help = "The name of the model")]
name: String,

#[arg(short, long)]
#[arg(help = "The model namespace. If not set, the main package ID is used.")]
namespace: Option<String>,

#[command(flatten)]
world: WorldOptions,

Expand All @@ -34,6 +39,10 @@ pub enum ModelCommand {
#[arg(help = "The name of the model")]
name: String,

#[arg(short, long)]
#[arg(help = "The model namespace. If not set, the main package ID is used.")]
namespace: Option<String>,

#[command(flatten)]
world: WorldOptions,

Expand Down Expand Up @@ -65,6 +74,10 @@ hashes, called 'hash' in the following documentation.
#[arg(help = "The name of the model")]
name: String,

#[arg(short, long)]
#[arg(help = "The model namespace. If not set, the main package ID is used.")]
namespace: Option<String>,

#[command(flatten)]
world: WorldOptions,

Expand All @@ -77,6 +90,10 @@ hashes, called 'hash' in the following documentation.
#[arg(help = "The name of the model")]
name: String,

#[arg(short, long)]
#[arg(help = "The model namespace. If not set, the main package ID is used.")]
namespace: Option<String>,

#[command(flatten)]
world: WorldOptions,

Expand All @@ -93,6 +110,10 @@ hashes, called 'hash' in the following documentation.
#[arg(help = "The name of the model")]
name: String,

#[arg(short, long)]
#[arg(help = "The model namespace. If not set, the main package ID is used.")]
namespace: Option<String>,

#[arg(value_name = "KEYS")]
#[arg(value_delimiter = ',')]
#[arg(help = "Comma seperated values e.g., 0x12345,0x69420,...")]
Expand All @@ -109,34 +130,50 @@ 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 get_namespace = |ns: Option<String>| -> String {
match ns {
Some(x) => x,
None => {
let default_namespace = get_default_namespace_from_ws(&ws);
println!("[default namespace: {}]", default_namespace);
default_namespace
}
}
};

config.tokio_handle().block_on(async {
match self.command {
ModelCommand::ClassHash { name, starknet, world } => {
ModelCommand::ClassHash { name, namespace, starknet, world } => {
let namespace = get_namespace(namespace);
let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_class_hash(name, world_address, provider).await
model::model_class_hash(namespace, name, world_address, provider).await
}
ModelCommand::ContractAddress { name, starknet, world } => {
ModelCommand::ContractAddress { name, namespace, starknet, world } => {
let namespace = get_namespace(namespace);
let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_contract_address(name, world_address, provider).await
model::model_contract_address(namespace, name, world_address, provider).await
}
ModelCommand::Layout { name, starknet, world } => {
ModelCommand::Layout { name, namespace, starknet, world } => {
let namespace = get_namespace(namespace);
let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_layout(name, world_address, provider).await
model::model_layout(namespace, name, world_address, provider).await
}
ModelCommand::Schema { name, to_json, starknet, world } => {
ModelCommand::Schema { name, namespace, to_json, starknet, world } => {
let namespace = get_namespace(namespace);
let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_schema(name, world_address, provider, to_json).await
model::model_schema(namespace, name, world_address, provider, to_json).await
}
ModelCommand::Get { name, keys, starknet, world } => {
ModelCommand::Get { name, namespace, keys, starknet, world } => {
let namespace = get_namespace(namespace);
let world_address = world.address(env_metadata.as_ref()).unwrap();
let provider = starknet.provider(env_metadata.as_ref()).unwrap();
model::model_get(name, keys, world_address, provider).await
model::model_get(namespace, name, keys, world_address, provider).await
}
}
})
Expand Down
13 changes: 10 additions & 3 deletions bin/sozo/tests/register_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use dojo_world::migration::TxnConfig;
use katana_runner::KatanaRunner;
use scarb::ops;
use sozo_ops::migration::execute_strategy;
use sozo_ops::utils::get_default_namespace_from_ws;
use starknet::accounts::Account;
use starknet::core::types::{BlockId, BlockTag};
use utils::snapbox::get_snapbox;
Expand All @@ -27,9 +28,15 @@ async fn reregister_models() {
let target_path =
ws.target_dir().path_existent().unwrap().join(ws.config().profile().to_string());

let migration =
prepare_migration(source_project_dir.clone(), target_path, dojo_metadata.skip_migration)
.unwrap();
let default_namespace = get_default_namespace_from_ws(&ws);

let migration = prepare_migration(
source_project_dir.clone(),
target_path,
dojo_metadata.skip_migration,
&default_namespace,
)
.unwrap();

let sequencer = KatanaRunner::new().expect("Failed to start runner.");

Expand Down
2 changes: 1 addition & 1 deletion crates/benches/contracts/src/tests/test_world.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ mod tests {
let mut models = array![position::TEST_CLASS_HASH, moves::TEST_CLASS_HASH];

// deploy world with models
let world = spawn_test_world(models);
let world = spawn_test_world("benches", models);

// deploy systems contract
let contract_address = world
Expand Down
60 changes: 16 additions & 44 deletions crates/dojo-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use std::path::PathBuf;
use cainome::parser::tokens::Token;
use cainome::parser::{AbiParser, TokenizedAbi};
use camino::Utf8PathBuf;
use convert_case::{Case, Casing};
use dojo_world::manifest::BaseManifest;
pub mod error;
use error::{BindgenResult, Error};
use dojo_world::utils::get_full_world_element_name;
use error::BindgenResult;

mod plugins;
use plugins::typescript::TypescriptPlugin;
Expand Down Expand Up @@ -151,7 +151,10 @@ fn gather_dojo_data(
}
}

let contract_name = contract_manifest.name.to_string();
let contract_name = get_full_world_element_name(
&contract_manifest.inner.namespace,
&contract_manifest.inner.name,
);

contracts.insert(
contract_name.clone(),
Expand All @@ -170,26 +173,18 @@ fn gather_dojo_data(

let tokens = AbiParser::tokens_from_abi_string(&abi, &HashMap::new())?;

let name = model_manifest.name.to_string();

if let Some(model_name) = model_name_from_fully_qualified_path(&name) {
let model_pascal_case = model_name.from_case(Case::Snake).to_case(Case::Pascal);
let full_name = get_full_world_element_name(
&model_manifest.inner.namespace,
&model_manifest.inner.name,
);

let model = DojoModel {
name: model_pascal_case.clone(),
qualified_path: name
.replace(&model_name, &model_pascal_case)
.trim_end_matches(".json")
.to_string(),
tokens: filter_model_tokens(&tokens),
};
let model = DojoModel {
name: full_name.clone(),
qualified_path: full_name.clone(),
tokens: filter_model_tokens(&tokens),
};

models.insert(model_pascal_case, model);
} else {
return Err(Error::Format(format!(
"Could not extract model name from file name `{name}`"
)));
}
models.insert(full_name, model);
}

let world = DojoWorld { name: root_package_name.to_string() };
Expand Down Expand Up @@ -234,36 +229,13 @@ fn filter_model_tokens(tokens: &TokenizedAbi) -> TokenizedAbi {
TokenizedAbi { structs, enums, ..Default::default() }
}

/// Extracts a model name from the fully qualified path of the model.
///
/// # Example
///
/// The fully qualified name "dojo_examples::models::position" should return "position".
///
/// # Arguments
///
/// * `file_name` - Fully qualified model name.
fn model_name_from_fully_qualified_path(file_name: &str) -> Option<String> {
let parts: Vec<&str> = file_name.split("::").collect();

// TODO: we may want to have inside the manifest the name of the model struct
// instead of extracting it from the file's name.
parts.last().map(|last_part| last_part.to_string())
}

#[cfg(test)]
mod tests {
use dojo_test_utils::compiler;
use dojo_world::metadata::dojo_metadata_from_workspace;

use super::*;

#[test]
fn model_name_from_fully_qualified_path_ok() {
let file_name = "dojo_examples::models::position";
assert_eq!(model_name_from_fully_qualified_path(file_name), Some("position".to_string()));
}

#[test]
fn gather_data_ok() {
let manifest_path = Utf8PathBuf::from("src/test_data/spawn-and-move/Scarb.toml");
Expand Down
38 changes: 36 additions & 2 deletions crates/dojo-core/src/base_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use contract_upgrade::{IQuantumLeapDispatcher, IQuantumLeapDispatcherTrait};

// Utils
fn deploy_world() -> IWorldDispatcher {
spawn_test_world(array![])
spawn_test_world("dojo", array![])
}

// A test contract needs to be used instead of previously used base contract since.
Expand Down Expand Up @@ -111,6 +111,8 @@ fn test_upgrade_direct() {
trait IMetadataOnly<T> {
fn selector(self: @T) -> felt252;
fn name(self: @T) -> ByteArray;
fn namespace(self: @T) -> ByteArray;
fn namespace_selector(self: @T) -> felt252;
}

#[starknet::contract]
Expand All @@ -125,6 +127,14 @@ mod invalid_legacy_model {
0x1b1edb46931b1a98d8c6ecf2703e8483ec1d85fb75b3e9c061eab383fc8f8f1
}

fn namespace(self: @ContractState) -> ByteArray {
"dojo"
}

fn namespace_selector(self: @ContractState) -> felt252 {
dojo::utils::hash(@Self::namespace(self))
}

fn name(self: @ContractState) -> ByteArray {
"invalid_legacy_model"
}
Expand All @@ -144,6 +154,14 @@ mod invalid_legacy_model_world {
0
}

fn namespace(self: @ContractState) -> ByteArray {
"dojo"
}

fn namespace_selector(self: @ContractState) -> felt252 {
dojo::utils::hash(@Self::namespace(self))
}

fn name(self: @ContractState) -> ByteArray {
"invalid_legacy_model"
}
Expand All @@ -160,7 +178,15 @@ mod invalid_model {
fn selector(self: @ContractState) -> felt252 {
// NOTE: Need to update this value if address changes
// Pre-computed address of a contract deployed through the world.
0x1b1edb46931b1a98d8c6ecf2703e8483ec1d85fb75b3e9c061eab383fc8f8f1
0x314a23ab2b297b235fe87bf5acade82bcef62e3a375183ab7bf1fe0a3f5e8dd
}

fn namespace(self: @ContractState) -> ByteArray {
"dojo"
}

fn namespace_selector(self: @ContractState) -> felt252 {
dojo::utils::hash(@Self::namespace(self))
}

fn name(self: @ContractState) -> ByteArray {
Expand All @@ -182,6 +208,14 @@ mod invalid_model_world {
0
}

fn namespace(self: @ContractState) -> ByteArray {
"dojo"
}

fn namespace_selector(self: @ContractState) -> felt252 {
dojo::utils::hash(@Self::namespace(self))
}

fn name(self: @ContractState) -> ByteArray {
"invalid_model_world"
}
Expand Down
Loading

0 comments on commit 8d98dc7

Please sign in to comment.