Skip to content

Commit

Permalink
feat: add systems to manifest (#2642)
Browse files Browse the repository at this point in the history
A system is any function found in a dojo contract that is exposed in the ABI
with the state mutability as external.
Event if Dojo per se doesn't modify the storage of the contract,
it's required that the user explicitely identify the systems with
ref self.
  • Loading branch information
glihm authored Nov 6, 2024
1 parent 7bf9be3 commit ba96d0e
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 51 deletions.
18 changes: 18 additions & 0 deletions crates/dojo/world/src/diff/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub struct WorldContract {
pub seed: String,
/// Name of the world.
pub name: String,
/// Entrypoints of the world.
pub entrypoints: Vec<String>,
/// Abi of the world.
pub abi: Vec<AbiEntry>,
}
Expand All @@ -53,6 +55,9 @@ pub struct DojoContract {
pub init_calldata: Vec<String>,
/// Tag of the contract.
pub tag: String,
/// Selector of the contract.
#[serde_as(as = "UfeHex")]
pub selector: Felt,
/// Systems of the contract.
pub systems: Vec<String>,
}
Expand All @@ -68,6 +73,9 @@ pub struct DojoModel {
pub class_hash: Felt,
/// Tag of the model.
pub tag: String,
/// Selector of the model.
#[serde_as(as = "UfeHex")]
pub selector: Felt,
}

#[serde_as]
Expand All @@ -81,6 +89,9 @@ pub struct DojoEvent {
pub class_hash: Felt,
/// Tag of the event.
pub tag: String,
/// Selector of the event.
#[serde_as(as = "UfeHex")]
pub selector: Felt,
}

/// Represents a model member.
Expand All @@ -102,6 +113,7 @@ impl Manifest {
address: diff.world_info.address,
seed: diff.profile_config.world.seed.clone(),
name: diff.profile_config.world.name.clone(),
entrypoints: diff.world_info.entrypoints.clone(),
abi: diff.world_info.class.abi.clone(),
};

Expand Down Expand Up @@ -147,6 +159,7 @@ fn resource_diff_to_dojo_contract(diff: &WorldDiff, resource: &ResourceDiff) ->
init_calldata,
tag,
systems: l.systems.clone(),
selector: resource.dojo_selector(),
},
ResourceDiff::Updated(ResourceLocal::Contract(l), ResourceRemote::Contract(r))
| ResourceDiff::Synced(ResourceLocal::Contract(l), ResourceRemote::Contract(r)) => {
Expand All @@ -157,6 +170,7 @@ fn resource_diff_to_dojo_contract(diff: &WorldDiff, resource: &ResourceDiff) ->
init_calldata,
tag,
systems: l.systems.clone(),
selector: resource.dojo_selector(),
}
}
_ => unreachable!(),
Expand All @@ -173,6 +187,7 @@ fn resource_diff_to_dojo_model(resource: &ResourceDiff) -> DojoModel {
.collect(),
class_hash: l.common.class_hash,
tag: l.common.name.clone(),
selector: resource.dojo_selector(),
},
ResourceDiff::Updated(ResourceLocal::Model(l), _)
| ResourceDiff::Synced(ResourceLocal::Model(l), _) => DojoModel {
Expand All @@ -183,6 +198,7 @@ fn resource_diff_to_dojo_model(resource: &ResourceDiff) -> DojoModel {
.collect(),
class_hash: l.common.class_hash,
tag: l.common.name.clone(),
selector: resource.dojo_selector(),
},
_ => unreachable!(),
}
Expand All @@ -198,6 +214,7 @@ fn resource_diff_to_dojo_event(resource: &ResourceDiff) -> DojoEvent {
.collect(),
class_hash: l.common.class_hash,
tag: l.common.name.clone(),
selector: resource.dojo_selector(),
},
ResourceDiff::Updated(ResourceLocal::Event(l), _)
| ResourceDiff::Synced(ResourceLocal::Event(l), _) => DojoEvent {
Expand All @@ -208,6 +225,7 @@ fn resource_diff_to_dojo_event(resource: &ResourceDiff) -> DojoEvent {
.collect(),
class_hash: l.common.class_hash,
tag: l.common.name.clone(),
selector: resource.dojo_selector(),
},
_ => unreachable!(),
}
Expand Down
4 changes: 4 additions & 0 deletions crates/dojo/world/src/diff/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub struct WorldStatusInfo {
pub class: SierraClass,
/// The status of the world.
pub status: WorldStatus,
/// The entrypoints of the world.
pub entrypoints: Vec<String>,
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -75,6 +77,7 @@ impl WorldDiff {
casm_class_hash: local.casm_class_hash,
class: local.class,
status: WorldStatus::NotDeployed,
entrypoints: local.entrypoints,
},
namespaces: vec![],
resources: HashMap::new(),
Expand Down Expand Up @@ -111,6 +114,7 @@ impl WorldDiff {
class_hash: local.class_hash,
casm_class_hash: local.casm_class_hash,
class: local.class,
entrypoints: local.entrypoints,
status,
},
namespaces: vec![],
Expand Down
79 changes: 70 additions & 9 deletions crates/dojo/world/src/local/artifact_to_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use anyhow::Result;
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use cairo_lang_starknet_classes::contract_class::ContractClass;
use serde_json;
use starknet::core::types::contract::{AbiEntry, AbiImpl, SierraClass};
use starknet::core::types::contract::{AbiEntry, AbiImpl, SierraClass, StateMutability};
use starknet::core::types::Felt;
use tracing::trace;

Expand All @@ -31,7 +31,7 @@ impl WorldLocal {
let mut world_class = None;
let mut world_class_hash = None;
let mut world_casm_class_hash = None;

let mut world_entrypoints = vec![];
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
Expand All @@ -57,11 +57,14 @@ impl WorldLocal {
world_class = Some(sierra);
world_class_hash = Some(class_hash);
world_casm_class_hash = Some(casm_class_hash);
world_entrypoints = systems_from_abi(&abi);
break;
}
ResourceType::Contract(name) => {
let namespaces = profile_config.namespace.get_namespaces(&name);

let systems = systems_from_abi(&abi);

for ns in namespaces {
trace!(
name,
Expand All @@ -77,7 +80,7 @@ impl WorldLocal {
class_hash,
casm_class_hash,
},
systems: vec![],
systems: systems.clone(),
});

resources.push(resource);
Expand Down Expand Up @@ -162,6 +165,7 @@ impl WorldLocal {
casm_class_hash,
resources: HashMap::new(),
profile_config,
entrypoints: world_entrypoints,
},
_ => {
return Err(anyhow::anyhow!(
Expand Down Expand Up @@ -227,6 +231,26 @@ fn name_from_impl(impl_name: &str) -> String {
impl_name.split("__").collect::<Vec<&str>>()[0].to_string()
}

fn systems_from_abi(abi: &[AbiEntry]) -> Vec<String> {
fn extract_systems_from_abi_entry(entry: &AbiEntry) -> Vec<String> {
match entry {
AbiEntry::Function(f) => {
if matches!(f.state_mutability, StateMutability::External) {
vec![f.name.clone()]
} else {
vec![]
}
}
AbiEntry::Interface(intf_entry) => {
intf_entry.items.iter().flat_map(extract_systems_from_abi_entry).collect()
}
_ => vec![],
}
}

abi.iter().flat_map(extract_systems_from_abi_entry).collect()
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -274,19 +298,56 @@ mod tests {
);
}

#[ignore = "The simple example must be stabilized first (and built for this test to work)"]
#[test]
fn test_load_world_from_directory() {
let namespace_config = NamespaceConfig::new("dojo");
let profile_config = ProfileConfig::new("test", "seed", namespace_config);

let world = WorldLocal::from_directory(
"/Users/glihm/cgg/dojo/examples/simple/target/dev",
profile_config,
let world =
WorldLocal::from_directory("../../../examples/simple/target/dev/", profile_config)
.unwrap();

assert!(world.class_hash != Felt::ZERO);
assert_eq!(world.resources.len(), 7);
assert_eq!(
world.entrypoints,
vec![
"uuid",
"set_metadata",
"register_namespace",
"register_event",
"register_model",
"register_contract",
"init_contract",
"upgrade_event",
"upgrade_model",
"upgrade_contract",
"emit_event",
"emit_events",
"set_entity",
"set_entities",
"delete_entity",
"delete_entities",
"grant_owner",
"revoke_owner",
"grant_writer",
"revoke_writer",
"upgrade"
]
);
}

#[test]
fn test_systems_from_abi() {
let abi = serde_json::from_reader::<_, SierraClass>(
std::fs::File::open(
"../../../examples/simple/target/dev/dojo_simple_c1.contract_class.json",
)
.unwrap(),
)
.unwrap();

assert!(world.class_hash != Felt::ZERO);
assert_eq!(world.resources.len(), 3);
let systems = systems_from_abi(&abi.abi);
assert_eq!(systems, vec!["system_1", "system_2", "system_3", "system_4", "upgrade"]);
}
}
4 changes: 4 additions & 0 deletions crates/dojo/world/src/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ pub struct WorldLocal {
pub resources: HashMap<DojoSelector, ResourceLocal>,
/// The profile configuration of the local world.
pub profile_config: ProfileConfig,
/// All the entrypoints that are exposed by the world
/// and can be targetted by a transaction.
pub entrypoints: Vec<String>,
}

#[cfg(test)]
Expand Down Expand Up @@ -64,6 +67,7 @@ impl Default for WorldLocal {
casm_class_hash: Felt::ZERO,
resources: HashMap::new(),
profile_config: ProfileConfig::default(),
entrypoints: vec![],
}
}
}
Expand Down
Loading

0 comments on commit ba96d0e

Please sign in to comment.