Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: check models and events upgradability #2626

Merged
merged 1 commit into from
Nov 5, 2024

Conversation

remybar
Copy link
Contributor

@remybar remybar commented Nov 4, 2024

Description

Models and events are already upgradeable by deploying a new classhash and use the newly deployed contract address.

However, we would like to check some conditions before allowing to upgrade a model or an event contract:

  • the layout type must remain the same (Struct or Fixed),
  • existing fields cannot be changed or moved inside the resource,
  • new fields can only be appended at the end of the resource.

At the same time, we noticed that having a versioning of models and events is no more useful, so this PR removes versioning management.

Related issue

N/A

Tests

  • Yes
  • No, because they aren't needed
  • No, because I need help

Added to documentation?

  • README.md
  • Dojo Book
  • No documentation needed

Checklist

  • I've formatted my code (scripts/prettier.sh, scripts/rust_fmt.sh, scripts/cairo_fmt.sh)
  • I've linted my code (scripts/clippy.sh, scripts/docs.sh)
  • I've commented my code
  • I've requested a review after addressing the comments

Summary by CodeRabbit

  • New Features

    • Enhanced resource inspection functionality with improved status reporting and visual formatting.
    • Added new event and model structures for testing within the Dojo framework.
    • Introduced new interfaces for deployed and stored resources, improving resource management.
    • Expanded functionality for record management with the addition of a delete method.
    • Updated event handling characteristics by modifying the EH event structure.
    • Introduced new functions for error handling related to resource upgrades and namespace management.
    • Updated the world_address configuration in the dojo_dev.toml file.
  • Bug Fixes

    • Improved error handling for resource upgrades and namespace management.
  • Documentation

    • Updated configuration settings in the dojo_dev.toml file.
  • Refactor

    • Restructured model and event handling implementations for better organization and clarity.
    • Streamlined test setup for entity management to ensure consistent dispatcher usage.
  • Chores

    • Updated dependencies in the Cargo.toml file.

@remybar remybar mentioned this pull request Nov 4, 2024
10 tasks
Copy link

coderabbitai bot commented Nov 4, 2024

Walkthrough

Ohayo, sensei! This pull request introduces significant changes across various files in the Dojo framework. Key updates include a transition of dependencies in Cargo.toml to a new Git repository, restructuring of modules in lib.cairo, and enhancements to event and model handling. New interfaces and methods have been added for better resource management, while several existing methods have been removed or updated to streamline functionality. Additionally, tests have been expanded to cover new features and ensure robustness in contract interactions.

Changes

File Change Summary
Cargo.toml Updated dependencies for scarb and scarb-ui to a new Git repository; commented out previous references.
crates/dojo/core-cairo-test/src/lib.cairo Introduced new modules and restructured existing ones for better organization; expanded public exports.
crates/dojo/core-cairo-test/src/tests/contract.cairo Modified contract implementations and added new methods for resource management; updated tests for contract upgrades.
crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo Replaced contract implementations to enhance resource deployment; introduced new methods for layout and schema.
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo Added new event contracts and a function for setting up test environments for event upgrades.
crates/dojo/core-cairo-test/src/tests/helpers/model.cairo Introduced model contracts for testing model upgrades; added functions for deploying test worlds.
crates/dojo/core-cairo-test/src/tests/world/contract.cairo Added new modules for contract upgrades and namespace management; implemented comprehensive tests for contract behaviors.
crates/dojo/core/src/contract/interface.cairo Removed dojo_name method from IContract trait, altering its functionality.
crates/dojo/core/src/event/component.cairo Introduced new event handling implementations for deployed and stored events.
crates/dojo/core/src/model/component.cairo Restructured model implementations into IDeployedModelImpl and IStoredModelImpl; updated method signatures.
crates/dojo/core/src/world/world_contract.cairo Added Permission enum and updated resource management methods for enhanced access control.
crates/dojo/lang/src/attribute_macros/event.rs Enhanced DojoEvent struct with unique hash computation for event generation.
examples/spawn-and-move/dojo_dev.toml Updated world_address configuration value.
bin/sozo/src/commands/inspect.rs Improved resource inspection functionality and output formatting.
crates/dojo/lang/Cargo.toml Added dependency for starknet-crypto.

Possibly related PRs


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

🧹 Outside diff range and nitpick comments (43)
crates/dojo/core/src/contract/interface.cairo (2)

2-2: Consider adding documentation about trait's purpose.

Even though the trait is empty, it might serve as a marker interface. Adding documentation would help explain its role in the new architecture.

 #[starknet::interface]
+/// Marker trait for Dojo contracts after removal of versioning management.
+/// This trait is intentionally empty as contract identification is now handled
+/// through the new resource management system.
 pub trait IContract<T> {}

2-2: Provide migration guidance for existing implementations.

Since this is a breaking change that removes functionality, consider adding migration documentation to help users update their code to use the new resource management system.

Would you like me to help draft migration documentation or create a GitHub issue to track this task?

crates/dojo/core/src/model/interface.cairo (1)

Line range hint 1-11: Document the interface changes, sensei!

The removal of dojo_name, version, layout, and schema methods represents a significant change to the interface. Consider updating the doc comments to:

  1. Explain why these methods were removed
  2. Document how the upgradability checks work
  3. Guide users on handling model upgrades
 /// The `IModel` starknet interface.
 ///
 /// This is the interface used by offchain components and other contracts
- /// to interact with deployed models.
+ /// to interact with deployed models.
+ ///
+ /// # Model Upgrades
+ /// Models can be upgraded by deploying a new classhash while following these rules:
+ /// - Layout type (Struct/Fixed) must remain the same
+ /// - Existing fields cannot be changed or moved
+ /// - New fields can only be appended at the end
crates/dojo/core/src/event/event.cairo (1)

11-21: Architectural consideration for event upgradability, sensei!

The switch to Struct return type for schema() provides better structural guarantees for event upgradability checks. This change will help enforce the conditions mentioned in the PR objectives:

  • Maintaining the same layout type
  • Preventing changes to existing fields
  • Allowing new fields only at the end

Consider adding documentation that explicitly states these upgrade constraints in the trait documentation. Would you like me to provide a suggested documentation block?

crates/dojo/core/src/meta/interface.cairo (2)

4-11: Excellent interface design, sensei!

The IDeployedResource interface is well-documented and follows the single responsibility principle. The dojo_name method will be crucial for resource identification during upgrades.

Consider documenting the expected format or constraints of the returned ByteArray in the method documentation, if any exist.


13-21: Well-structured interface for upgrade validation, sensei!

The IStoredResource interface is perfectly aligned with the PR objectives, providing methods to verify upgrade constraints (layout type consistency and field positions).

Consider enhancing the documentation with:

  • Method-level documentation explaining the purpose of layout and schema
  • Examples of how these methods support upgrade validation
  • Return value descriptions
 /// The `IStoredResource` starknet interface.
 ///
 /// This is the interface used by offchain components and other contracts
 /// to access to storage related data of a deployed resource.
 #[starknet::interface]
 pub trait IStoredResource<T> {
+    /// Returns the layout type (Struct or Fixed) of the resource.
+    /// Used to ensure layout consistency during upgrades.
     fn layout(self: @T) -> Layout;
+
+    /// Returns the resource's schema definition.
+    /// Used to validate field positions and additions during upgrades.
     fn schema(self: @T) -> Struct;
 }
crates/dojo/core/src/model/component.cairo (2)

5-11: Clean separation of deployed model concerns, sensei!

The introduction of IDeployedModelImpl effectively separates the deployed model interface, which is crucial for the new upgradability system. The dojo_name method provides a stable identifier for models across upgrades.

This separation of deployed and stored model traits provides a solid foundation for managing model upgrades while maintaining consistent identification.


Line range hint 27-39: Clean removal of versioning, sensei!

The implementation correctly removes the version management while maintaining essential model metadata methods. This aligns perfectly with the PR objective to remove versioning management from the system.

The retained methods (unpacked_size, packed_size, and definition) provide sufficient metadata for model management without the complexity of version tracking.

crates/dojo/core/src/model/definition.cairo (1)

32-34: Confirm removal of versioning is handled properly.

The removal of the version field from ModelDef aligns with the PR objective to remove versioning management. However, we should ensure this change is handled gracefully in existing deployments.

Consider documenting the migration path for existing deployments that might be relying on version information. This could include:

  1. How to handle existing deployed models with versions
  2. Guidelines for upgrading without version checks
  3. New upgrade validation rules based on layout and field positions
crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (1)

18-24: Nice refactoring of contract implementations, sensei!

The changes effectively:

  1. Remove versioning through the empty IContract implementation
  2. Add resource identification via IDeployedResource implementation

This aligns perfectly with the PR's goal of removing versioning while enhancing upgradability management.

Consider documenting these changes in the module-level documentation to help other developers understand the new contract lifecycle and resource management approach.

crates/dojo/core/src/meta/layout.cairo (2)

25-38: Ohayo! The implementation looks clean and effective, sensei!

The is_same_type_of implementation correctly handles all Layout variants and provides a solid foundation for upgradability checks. However, consider adding documentation to explain its role in the upgrade process.

Add documentation above the trait:

+/// Trait for comparing Layout types during resource upgrades.
+/// Used to ensure that new versions maintain the same layout type as their predecessors.
 #[generate_trait]
 pub impl LayoutCompareImpl of LayoutCompareTrait {

27-37: Consider enhancing type comparison for stricter validation, sensei!

While the current implementation checks layout types, it might be beneficial to add methods for comparing internal structures (e.g., field order in Struct, array element types) to enforce the PR's requirement that "existing fields cannot be changed or moved".

Consider adding a method like:

fn is_compatible_with(self: @Layout, old: @Layout) -> bool {
    if !self.is_same_type_of(old) {
        return false;
    }
    match (self, old) {
        (Layout::Struct(new_fields), Layout::Struct(old_fields)) => {
            // Check if old fields exist in same order
            if old_fields.len() > new_fields.len() {
                return false;
            }
            let mut i = 0;
            loop {
                if i >= old_fields.len() {
                    break true;
                }
                if new_fields[i] != old_fields[i] {
                    break false;
                }
                i += 1;
            }
        },
        // Add similar checks for other variants
        _ => true
    }
}
crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (1)

64-64: Nice architectural split of event implementations, sensei!

The separation into DeployedEventImpl, StoredEventImpl, and EventImpl provides better modularity and clearer responsibility boundaries. This change aligns with the removal of versioning while maintaining proper event handling capabilities.

Consider documenting the specific responsibilities of each implementation type in the module-level documentation to help other developers understand when to use each variant.

Also applies to: 66-67, 69-70

crates/dojo/core-cairo-test/src/lib.cairo (2)

43-50: Ohayo! Clean modular structure for test helpers!

The new helpers module provides a well-organized structure for test utilities. The exports are clearly named and follow good patterns for test resources.

Consider grouping the exports by their purpose (e.g., contracts, models, utilities) to make it even more maintainable as the test suite grows.


72-78: Clean up commented modules, sensei!

While the new module structure looks good, there are some commented-out module declarations that should be addressed:

  • //mod entities;
  • //mod world;

Either remove them if they're no longer needed or add a TODO comment explaining why they're kept.

crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (3)

6-30: Well-structured test with comprehensive assertions, sensei!

The test thoroughly verifies both state changes and event emissions. Consider extracting the test address 0xb0b to a constant for reuse across tests.

+const BOB_ADDRESS: felt252 = 0xb0b;
+
 #[test]
 fn test_register_namespace() {
     let world = deploy_world();
 
-    let bob = starknet::contract_address_const::<0xb0b>();
+    let bob = starknet::contract_address_const::<BOB_ADDRESS>();
     starknet::testing::set_account_contract_address(bob);

32-43: Consider extracting common setup code, sensei!

The setup code is duplicated across tests. Consider creating a helper function to reduce duplication.

+fn setup_test_caller(address: felt252) -> IWorldDispatcher {
+    let world = deploy_world();
+    let caller = starknet::contract_address_const::<address>();
+    starknet::testing::set_account_contract_address(caller);
+    starknet::testing::set_contract_address(caller);
+    world
+}
+
 #[test]
 #[should_panic(expected: ("Namespace `namespace` is already registered", 'ENTRYPOINT_FAILED',))]
 fn test_register_namespace_already_registered_same_caller() {
-    let world = deploy_world();
-
-    let bob = starknet::contract_address_const::<0xb0b>();
-    starknet::testing::set_account_contract_address(bob);
-    starknet::testing::set_contract_address(bob);
+    let world = setup_test_caller(BOB_ADDRESS);

64-76: Consider expanding invalid namespace test cases, sensei!

While testing empty namespace is good, consider adding more test cases for invalid characters based on the regex pattern ^[a-zA-Z0-9_]+$.

Would you like me to help generate additional test cases for invalid namespaces? For example:

  • Spaces in name
  • Special characters
  • Starting with numbers
  • Unicode characters

Also, the gas limit of 6000000 seems high for a validation test. Consider profiling to determine a more appropriate limit.

crates/dojo/core/src/lib.cairo (1)

25-30: Ohayo! The new resource interfaces look well-structured.

The introduction of IDeployedResource and IStoredResource interfaces aligns perfectly with the PR's objective of implementing upgradability checks. These interfaces will help manage the upgrade process by providing clear contracts for deployed and stored resources.

Consider adding documentation comments to explain the upgrade constraints (same layout type, no field changes/movements, append-only new fields) directly in these interfaces.

crates/dojo/core/src/world/errors.cairo (1)

85-87: Consider adding more context to the layout upgrade error message.

While the message is consistent with other errors, it could be more helpful by indicating what makes the layout invalid (e.g., whether it's due to field reordering, type changes, etc.).

-    format!("Invalid new layout to upgrade the resource `{}-{}`", namespace, name)
+    format!("Invalid new layout to upgrade the resource `{}-{}`. Layout type must remain the same and existing fields cannot be modified", namespace, name)
crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (3)

6-17: Consider adding event verification.

The test validates metadata storage but doesn't verify if the appropriate MetadataUpdate event was emitted. Consider adding event verification similar to the one in test_set_metadata_resource_owner.

 world.set_metadata(metadata.clone());
 assert(world.metadata(0) == metadata, 'invalid metadata');
+
+let event = starknet::testing::pop_log::<world::Event>(world.contract_address);
+assert(event.is_some(), 'no event');
+
+if let world::Event::MetadataUpdate(event) = event.unwrap() {
+    assert(event.resource == metadata.resource_id, 'bad resource');
+    assert(event.uri == metadata.metadata_uri, 'bad uri');
+}

52-74: Consider adding post-failure metadata verification.

While the test correctly verifies that writers cannot set metadata, it would be valuable to assert that the metadata remains unchanged after the failed attempt.

+let original_metadata = world.metadata(model_selector);
 world.set_metadata(metadata.clone());
+assert(world.metadata(model_selector) == original_metadata, 'metadata changed');

96-114: Consider enhancing security test documentation.

While the test effectively validates protection against malicious contracts, it would be valuable to add comments explaining:

  1. Why contract deployment status is checked
  2. The potential security implications of allowing non-deployed contracts
+    // Even if an account has owner permissions, they cannot update metadata
+    // through a non-deployed contract address. This prevents potential
+    // security risks from malicious contracts masquerading as legitimate ones.
     world.set_metadata(metadata.clone());
crates/dojo/core/src/model/model.cairo (1)

Line range hint 91-109: Consider documenting the upgradability constraints, sensei!

The removal of versioning and the switch to Struct type supports the new upgradability checks. However, since this is a core change in how models can be upgraded, consider adding documentation about:

  • The requirement to maintain the same layout type
  • The prohibition of modifying existing fields
  • The rule about appending new fields only at the end

This will help developers understand the constraints when designing their models for future upgradability.

crates/dojo/core-cairo-test/src/tests/contract.cairo (1)

64-68: Excellent implementation of IDeployedResource, sensei!

The new Contract_DeployedContractImpl implementation properly identifies the contract as a deployed resource, which is essential for the new upgradability system.

Consider adding a brief comment explaining that this is a test implementation, like:

 #[abi(embed_v0)]
+// Test implementation of IDeployedResource for contract upgradability testing
 pub impl Contract_DeployedContractImpl of IDeployedResource<ContractState> {
crates/torii/types-test/src/contracts.cairo (1)

Line range hint 139-152: Ohayo! Some concerns about the delete implementation, sensei!

The delete function has several issues that need attention:

  1. The assumption that subrecord_id = record_id + 1 is unsafe and might lead to incorrect deletions
  2. Missing error handling for non-existent records
  3. No events are emitted for tracking deletion operations
  4. No transaction safety if deletion fails midway

Here's a suggested improvement:

fn delete(ref self: ContractState, record_id: u32) {
    let mut world = self.world(@"types_test");

+    // Verify record exists before proceeding
+    assert(world.model_exists<Record>(record_id), 'Record does not exist');
+
    let record: Record = world.read_model(record_id);
    let record_sibling: RecordSibling = world.read_model(record_id);

-    let subrecord_id = record_id + 1;
+    // Read all subrecords associated with this record_id
+    let subrecords = world.get_models<Subrecord>((record_id));

    world.erase_model(@record);
    world.erase_model(@record_sibling);
-    world.erase_model(@subrecord);
+    // Delete all associated subrecords
+    subrecords.iter().for_each(|subrecord| {
+        world.erase_model(@subrecord);
+    });

+    // Emit deletion event
+    world.emit_event(
+        @RecordDeleted { record_id }
+    );
}

Would you like me to help create a GitHub issue to track these improvements?

crates/dojo/lang/src/attribute_macros/element.rs (1)

Line range hint 16-23: Ohayo! Consider updating the trait documentation, sensei.

With the removal of versioning, the documentation for StructParameterParser should be updated to reflect that it now focuses solely on model and event attribute parsing without version management.

crates/dojo/lang/src/attribute_macros/event.rs (1)

56-63: Consider enhancing the warning message with valid parameter options.

The warning message could be more helpful by listing the valid parameters that are supported.

- "Unexpected parameter {} for {attribute_name}.",
+ "Unexpected parameter {} for {attribute_name}. Only 'historical' parameter is supported.",
crates/dojo/lang/src/attribute_macros/model.rs (3)

Line range hint 31-70: Consider adding upgradability validation checks, sensei!

While the existing validation logic is solid, consider adding checks to enforce the upgradability constraints mentioned in the PR objectives:

  • Validate layout type consistency (Struct/Fixed)
  • Ensure no modifications to existing field positions
  • Verify new fields are only appended at the end

This would prevent invalid model upgrades at compile-time rather than runtime.

Would you like help implementing these additional validation checks?


Line range hint 72-185: Add documentation about upgradability implications.

The code generation logic is robust, but it would be helpful to add documentation explaining:

  • How the generated code handles model upgrades
  • Impact on storage layout
  • Compatibility considerations for existing deployments

This documentation would be valuable for developers implementing upgradeable models.

Example documentation to add above the from_struct function:

/// Generates code for a Dojo model, ensuring upgradability constraints:
/// - Maintains layout type consistency (Struct/Fixed)
/// - Preserves existing field positions
/// - Allows new fields only at the end of the resource
/// 
/// Note: Model versioning is not supported as upgrades are handled through
/// classhash deployment while maintaining backward compatibility.

Line range hint 187-208: Consider documenting accessor stability guarantees.

The field accessor generation is solid, but it would be helpful to document that:

  • Field selectors remain stable across upgrades
  • Accessors maintain backward compatibility
  • New fields don't affect existing accessor behavior

This helps developers understand the implications of model upgrades on their accessor usage.

crates/dojo/core/src/event/component.cairo (1)

26-31: Ohayo, sensei! Consider adding documentation comments to IEventImpl for clarity.

Including documentation comments for the definition method would enhance readability and assist other developers in understanding its purpose and usage.

Apply this diff to add a documentation comment:

 pub impl IEventImpl<TContractState, E, +Event<E>> of IEvent<TContractState> {
+    /// Returns the event definition containing name, schema, and layout.
     fn definition(self: @TContractState) -> EventDefinition {
         Event::<E>::definition()
     }
 }
crates/dojo/core/src/meta/introspect.cairo (1)

49-59: Consider using a for loop for cleaner iteration

Ohayo, sensei! To enhance readability and follow idiomatic practices, you might replace the manual loop with a for loop that iterates over the indices of old.children.

Here's how you could refactor the code:

 let mut i = 0;

-loop {
-    if i >= (*old.children).len() {
-        break true;
-    }
-
-    if *old.children[i] != *self.children[i] {
-        break false;
-    }
-
-    i += 1;
-}
+for i in 0..(*old.children).len() {
+    if *old.children[i] != *self.children[i] {
+        return false;
+    }
+}
+return true;
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (3)

7-10: Ohayo, sensei! Typo in comment: 'differenciate' should be 'differentiate'

There's a misspelling in the comment. The correct spelling is "differentiate."


80-228: Ohayo, sensei! Consider refactoring to reduce code duplication in modules

The implementations of DeployedEventImpl and StoredImpl are similar across different modules. Refactoring these implementations could improve maintainability and reduce repetition.


100-100: Enhance panic messages for better debugging

Consider providing more informative panic messages to aid in identifying issues during runtime.

For example, in line 100~:

- panic!("Unexpected schema.")
+ panic!("Unexpected schema: expected a struct type for FooEventBadLayoutType.")

Also applies to: 130-130, 160-160, 190-190, 220-220

crates/dojo/core-cairo-test/src/tests/world/event.cairo (3)

13-16: Refactor repeated setup code into a helper function

Ohayo, sensei! I noticed that the setup code for initializing bob and deploying the world is repeated in multiple test functions. To enhance maintainability and reduce duplication, consider refactoring this code into a helper function.

Here's an example of how you could refactor:

fn setup_bob_as_owner() -> (ContractAddress, IWorldDispatcherTrait) {
    let bob = starknet::contract_address_const::<0xb0b>();
    let world = deploy_world();
    world.grant_owner(DOJO_NSH, bob);
    (bob, world)
}

Then, in your test functions, you can use:

let (bob, world) = setup_bob_as_owner();

Also applies to: 50-53


25-25: Fix typo in assertion message

Ohayo, sensei! There's a small typo in your assertion message. The closing parenthesis is unnecessary.

Please update the assertion as follows:

- assert(event.is_some(), 'no event)');
+ assert(event.is_some(), 'no event');

77-77: Fix typo in assertion message

Ohayo, sensei! Found another small typo in your assertion message.

Please correct it as follows:

- assert(event.is_some(), 'no event)');
+ assert(event.is_some(), 'no event');
crates/dojo/core/src/world/world_contract.cairo (2)

975-1011: Ohayo sensei! The assert_resource_upgradability function strengthens upgrades

Implementing assert_resource_upgradability enhances the upgrade process by enforcing layout and schema compatibility. Consider adding unit tests to cover various upgrade scenarios and edge cases.


1028-1040: Ensure safe access to dojo_name() in error handling

In panic_with_details, accessing dojo_name() assumes the resource is a deployed Dojo contract. To prevent potential runtime errors, verify the resource type before calling dojo_name() or handle exceptions appropriately.

crates/dojo/core-cairo-test/src/tests/world/model.cairo (1)

20-23: Ohayo, sensei! Refactor repetitive test setup code into a helper function

The code for setting the account and contract addresses is repeated in multiple test functions. Consider refactoring this code into a helper function to improve maintainability and reduce duplication.

Also applies to: 70-71, 81-82, 205-206

crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1)

164-170: Refactor repeated test setup into a helper function

Ohayo sensei, I noticed that setting the account and contract address is repeated across multiple tests. To adhere to the DRY principle and enhance maintainability, consider refactoring this code into a helper function.

Apply this diff to create a helper function and replace the repeated code:

+fn set_test_account(contract_address: ContractAddress) {
+    starknet::testing::set_account_contract_address(contract_address);
+    starknet::testing::set_contract_address(contract_address);
+}

 // Usage in tests:
-set_account_contract_address(bob);
-set_contract_address(bob);
+set_test_account(bob);

Also applies to: 200-205, 257-263, 315-316, 336-337, 353-354

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 131cd89 and 25deaa8.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (38)
  • Cargo.toml (1 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (1 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (1 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (2 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
💤 Files with no reviewable changes (4)
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
✅ Files skipped from review due to trivial changes (1)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
🔇 Additional comments (55)
crates/dojo/core/src/contract/interface.cairo (1)

2-2: Ohayo sensei! Verify the impact of empty trait.

The removal of dojo_name leaves this trait empty. While this aligns with the PR objectives of removing versioning, we should verify existing implementations aren't broken.

✅ Verification successful

Ohayo sensei! The empty IContract trait is part of a larger refactoring

The removal of dojo_name from IContract is intentional as this functionality has been moved to the meta::interface module. The dojo_name method is now properly defined in crates/dojo/core/src/meta/interface.cairo, which provides a more organized structure for metadata-related functionality.

Key findings:

  • dojo_name is now centralized in the meta interface module
  • All existing implementations have been updated to use the new location
  • No direct implementations of the empty IContract trait were found, indicating clean refactoring
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for implementations of IContract to ensure they're updated
ast-grep --pattern 'impl IContract<$_> for $_'

# Search for any remaining references to dojo_name
rg "dojo_name" --type cairo

Length of output: 106


Script:

#!/bin/bash
# Search for implementations of IContract using ripgrep
rg "impl IContract"

# Search for any remaining references to dojo_name
rg "dojo_name"

# Find all cairo files to understand the codebase structure
fd "\.cairo$"

Length of output: 11986

crates/dojo/core/src/model/interface.cairo (2)

9-9: Ohayo! The fully qualified return type looks good, sensei!

Using the complete path dojo::model::ModelDef improves code clarity and prevents potential naming conflicts.


Line range hint 1-11: Verify implementation of upgradability checks, sensei!

The PR objectives mention specific conditions for model upgrades (same layout type, no field changes/movements, append-only new fields), but these constraints aren't visible in the interface. Let's verify where these checks are implemented.

crates/dojo/core/src/event/event.cairo (2)

1-2: Ohayo! Import changes look good, sensei!

The addition of Struct import aligns well with the schema type changes and supports the removal of versioning.


4-9: Schema type change looks good but needs verification, sensei!

The removal of versioning and switch to Struct type aligns with the PR objectives. However, we should verify the impact on existing events in the system.

✅ Verification successful

Ohayo! Schema change is safe to proceed, sensei! 🍃

The search results show that EventDefinition is being used consistently across the codebase, with no remaining version references. The struct is properly imported and implemented in various locations, and the new schema type appears to be correctly integrated into the existing event patterns.

  • All event definitions follow the new structure without version field
  • No legacy version references were found
  • Event implementations are properly using the updated EventDefinition struct
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing event implementations to ensure compatibility
echo "Checking for existing event implementations..."
rg -l "impl.*Event.*for" --type cairo

# Look for any remaining references to event versions
echo "Checking for any remaining version references in events..."
rg "version.*->.*u8" --type cairo

Length of output: 365


Script:

#!/bin/bash
# Search for event implementations using file extension .cairo
echo "Checking for existing event implementations..."
fd -e cairo -x rg -l "impl.*Event.*for" {}

# Look for any remaining version references in events
echo "Checking for any remaining version references..."
fd -e cairo -x rg "version.*->.*u8" {}

# Check for event usage patterns
echo "Checking event usage patterns..."
fd -e cairo -x rg "EventDefinition" {}

Length of output: 790

crates/dojo/core/src/meta/interface.cairo (1)

1-2: Ohayo! Clean and focused imports, sensei!

The imports are well-scoped and bring in exactly what's needed for the interfaces.

crates/dojo/core/src/model/component.cairo (2)

1-2: Ohayo! Clean and focused imports, sensei!

The imports are well-organized and precisely match the needs of the implementation changes, particularly the new Struct type from dojo::meta::introspect.


14-24: 💡 Codebase verification

Excellent schema type refinement for upgradability checks, sensei!

The change from Ty to Struct in the schema method provides more precise type information, which is essential for implementing the upgradability constraints mentioned in the PR objectives (maintaining layout type and field ordering).

Let's verify the schema implementation across the codebase:

✅ Verification successful

Schema return type needs alignment across the codebase, sensei!

The verification reveals inconsistencies in schema return types. While the core component implementation has been updated to return Struct, there are multiple locations still using Ty:

  • World contracts and abigen code (crates/dojo/world/src/contracts/)
  • Test data in lang crate (crates/dojo/lang/src/plugin_test_data/)
  • Torii core implementation (crates/torii/core/src/model.rs)

Let's verify if this is part of a planned migration or if these need to be updated:


Ohayo! Schema migration is in progress, sensei!

The verification shows this is part of an ongoing migration from Ty to Struct. We can see:

  1. Core interfaces and implementations now use Struct (crates/dojo/core/src/)
  2. Migration patches exist in the lang crate (crates/dojo/lang/src/attribute_macros/patches/)
  3. Test implementations have been updated (crates/dojo/core-cairo-test/)

However, external facing APIs (world, torii) still use Ty, suggesting a bottom-up migration approach. This is a valid architectural pattern for maintaining backward compatibility during transitions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining Ty usages in schema-related code
# and verify consistent usage of Struct type

# Search for any remaining Ty usage in schema contexts
rg -A 2 'fn schema.*->.*Ty'

# Verify Struct usage in schema implementations
ast-grep --pattern 'fn schema($$$) -> Struct { $$ }'

Length of output: 6071


Script:

#!/bin/bash
# Check for any recent commits or PRs mentioning schema type changes
git log --grep="schema.*Ty.*Struct" --pretty=format:"%h %s" -n 5
git log --grep="upgradability.*schema" --pretty=format:"%h %s" -n 5

# Check if there are any other Struct return types in schema implementations
rg -A 2 'fn schema.*->.*Struct'

Length of output: 7039

crates/dojo/core/src/model/definition.cairo (1)

1-1: LGTM! Clean import update.

Ohayo! The import change from Ty to Struct aligns well with the PR's objective of implementing stricter model upgradability checks.

crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (1)

6-6: Ohayo! Clean addition of IDeployedResource import.

The import aligns well with the new resource management approach for handling upgradability checks.

crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (1)

22-28: Ohayo! Runtime type checking enhancement looks good, sensei!

The schema function now properly enforces the Struct type requirement and provides a clear error message. This aligns well with the PR's objective of maintaining layout type consistency.

crates/dojo/core-cairo-test/src/lib.cairo (2)

60-67: Excellent parallel structure between model and event tests!

The model test exports mirror the event testing structure, maintaining consistency in the testing approach. The 'm_' prefix convention is well maintained.

Let's verify the parallel implementation:

✅ Verification successful

Perfect parallel structure confirmed, sensei!

The verification shows exact mirroring between event and model test structures:

  • Both have identical test cases: BadLayoutType, MemberRemoved, MemberAddedButRemoved, MemberAddedButMoved, and MemberAdded
  • Event tests use e_ prefix while model tests use m_ prefix consistently
  • Test implementations follow the same patterns for both events and models in the world upgrade scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify that model tests match event test patterns
echo "=== Event Tests ==="
rg "FooEvent.*" --type cairo
echo "=== Model Tests ==="
rg "FooModel.*" --type cairo

Length of output: 219


Script:

#!/bin/bash
# Let's try without file type specification
echo "=== Event Tests ==="
rg "FooEvent"
echo "=== Model Tests ==="
rg "FooModel"

Length of output: 11090


52-58: Well-structured event test cases for upgradability, sensei!

The event test exports provide comprehensive coverage for various upgrade scenarios:

  • Layout type validation
  • Member removal checks
  • Member addition and position validation

Let's verify the test coverage:

✅ Verification successful

The previous command failed due to file type restrictions. Let's try a broader search to find the test implementations and verify the event test coverage. I'm using multiple approaches to ensure we catch all relevant code:

  1. Direct function search without file type restriction
  2. General search for FooEvent occurrences
  3. AST-based search for test functions

These should help us verify if the exported event test cases have corresponding implementations.


Event test coverage is comprehensive and well-implemented, sensei!

The verification shows that all exported event types have corresponding test implementations in tests/world/event.cairo:

  • FooEventBadLayoutType: Tests invalid layout upgrades
  • FooEventMemberRemoved: Verifies member removal scenarios
  • FooEventMemberAddedButRemoved: Tests member addition/removal cases
  • FooEventMemberAddedButMoved: Validates member position changes
  • FooEventMemberAdded: Tests basic member addition functionality

Each event type has proper struct definitions, test implementations, and upgrade validation, perfectly aligned with the exported types in the module.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify that all event test cases have corresponding test implementations
rg -A 2 "fn test.*Event.*upgrade" 

Length of output: 219


Script:

#!/bin/bash
# Search for event test implementations without file type restriction
rg -A 2 "fn test.*Event.*upgrade"

# Search for FooEvent-related code
rg "FooEvent" -A 3

# Look for test functions in the event module
ast-grep --pattern 'fn test_$_($$$) {
  $$$
}'

Length of output: 14241

crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (2)

1-4: Ohayo sensei! Clean and well-organized imports.

The imports are properly structured, separating core functionality from test helpers.


45-61: Excellent edge case coverage, sensei!

The test properly verifies that namespace ownership is exclusive, regardless of the caller.

crates/dojo/core/src/lib.cairo (2)

12-13: Ohayo sensei! Please verify the purpose of the new event component module.

The addition of the component module under events suggests a more modular approach. Could you confirm if this module contains the upgradability check logic for events?


32-32: The comparison traits are a great addition for upgrade safety!

The StructCompareTrait and LayoutCompareTrait exports are essential for implementing the upgrade constraints. They'll help ensure that:

  1. Layout types remain the same
  2. Existing fields aren't changed or moved
  3. New fields are only appended at the end

Also applies to: 35-35

✅ Verification successful

Ohayo sensei! The comparison traits are indeed well-implemented for upgrade safety! ✨

The implementation confirms that:

  • StructCompareTrait properly verifies:
    • Same struct name and attributes
    • No removal of existing fields (length check)
    • Exact match of existing fields in same order
  • LayoutCompareTrait ensures type compatibility across:
    • Fixed types
    • Structs
    • Tuples
    • Arrays
    • ByteArrays
    • Enums

This provides strong guarantees for safe contract upgrades by preventing breaking changes to existing structures.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of comparison traits
# Expected: Find trait definitions with comparison logic

# Check StructCompareTrait implementation
ast-grep --pattern 'trait StructCompareTrait {
  $$$
}'

# Check LayoutCompareTrait implementation
ast-grep --pattern 'trait LayoutCompareTrait {
  $$$
}'

Length of output: 115


Script:

#!/bin/bash
# Let's try searching for the trait definitions with ripgrep instead
# Search for StructCompareTrait
rg -A 10 "trait StructCompareTrait" 

# Search for LayoutCompareTrait
rg -A 10 "trait LayoutCompareTrait"

# Also search for any struct comparison related functions/implementations
rg -A 5 "impl.*Compare"

Length of output: 1189


Script:

#!/bin/bash
# Let's check the full trait definitions and their usage
rg -B 5 -A 15 "trait (StructCompareTrait|LayoutCompareTrait)"

# Also check the full implementation of LayoutCompareImpl
rg -B 5 -A 15 "impl LayoutCompareImpl"

# And the full implementation of StructCompareImpl
rg -B 5 -A 15 "impl StructCompareImpl"

Length of output: 3160

crates/dojo/core/src/world/errors.cairo (2)

81-83: Ohayo! Clean and consistent error message formatting, sensei!

The error message follows the established pattern and clearly identifies the resource using the namespace-name combination.


89-93: Verify if version upgrade check is still needed.

According to the PR objectives, versioning management is being removed from the system. This error message seems to contradict that goal by implementing version-specific checks.

crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (3)

1-4: LGTM! Imports are well-organized.

Ohayo sensei! The imports are properly structured with clear separation between core functionality and test helpers.


19-50: Well-structured test with comprehensive checks!

The test thoroughly validates both the metadata update and event emission. Good use of drop_all_events for clean event testing.


76-94: Excellent security validation, sensei!

The test effectively validates that unauthorized accounts cannot modify world metadata, with clear documentation of the conventional ACL behavior.

crates/dojo/core/src/model/model.cairo (2)

1-3: Ohayo! Import changes look good, sensei!

The switch from Ty to Struct aligns well with the new schema representation approach, and the addition of compute_packed_size maintains proper dependency management.


39-39: Schema type change needs verification across implementations, sensei!

The change from Ty to Struct as the return type provides better type safety and structure validation, which aligns with the upgradability checks mentioned in the PR objectives.

Let's verify all implementations are updated:

✅ Verification successful

Ohayo! Schema change is properly aligned across implementations, sensei!

The change from Ty to Struct in the Model trait is correctly reflected in all implementations. The ModelDefinition trait and ModelImpl both use Struct as the return type for schema(), and the test files in plugin_test_data are just test fixtures that don't affect runtime behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining Ty usage in schema implementations
rg -l "fn schema\(\).*->.*Ty" 

# Search for any potential custom implementations of the Model trait
ast-grep --pattern 'impl $_ of Model<$_>'

Length of output: 163


Script:

#!/bin/bash
# Let's check the actual content of these files to understand the context
echo "=== Content of model file ==="
cat "crates/dojo/lang/src/plugin_test_data/model"

echo -e "\n=== Content of event file ==="
cat "crates/dojo/lang/src/plugin_test_data/event"

# Let's also check if there are any schema implementations with the new Struct return type
rg "fn schema\(\).*->.*Struct"

Length of output: 482625


Script:

#!/bin/bash
# Let's check the actual content of these files to understand the schema() implementation
echo "=== Content of model.cairo ==="
cat "crates/dojo/core/src/model/model.cairo"

echo -e "\n=== Content of model/definition.cairo ==="
cat "crates/dojo/core/src/model/definition.cairo"

Length of output: 5943

crates/dojo/core-cairo-test/src/tests/contract.cairo (2)

37-37: Ohayo! The import looks good, sensei!

The addition of IDeployedResource import aligns perfectly with the PR's objective of implementing resource upgradability checks.


62-62: Verify the empty contract implementation, sensei!

The empty ContractImpl implementation suggests removal of previous functionality. While this aligns with removing versioning management, we should verify this doesn't break existing contract behavior.

✅ Verification successful

Let me search for the IContract trait definition to understand what methods are expected to be implemented.


Ohayo! Empty ContractImpl is perfectly fine, sensei!

The IContract<T> trait in crates/dojo/core/src/contract/interface.cairo is defined as an empty trait with no required methods. The empty implementation aligns with the trait's definition and is intentional.

Looking at the test files and examples, we can see that the actual contract functionality is implemented through other traits like IDeployedResource, while IContract serves as a marker trait.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any direct usage of removed IContract methods
rg -A 3 "ContractImpl" 

Length of output: 57352


Script:

#!/bin/bash
# Search for IContract trait definition
rg -A 10 "trait IContract"

Length of output: 2431

crates/torii/types-test/src/contracts.cairo (1)

111-112: Ohayo! Clean and readable event emission, sensei!

The method chaining approach improves code readability while maintaining the same functionality.

crates/dojo/lang/src/attribute_macros/element.rs (2)

7-7: Ohayo! LGTM on the imports!

The import organization looks clean and properly structured, sensei.


Line range hint 24-67: Verify parameter parsing behavior after version removal.

The load_from_struct implementation looks solid, but we should verify that all attribute parameters are still correctly processed without the version handling logic.

Let's check for any existing usages that might expect version handling:

✅ Verification successful

Based on the search results, I can now generate the final response since I have enough information to verify the parameter parsing behavior after version removal.

Parameter parsing is working correctly without version handling

The search results show that the version parameter has been properly removed from production code, and all current attribute usages follow the correct parameter patterns:

  • Events use namespace and historical parameters
  • Models use namespace parameter
  • No active usages of version parameter in production code

The test files appropriately handle validation of incorrect version usage:

#[dojo::model(version: 0)] // Properly caught as error
#[dojo::model(version: hello)] // Properly caught as error
#[dojo::model(version)] // Properly caught as error
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for attribute usage patterns that might have depended on version parameter
rg -A 3 '#\[dojo::(model|event)' 

# Look for any remaining version-related code
rg -i 'version|versioning' --type rust

Length of output: 75519

crates/dojo/lang/src/attribute_macros/event.rs (3)

Line range hint 20-40: Ohayo! Clean simplification of EventParameters, sensei!

The removal of the common field and simplified Default implementation aligns well with the PR objective of removing versioning management. The structure is now more focused and maintainable.


Line range hint 142-170: Excellent derive attribute handling, sensei!

The implementation ensures proper derive attributes by:

  • Preventing IntrospectPacked usage
  • Automatically adding Introspect if missing
  • Providing clear error messages

This helps maintain consistency across event definitions.


Line range hint 71-198: Add validation for upgradability constraints, sensei!

The implementation has robust validation for event structure, but it's missing checks for the upgradability constraints mentioned in the PR objectives:

  • Maintaining the same layout type
  • Preventing changes to existing fields
  • Ensuring new fields are only appended at the end

Consider adding validation to ensure:

  1. Layout type consistency between versions
  2. Field order preservation
  3. New fields are only appended at the end

Would you like assistance in implementing these checks?

crates/dojo/lang/src/attribute_macros/model.rs (1)

18-19: Ohayo sensei! Import changes look good!

The simplified imports align well with the removal of versioning management while retaining essential model functionality.

crates/dojo/core/src/event/component.cairo (2)

4-11: Ohayo, sensei! Great implementation of IDeployedEventImpl.

The dojo_name method is properly implemented, correctly returning the event name using Event::<E>::name(). This aligns well with the IDeployedResource interface requirements.


13-24: Ohayo, sensei! The IStoredEventImpl is implemented excellently.

Both schema and layout methods are accurately defined, providing essential metadata by delegating to Event::<E>::schema() and Event::<E>::layout(). This ensures that the stored event's structure and memory layout are retrievable as expected.

crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (4)

14-17: Implementation of DojoDeployedModelImpl is correct in attacker_contract.

Ohayo, sensei! The implementation of DojoDeployedModelImpl for IDeployedResource<ContractState> in attacker_contract correctly defines the dojo_name method as "test_1".


27-31: Implementation of DojoDeployedModelImpl is correct in attacker_model.

Ohayo, sensei! The implementation of DojoDeployedModelImpl for IDeployedResource<ContractState> in attacker_model correctly defines the dojo_name method as "foo".


33-42: Ensure layout and schema methods meet upgradability requirements.

Ohayo, sensei! The layout method returns a fixed layout with an empty array, and the schema method returns an empty Struct named 'm1'. Please verify that these definitions comply with the new upgradability conditions, specifically maintaining the same layout type and correctly defining fields to prevent issues during model upgrades.


Line range hint 44-63: Implementation of DojoModelImpl aggregates components correctly.

Ohayo, sensei! The DojoModelImpl correctly implements IModel<ContractState> and aggregates the name, layout, and schema from DojoDeployedModelImpl and DojoStoredModelImpl. This aligns with the upgradability checks introduced in this PR.

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (2)

33-39: Ohayo, sensei! Excellent update to the schema function.

The use of pattern matching to ensure that dojo::meta::introspect::Ty::Struct is correctly handled enhances the robustness of the schema function. The panic with a clear message in the else branch provides good error handling for invalid schemas.


84-89: Ohayo, sensei! Great addition of IDeployedModelImpl and IStoredModelImpl implementations.

Implementing IDeployedModelImpl and IStoredModelImpl for $model_type$ aligns with the new resource management strategies. The inclusion of #[abi(embed_v0)] ensures proper ABI embedding, which is crucial for contract interactions.

crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1)

63-78: Well-implemented deploy_world_for_event_upgrades function

The function correctly sets up the test world with the specified event resources for upgrade testing.

crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (6)

14-19: Ohayo, sensei! The base model looks solid.

The definition of FooBaseModel is correctly implemented.


77-92: Ohayo, sensei! The deploy_world_for_model_upgrades function is well-crafted.

The function properly constructs the test world with the specified namespace and resources.


137-146: Ohayo, sensei! Potential inconsistency in schema generation

Similar to the previous comment, in old_foo_model_member_removed, the schema function introspects FooBaseModel instead of FooModelMemberRemoved. This may lead to discrepancies between the schema and the actual struct. It's advisable to introspect FooModelMemberRemoved directly.


167-176: Ohayo, sensei! Potential inconsistency in schema generation

Once again, in old_foo_model_member_added_but_removed, the schema function is using FooBaseModel for introspection. To maintain accuracy, please introspect FooModelMemberAddedButRemoved instead.


197-206: Ohayo, sensei! Potential inconsistency in schema generation

In old_foo_model_member_added_but_moved, the schema introspection targets FooBaseModel. For consistency and correctness, consider introspecting FooModelMemberAddedButMoved.


227-236: Ohayo, sensei! Potential inconsistency in schema generation

In the case of old_foo_model_member_added, the schema function should introspect FooModelMemberAdded directly rather than FooBaseModel to accurately reflect the struct's schema.

crates/dojo/core-cairo-test/src/tests/world/event.cairo (1)

229-230: ⚠️ Potential issue

Correct the #[should_panic] attribute syntax

Ohayo, sensei! The #[should_panic] attribute here has the same syntax issue. Let's fix it for consistency.

Update it like this:

- #[should_panic(expected: ('CONTRACT_NOT_DEPLOYED', 'ENTRYPOINT_FAILED',))]
+ #[should_panic(expected = "CONTRACT_NOT_DEPLOYED")]

Likely invalid or redundant comment.

crates/dojo/core/src/world/world_contract.cairo (6)

42-45: Ohayo sensei! The new imports improve code organization

The added imports from dojo::meta enhance modularity by bringing in necessary traits and structures for resource management.


357-357: Verify the correctness of entity_id_from_keys usage

Ensure that metadata.resource_id is the appropriate key when computing entity_id_from_keys([metadata.resource_id].span()) for setting metadata.


436-437: Ohayo sensei! Consistent use of IDeployedResourceDispatcher

Replacing the dispatcher with IDeployedResourceDispatcher standardizes resource handling. This improves code consistency when registering events.


508-512: Ohayo sensei! Validating resource upgradability enhances safety

The call to assert_resource_upgradability ensures that only compatible events are upgraded, maintaining system integrity and preventing potential runtime issues.


586-587: Ohayo sensei! Consistent dispatcher usage in model upgrades

Using IDeployedResourceDispatcher for model upgrades aligns with event handling, improving code consistency and readability.


612-615: Ohayo sensei! Ensuring model upgradability checks

The addition of assert_resource_upgradability in model upgrades safeguards against incompatible schema changes, preserving data integrity.

fn definition(self: @T) -> EventDefinition;
fn layout(self: @T) -> Layout;
fn schema(self: @T) -> Ty;
fn definition(self: @T) -> super::EventDefinition;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Ohayo! Breaking changes detected in the interface, sensei!

The removed methods (dojo_name, version, layout, schema) are actively used across multiple components:

  • layout and schema are used in:
    • crates/torii/core/src/processors/register_model.rs
    • crates/torii/core/src/processors/register_event.rs
    • crates/sozo/ops/src/model.rs
    • crates/dojo/world/src/contracts/model.rs
  • dojo_name is used in crates/dojo/lang/src/attribute_macros/contract.rs
  • These methods also have existing implementations in various files like crates/torii/core/src/model.rs and crates/dojo/world/src/contracts/model.rs

The removal of these methods will cause breaking changes in dependent code that needs to be addressed.

🔗 Analysis chain

Ohayo! The simplified interface looks clean, sensei!

The removal of dojo_name, version, layout, and schema methods aligns well with the PR objectives to eliminate versioning management. The explicit return type super::EventDefinition provides better clarity.

Let's verify the impact on existing implementations:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for existing implementations that might be affected by the removed methods

# Search for implementations of the removed methods
echo "Checking for existing implementations of removed methods..."
rg -A 2 "fn (dojo_name|version|layout|schema)\b.*\{" --type rust

# Search for calls to these methods
echo "Checking for calls to removed methods..."
rg "\.(dojo_name|version|layout|schema)\(" --type rust

Length of output: 4855

fn layout() -> Layout;
fn schema() -> Ty;
fn schema() -> Struct;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Breaking change confirmed in schema() return type

The change from Ty to Struct is indeed a breaking change that affects multiple parts of the codebase:

  • The plugin_test_data implementations return dojo::meta::introspect::Ty
  • The model patches in attribute_macros already expect Struct and handle the conversion from Ty
  • Multiple consumers call .schema() and depend on its return type
🔗 Analysis chain

Verify impact of schema return type change.

The change from Ty to Struct as the return type for schema() is a breaking change that could affect consumers of this trait.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential breaking changes in schema() usage
# Look for implementations and usages of schema() that might need updates

# Search for schema() implementations
echo "Checking schema() implementations:"
ast-grep --pattern 'fn schema() -> $return_type {
  $$$
}'

# Search for direct schema() calls
echo "Checking schema() usage:"
rg -l 'schema\(\)' 

Length of output: 1054


Script:

#!/bin/bash
# Let's check the actual implementations and usages in more detail

# Check implementations of schema() to see the return type changes
echo "=== Checking schema() implementations with context ==="
rg -A 5 "fn schema\(\) ->" 

# Check actual usage contexts of schema()
echo -e "\n=== Checking schema() usage contexts ==="
rg -B 2 -A 2 "\.schema\(\)"

# Look specifically for any Ty related usage that might be affected
echo -e "\n=== Checking for Ty related code ==="
rg "Ty" crates/dojo/core/src/model/definition.cairo

Length of output: 14115

Comment on lines 95 to 97
pub fn inconsistent_namespaces(old_hash: felt252, new_hash: felt252) -> ByteArray {
format!("Inconsistent namespaces (old: {old_hash} new: {new_hash}")
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix format string syntax error, sensei!

The format string is missing a closing brace after new_hash.

-    format!("Inconsistent namespaces (old: {old_hash} new: {new_hash}")
+    format!("Inconsistent namespaces (old: {old_hash} new: {new_hash})")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn inconsistent_namespaces(old_hash: felt252, new_hash: felt252) -> ByteArray {
format!("Inconsistent namespaces (old: {old_hash} new: {new_hash}")
}
pub fn inconsistent_namespaces(old_hash: felt252, new_hash: felt252) -> ByteArray {
format!("Inconsistent namespaces (old: {old_hash} new: {new_hash})")
}

Cargo.toml Outdated
Comment on lines 193 to 194
#scarb = { git = "https://github.com/remybar/scarb", rev = "e5011654899e3f48e3503973729d7b37a28f58be" }
#scarb-ui = { git = "https://github.com/remybar/scarb", rev = "e5011654899e3f48e3503973729d7b37a28f58be" }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

⚠️ Potential issue

Ohayo sensei! Local paths will break builds for other developers

The verification confirms that:

  1. The specified path /Users/remybaranx/pro/projets/contribs/dojo/scarb does not exist in the sandbox environment
  2. Multiple commented git dependencies show different sources (remybar/scarb, software-mansion/scarb, dojoengine/scarb)
  3. The scarb dependency is used across many workspace members

Please replace the local paths with the appropriate git dependency. You can:

  • Use the official software-mansion/scarb repository
  • Or use your fork if you need custom changes, but ensure the changes are pushed

Also, clean up the commented dependencies to maintain a cleaner configuration.

🔗 Analysis chain

Ohayo sensei! Please avoid hardcoded local paths in dependencies

The current configuration uses absolute paths specific to your local machine:

scarb = { path = "/Users/remybaranx/pro/projets/contribs/dojo/scarb/scarb" }
scarb-ui = { path = "/Users/remybaranx/pro/projets/contribs/dojo/scarb/utils/scarb-ui" }

This will break builds for other developers. Consider:

  1. Using relative paths if the scarb repository is meant to be developed locally
  2. Using the git dependency if this is temporary for development

Additionally, please clean up the commented-out dependency versions to maintain cleaner configuration.

Let's verify the scarb repository location:

Also applies to: 197-200

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if scarb exists at the specified path
if [ -d "/Users/remybaranx/pro/projets/contribs/dojo/scarb" ]; then
    echo "Found scarb repository"
else
    echo "Scarb repository not found at specified path"
fi

# Look for any other potential scarb references in the codebase
rg --type toml 'scarb.*='

Length of output: 2548

Comment on lines +49 to +61
fn schema(self: @ContractState) -> dojo::meta::introspect::Struct {
dojo::meta::introspect::Struct { name: 'foo', attrs: [].span(), children: [].span() }
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Inconsistency between schema name and dojo_name

Ohayo, sensei! The schema method returns a struct with name: 'foo', while the dojo_name method returns "foo-bis". To maintain consistency and prevent potential issues when referencing this resource, it's advisable to align the names in both methods.

Apply this diff to update the schema name:

-            dojo::meta::introspect::Struct { name: 'foo', attrs: [].span(), children: [].span() }
+            dojo::meta::introspect::Struct { name: 'foo-bis', attrs: [].span(), children: [].span() }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn schema(self: @ContractState) -> dojo::meta::introspect::Struct {
dojo::meta::introspect::Struct { name: 'foo', attrs: [].span(), children: [].span() }
}
}
fn schema(self: @ContractState) -> dojo::meta::introspect::Struct {
dojo::meta::introspect::Struct { name: 'foo-bis', attrs: [].span(), children: [].span() }
}
}

Comment on lines +322 to +341
#[should_panic(
expected: (
"Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`",
'ENTRYPOINT_FAILED',
)
)]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect usage of expected parameter in #[should_panic] attribute

Ohayo sensei, ensure the expected parameter is a string literal to prevent test failures.

Apply this diff to fix the issue:

-#[should_panic(
-    expected: (
-        "Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`",
-        'ENTRYPOINT_FAILED',
-    )
-)]
+#[should_panic(
+    expected = "Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`: ENTRYPOINT_FAILED"
+)]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[should_panic(
expected: (
"Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`",
'ENTRYPOINT_FAILED',
)
)]
#[should_panic(
expected = "Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`: ENTRYPOINT_FAILED"
)]

Comment on lines +225 to +233
#[should_panic(expected: ("Namespace `buzz_namespace` is not registered", 'ENTRYPOINT_FAILED',))]
fn test_deploy_contract_with_unregistered_namespace() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect usage of expected parameter in #[should_panic] attribute

Ohayo sensei, the expected parameter must be a string literal. Using a tuple may cause the test to fail improperly.

Apply this diff to fix the issue:

-#[should_panic(expected: ("Namespace `buzz_namespace` is not registered", 'ENTRYPOINT_FAILED',))]
+#[should_panic(expected = "Namespace `buzz_namespace` is not registered: ENTRYPOINT_FAILED")]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[should_panic(expected: ("Namespace `buzz_namespace` is not registered", 'ENTRYPOINT_FAILED',))]
fn test_deploy_contract_with_unregistered_namespace() {
#[should_panic(expected = "Namespace `buzz_namespace` is not registered: ENTRYPOINT_FAILED")]
fn test_deploy_contract_with_unregistered_namespace() {

Comment on lines +193 to +201
#[should_panic(
expected: ("Account `2827` does NOT have OWNER role on namespace `dojo`", 'ENTRYPOINT_FAILED',)
)]
fn test_deploy_contract_for_namespace_writer() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect usage of expected parameter in #[should_panic] attribute

Ohayo sensei, using a tuple for the expected parameter is not supported. It should be a single string literal to prevent compilation issues.

Apply this diff to fix the issue:

-#[should_panic(
-    expected: ("Account `2827` does NOT have OWNER role on namespace `dojo`", 'ENTRYPOINT_FAILED',)
-)]
+#[should_panic(expected = "Account `2827` does NOT have OWNER role on namespace `dojo`: ENTRYPOINT_FAILED")]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[should_panic(
expected: ("Account `2827` does NOT have OWNER role on namespace `dojo`", 'ENTRYPOINT_FAILED',)
)]
fn test_deploy_contract_for_namespace_writer() {
#[should_panic(expected = "Account `2827` does NOT have OWNER role on namespace `dojo`: ENTRYPOINT_FAILED")]
fn test_deploy_contract_for_namespace_writer() {

Comment on lines +290 to +307
#[should_panic(
expected: (
"Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`",
'ENTRYPOINT_FAILED',
)
)]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect usage of expected parameter in #[should_panic] attribute

Ohayo sensei, to avoid compilation errors, the expected parameter should be a single string.

Apply this diff to fix the issue:

-#[should_panic(
-    expected: (
-        "Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`",
-        'ENTRYPOINT_FAILED',
-    )
-)]
+#[should_panic(
+    expected = "Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`: ENTRYPOINT_FAILED"
+)]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[should_panic(
expected: (
"Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`",
'ENTRYPOINT_FAILED',
)
)]
#[should_panic(
expected = "Account `659918` does NOT have OWNER role on contract (or its namespace) `test_contract`: ENTRYPOINT_FAILED"
)]

Comment on lines +343 to +360
#[should_panic(expected: ('CONTRACT_NOT_DEPLOYED', 'ENTRYPOINT_FAILED',))]
fn test_upgrade_contract_through_malicious_contract() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect usage of expected parameter in #[should_panic] attribute

Ohayo sensei, the tuple in the expected parameter should be converted to a string literal for correct test execution.

Apply this diff to fix the issue:

-#[should_panic(expected: ('CONTRACT_NOT_DEPLOYED', 'ENTRYPOINT_FAILED',))]
+#[should_panic(expected = "CONTRACT_NOT_DEPLOYED: ENTRYPOINT_FAILED")]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[should_panic(expected: ('CONTRACT_NOT_DEPLOYED', 'ENTRYPOINT_FAILED',))]
fn test_upgrade_contract_through_malicious_contract() {
#[should_panic(expected = "CONTRACT_NOT_DEPLOYED: ENTRYPOINT_FAILED")]
fn test_upgrade_contract_through_malicious_contract() {

@remybar remybar force-pushed the upgradeable_models branch 2 times, most recently from 6d58b2c to df9efb8 Compare November 4, 2024 16:53
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (23)
crates/dojo/core/src/model/component.cairo (1)

5-11: Clean implementation of IDeployedModelImpl, sensei!

The separation between deployed and stored resources provides a clear boundary for upgrade management. This design choice aligns well with the PR's objective of implementing upgradability checks.

This separation will make it easier to enforce upgrade constraints, as deployed and stored aspects can be validated independently.

crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (1)

Line range hint 44-63: Clean architectural separation, sensei!

The refactored DojoModelImpl nicely delegates to the specialized implementations:

  • DojoDeployedModelImpl for name
  • DojoStoredModelImpl for layout and schema

This separation of concerns aligns well with the new resource management strategy and makes the code more maintainable.

Consider documenting these architectural patterns in the module-level documentation to help other developers understand the design decisions.

crates/dojo/core/src/lib.cairo (1)

25-35: Ohayo! Excellent architectural improvements, sensei!

The meta module changes introduce a robust foundation for resource upgradability:

  • New interface module with resource traits provides clear contracts for deployed and stored resources
  • Addition of compare traits (StructCompareTrait, LayoutCompareTrait) enables validation of upgradability conditions mentioned in PR objectives (same layout type, field preservation)

Consider documenting these interfaces as they form a critical part of the upgradability contract. They will serve as the primary reference for developers implementing upgradable models and events.

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (1)

33-39: Ohayo! The schema function changes look solid, sensei!

The stricter return type (Struct instead of Ty) and runtime type checking align well with the PR's goal of enforcing upgradability constraints. This change ensures that models maintain a consistent structure type, which is crucial for safe upgrades.

Consider documenting these structural constraints in the model's documentation to help other developers understand the upgrade limitations, particularly:

  • Same layout type requirement
  • No field modifications
  • New fields must be appended at the end
crates/torii/types-test/src/contracts.cairo (1)

Line range hint 116-131: Critical issues in delete implementation need attention!

Ohayo sensei! The delete implementation has several concerns that need to be addressed:

  1. The hardcoded subrecord_id = record_id + 1 assumption is dangerous and could lead to incorrect deletions
  2. Missing error handling for non-existent records
  3. No events are emitted for deletion operations
  4. No transaction safety - partial deletions could occur if any operation fails

Consider this improved implementation:

fn delete(ref self: ContractState, record_id: u32) {
    let mut world = self.world(@"types_test");

+    // Verify record exists before proceeding
+    assert(world.model_exists<Record>(record_id), 'Record does not exist');
+
    let record: Record = world.read_model(record_id);
    let record_sibling: RecordSibling = world.read_model(record_id);

-    let subrecord_id = record_id + 1;
+    // Read subrecord_id from the record if it exists
+    if world.model_exists<Subrecord>((record_id, record_id)) {
+        let subrecord: Subrecord = world.read_model((record_id, record_id));
+        world.erase_model(@subrecord);
+    }

    world.erase_model(@record);
    world.erase_model(@record_sibling);
-    world.erase_model(@subrecord);

+    // Emit deletion event
+    world.emit_event(
+        @RecordDeleted { record_id }
+    );
}

You'll also need to add the deletion event:

#[derive(Drop, starknet::Event)]
#[dojo::event]
struct RecordDeleted {
    #[key]
    record_id: u32,
}
crates/dojo/lang/src/attribute_macros/element.rs (1)

Line range hint 16-150: Enhance error messages for upgrade constraints.

Sensei, since we're enforcing new upgrade constraints, we should enhance the error messages in the StructParameterParser trait to be more descriptive about these limitations.

Consider adding validation for:

  1. Layout type changes
  2. Field modifications
  3. Field position changes

Here's a suggested implementation:

// Add to trait
fn validate_upgrade_constraints(
    &self,
    db: &dyn SyntaxGroup,
    old_struct: ItemStruct,
    new_struct: ItemStruct,
    diagnostics: &mut Vec<PluginDiagnostic>,
) {
    // Validate layout type hasn't changed
    if old_struct.is_fixed() != new_struct.is_fixed() {
        diagnostics.push(PluginDiagnostic {
            message: "Cannot change layout type during upgrade".into(),
            stable_ptr: new_struct.stable_ptr().untyped(),
            severity: Severity::Error,
        });
    }

    // Validate existing fields haven't changed
    // ... implementation details
}
crates/dojo/core/src/meta/introspect.cairo (3)

38-61: Ohayo sensei! Add documentation for the upgrade rules.

The StructCompareImpl implementation needs documentation to explain:

  • The purpose of struct upgrades
  • The validation rules for upgrades
  • Examples of valid and invalid upgrades

Add this documentation before the implementation:

+/// Implements comparison logic for struct upgrades.
+/// 
+/// # Upgrade Rules
+/// - Names must match exactly
+/// - Attributes must remain unchanged
+/// - Existing fields must remain in the same order
+/// - New fields can only be added at the end
+/// 
+/// # Example
+/// ```
+/// // Valid upgrade:
+/// struct OldStruct { a: felt252 }
+/// struct NewStruct { a: felt252, b: felt252 }
+/// 
+/// // Invalid upgrade (field order changed):
+/// struct OldStruct { a: felt252, b: u32 }
+/// struct NewStruct { b: u32, a: felt252 }
+/// ```
 #[generate_trait]
 pub impl StructCompareImpl of StructCompareTrait {

47-59: Optimize the children comparison logic.

The current implementation uses a manual loop to compare children. Consider using span comparison methods for better readability and potentially better performance.

Consider this optimization:

-        let mut i = 0;
-
-        loop {
-            if i >= (*old.children).len() {
-                break true;
-            }
-
-            if *old.children[i] != *self.children[i] {
-                break false;
-            }
-
-            i += 1;
-        }
+        // Compare the overlapping children
+        let old_children = *old.children;
+        let new_children = (*self.children).slice(0, old_children.len());
+        old_children == new_children

40-45: Consider additional validation for type compatibility.

The current implementation checks for exact equality between children but doesn't handle cases where field types might be compatible but not identical (e.g., upgrades between numeric types).

Consider adding type compatibility checks to support valid type upgrades while preventing breaking changes. For example:

  • Allow upgrading between compatible numeric types (e.g., u8 → u16)
  • Prevent downgrades (e.g., u16 → u8)
  • Handle complex type upgrades (e.g., array size changes)

Would you like me to propose a detailed implementation for type compatibility checks?

crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (1)

Line range hint 54-72: LGTM! Well-structured model definition implementation

Ohayo, sensei! The implementation nicely integrates the new upgradability-related traits. Consider adding a brief comment explaining the relationship between DeployedModelImpl and StoredModelImpl for future maintainers.

Add a comment like:

 #[abi(embed_v0)]
+// Implements IModel by combining deployment-time (DeployedModelImpl) and
+// storage-time (StoredModelImpl) resource information
 pub impl ModelImpl of IModel<ContractState> {
crates/dojo/lang/src/attribute_macros/event.rs (1)

56-63: Enhance error message clarity, sensei!

While the error handling implementation is solid, we could make the message more helpful by including valid parameter options in the error message.

Consider updating the error message format:

-                    message: format!(
-                        "Unexpected parameter {} for {attribute_name}.",
-                        arg.as_syntax_node().get_text(db)
-                    ),
+                    message: format!(
+                        "Unexpected parameter {} for {attribute_name}. Valid parameters are: [{}]",
+                        arg.as_syntax_node().get_text(db),
+                        PARAMETER_HISTORICAL
+                    ),
crates/dojo/world/src/contracts/model.rs (1)

Line range hint 201-283: Ohayo sensei! Consider enhancing parse_schema for upgradability validation.

The parse_schema function handles various types well, but could be extended to support the new upgradability requirements.

Consider adding a validation step in the Struct case that:

  1. Compares against the previous schema version
  2. Validates field positions
  3. Ensures new fields are only appended

Example enhancement:

fn parse_schema(ty: &abigen::model::Ty, previous_schema: Option<&Ty>) -> Result<Ty, ParseError> {
    match ty {
        abigen::model::Ty::Struct(schema) => {
            // ... existing code ...
            
            if let Some(prev) = previous_schema {
                validate_upgradability(&children, prev)?;
            }
            
            Ok(Ty::Struct(Struct { name, children }))
        }
        // ... rest of the match cases ...
    }
}

fn validate_upgradability(new_fields: &[Member], previous_schema: &Ty) -> Result<(), ParseError> {
    // Add validation logic here
    Ok(())
}
crates/dojo/lang/src/attribute_macros/model.rs (2)

Line range hint 72-121: Add documentation about model upgradability.

Please add documentation comments explaining:

  • How model upgrades work
  • Constraints on field modifications
  • Best practices for maintaining backward compatibility

Example documentation to add:

/// Model Upgradability Guidelines:
/// 1. Layout type (Struct/Fixed) must remain consistent
/// 2. Existing fields cannot be modified or reordered
/// 3. New fields must be appended at the end

Line range hint 234-251: Consider adding upgrade-safe accessor generation.

The field accessor generation should account for model upgrades. Consider:

  1. Adding version checks in accessors if needed
  2. Ensuring backward compatibility for existing field accessors
crates/dojo/core/src/world/world_contract.cairo (1)

975-1010: Ohayo sensei! Excellent implementation of resource upgradability checks!

The implementation enforces strict rules for safe schema evolution:

  • Layout type must remain consistent
  • Existing fields cannot be modified
  • New fields can only be appended

However, consider adding explicit error messages for specific validation failures to help developers understand exactly what constraint was violated.

Consider enhancing the error messages like this:

 if !new_layout.is_same_type_of(@old_layout) {
-    panic_with_byte_array(@errors::invalid_resource_layout_upgrade(namespace, name));
+    panic_with_byte_array(@format!(
+        "Invalid layout upgrade for {}-{}: Cannot change from {} to {}",
+        namespace, name, old_layout, new_layout
+    ));
 }
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (2)

95-102: Handle Unexpected Types Gracefully in schema Function

Ohayo, Sensei! In the schema function, if the introspected type is not a Ty::Struct, the code panics with "Unexpected schema." To improve robustness, consider providing a more informative error message or handling unexpected types more gracefully. This can aid in debugging if the schema does not match expectations.


175-180: Consistency Check in dojo_name Methods

Ohayo, Sensei! The dojo_name method in each module returns a hardcoded string representing the event name. Please ensure that these names exactly match the corresponding struct names. Any discrepancies could lead to issues when referencing events elsewhere in the system.

crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (3)

9-9: Ohayo, sensei! Correct typo in comment.

There's a small typo in the comment on line 9: "differenciate" should be "differentiate".

Apply this diff to correct the typo:

-/// as the test runner does not differenciate them.
+/// as the test runner does not differentiate them.

14-14: Ohayo, sensei! Consider making FooBaseModel public.

The FooBaseModel struct is not declared as pub, which may limit its accessibility in other modules or contracts that rely on it. If it's intended to be used elsewhere, consider adding the pub keyword.

Apply this diff to make the struct public:

-struct FooBaseModel {
+pub struct FooBaseModel {

107-116: Ohayo, sensei! Refactor repeated schema functions to reduce code duplication.

The schema function implementations across multiple modules (old_foo_model_bad_layout_type, old_foo_model_member_removed, old_foo_model_member_added_but_removed, old_foo_model_member_added_but_moved, old_foo_model_member_added) contain similar code patterns. To improve maintainability and reduce redundancy, consider abstracting this functionality into a shared function or macro.

For example, you could create a helper function:

fn generate_schema(model_name: felt252) -> dojo::meta::introspect::Struct {
    if let dojo::meta::introspect::Ty::Struct(mut s) =
        dojo::meta::introspect::Introspect::<super::FooBaseModel>::ty() {
        s.name = model_name;
        s
    } else {
        panic!("Unexpected schema.")
    }
}

Then, in each schema function, you can call this helper:

 fn schema(self: @ContractState) -> dojo::meta::introspect::Struct {
-    if let dojo::meta::introspect::Ty::Struct(mut s) =
-        dojo::meta::introspect::Introspect::<super::FooBaseModel>::ty() {
-        s.name = 'FooModelBadLayoutType';
-        s
-    } else {
-        panic!("Unexpected schema.")
-    }
+    super::generate_schema('FooModelBadLayoutType')
 }

Also applies to: 135-145, 166-175, 196-205, 227-236

crates/dojo/core-cairo-test/src/tests/world/event.cairo (1)

25-25: Typo in assertion messages

Ohayo, sensei! The assertion messages on lines 25 and 77 contain an extra closing parenthesis ) in 'no event)'. Please remove the extra parenthesis for clarity.

Apply this diff to fix the typos:

- assert(event.is_some(), 'no event)');
+ assert(event.is_some(), 'no event');

Also applies to: 77-77

crates/dojo/core-cairo-test/src/tests/world/model.cairo (1)

20-21: Ohayo, sensei! Consider creating a helper function to set testing addresses

You are repeatedly calling starknet::testing::set_account_contract_address and starknet::testing::set_contract_address with the same address in multiple test functions. For improved readability and maintainability, consider creating a helper function to handle this setup.

Apply this refactor:

+fn set_testing_addresses(address: ContractAddress) {
+    starknet::testing::set_account_contract_address(address);
+    starknet::testing::set_contract_address(address);
+}

 // Usage in your test functions:
-starknet::testing::set_account_contract_address(bob);
-starknet::testing::set_contract_address(bob);
+set_testing_addresses(bob);

Also applies to: 69-70, 81-82, 205-206, 220-221, 224-225, 247-248

crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1)

273-273: Typo in error message string

Ohayo sensei, there's an extra closing parenthesis in the error message. Please remove it for clarity.

Apply this diff to fix the typo:

-        assert(event.is_some(), 'no event)');
+        assert(event.is_some(), 'no event');
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 25deaa8 and df9efb8.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (41)
  • Cargo.toml (1 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (1 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (1 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (2 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
💤 Files with no reviewable changes (4)
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (15)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/tests/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo
🔇 Additional comments (48)
examples/spawn-and-move/dojo_dev.toml (1)

14-14: Ohayo sensei! Please verify the new world address.

The world address has been updated, but we should ensure this change is intentional and properly documented.

Let's verify this address:

Consider adding a comment above the world_address explaining:

  • Why this specific address is used
  • When/why it might need to be updated
  • How to obtain a new address if needed
 [env]
 rpc_url = "http://localhost:5050/"
 # Default account for katana with seed = 0
 account_address = "0x2af9427c5a277474c079a1283c880ee8a6f0f8fbf73ce969c08d88befec1bba"
 private_key = "0x1800000000300000180000000000030000000000003006001800006600"
+# World address for the example world deployment
+# Update this when redeploying the world contract
 world_address = "0x5A1F4D377330BCE53D4948BA124722929D8ECE28A27F336319343C336E3F54B"
crates/dojo/core/src/model/component.cairo (3)

1-2: Ohayo sensei! Clean and well-structured imports.

The separation between model and meta concerns reflects good design principles and modularity.


Line range hint 27-39: Excellent removal of versioning, sensei!

The implementation cleanly removes versioning while maintaining essential model functionality through size and definition methods. This aligns perfectly with the PR objective of removing unnecessary versioning management.


14-24: Verify upgrade constraints in schema and layout implementations.

The schema and layout methods are crucial for enforcing upgrade constraints. These methods should ensure that:

  1. Layout type remains consistent (Struct or Fixed)
  2. Existing fields remain unchanged
  3. New fields are only appended at the end

Let's verify the implementation of these constraints:

crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2)

6-6: Ohayo! Clean separation of concerns with interface restructuring.

The removal of functionality from IContract and the addition of IDeployedResource creates a more focused and maintainable interface structure. This aligns well with the PR's objective of improving resource management.

Also applies to: 18-19


20-24: Implementation looks solid, sensei!

The IDeployedResource implementation provides a clean way to access the contract name. The use of the template variable $name$ ensures consistency between the actual contract name and its string representation.

Let's verify that this pattern is consistently used across other contract templates:

✅ Verification successful

Ohayo! The pattern is consistently implemented, sensei!

The verification shows that the IDeployedResource implementation pattern is consistently used across the codebase. We found two implementations:

  1. The template version in contract.patch.cairo using $name$ for dynamic contract naming
  2. A test implementation in core-cairo-test/src/tests/contract.cairo following the same pattern with a static name

Both implementations maintain the same structure and purpose, confirming that the pattern is well-established and consistently applied.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent contract name implementation patterns
# across other contract templates

# Search for similar patterns in other template files
rg -g '*.cairo' -A 5 'impl.*of IDeployedResource'

Length of output: 1135

crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (2)

14-17: Ohayo! Implementation looks good, sensei!

The transition to DojoDeployedModelImpl implementing IDeployedResource aligns well with the new resource management approach.


34-42: Ohayo! The DojoStoredModelImpl implementation aligns with upgradability requirements, sensei!

The implementation correctly uses a Fixed layout type, which is one of the allowed layout types for upgradable resources as per the PR objectives. However, we should verify if this empty layout is intended for testing purposes.

✅ Verification successful

Ohayo sensei! The empty layout is indeed intended for testing purposes!

Based on the extensive codebase analysis, I can confirm that the empty layout in DojoStoredModelImpl is intentionally used for testing attack scenarios. This is evidenced by:

  1. The file is located in the test directory (core-cairo-test/src/tests/expanded/selector_attack.cairo)
  2. The implementation is part of an "attacker_model" module used to test security scenarios
  3. Other test files in the codebase also use empty layouts for testing purposes, particularly when testing model registration and upgrades
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if other test files use similar empty layouts for testing
# This helps understand if this is a common testing pattern

rg -A 5 "layout\(.*\).*\{" --type cairo

Length of output: 71


Script:

#!/bin/bash
# Let's try with a more generic search for layout patterns in Cairo files
fd -e cairo | xargs grep -l "layout" || true

# If files are found, let's examine their content
fd -e cairo | while read -r file; do
    if grep -q "layout" "$file"; then
        echo "=== $file ==="
        cat "$file"
        echo
    fi
done

Length of output: 275764


Script:

#!/bin/bash
# Alternative approach: Search for similar struct patterns
fd -e cairo | while read -r file; do
    if grep -q "impl.*StoredModel" "$file"; then
        echo "=== $file ==="
        cat "$file"
        echo
    fi
done

Length of output: 24773


Script:

#!/bin/bash
# Let's also check for any test files with similar patterns
fd "test.*\.cairo$" | while read -r file; do
    echo "=== $file ==="
    cat "$file"
    echo
done

Length of output: 11382

crates/dojo/core-cairo-test/src/lib.cairo (4)

43-50: Ohayo! Clean organization of test helpers, sensei!

The new helpers module structure provides a well-organized collection of test utilities, making them easily accessible for testing scenarios.


60-67: Excellent symmetry with event testing patterns, sensei!

The model test cases maintain consistency with the event testing structure, providing parallel coverage for model upgradability scenarios.


72-78: Verify status of commented-out modules.

I notice that entities and world modules are commented out. Could you clarify if these modules are:

  1. Planned for future implementation
  2. Temporarily disabled
  3. Pending removal

This will help ensure we're not missing any critical functionality.

#!/bin/bash
# Description: Check if commented modules exist in the codebase
# Test: Search for the commented-out module files
fd "entities\.cairo|world\.cairo" crates/dojo/core-cairo-test/src/tests/world/

52-58: Well-structured event test cases for upgradability checks!

The event types cover various upgrade scenarios (bad layout, member removal, etc.) aligning perfectly with the PR's objective of implementing upgradability checks.

Let's verify the test coverage:

✅ Verification successful

Ohayo sensei! Event upgradability tests are well implemented and verified! ✨

The test coverage for event upgradability is comprehensive, including tests for:

  • Basic event upgrades (test_upgrade_event)
  • Permission checks (test_upgrade_event_from_event_owner, test_upgrade_event_from_event_writer)
  • Various failure scenarios:
    • Bad layout type (test_upgrade_event_with_bad_layout_type)
    • Member removal (test_upgrade_event_with_member_removed)
    • Member addition and removal (test_upgrade_event_with_member_added_but_removed)
    • Member movement (test_upgrade_event_with_member_moved)

The event types mentioned in the review comment are properly tested with appropriate error cases, validating the upgradability checks implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify test coverage for event upgradability scenarios
# Test: Search for test functions in the event module
rg -t cairo "fn test.*event.*upgrade" crates/dojo/core-cairo-test/src/tests/

Length of output: 288


Script:

#!/bin/bash
# Let's check the event module directly and its test implementations
rg -t cairo "fn test.*event" crates/dojo/core-cairo-test/src/

# Also check the event module content
cat crates/dojo/core-cairo-test/src/event.cairo

Length of output: 219


Script:

#!/bin/bash
# Let's find the event module first
fd "event.cairo" crates/dojo/core-cairo-test/

# Let's also check for test files that might contain event upgrade tests
fd "test.*cairo" crates/dojo/core-cairo-test/

Length of output: 263


Script:

#!/bin/bash
# Let's check the content of the event test files
cat crates/dojo/core-cairo-test/src/tests/event/event.cairo
cat crates/dojo/core-cairo-test/src/tests/world/event.cairo

# Also check for any upgrade-related patterns in these files
rg -A 5 "FooEvent" crates/dojo/core-cairo-test/src/tests/event/event.cairo
rg -A 5 "FooEvent" crates/dojo/core-cairo-test/src/tests/world/event.cairo

Length of output: 13680

crates/dojo/core/src/lib.cairo (1)

12-13: Ohayo! New event component module looks good, sensei!

The addition of the component module under event aligns well with the PR's objective of implementing event upgradability checks.

Let's verify the component module's contents:

✅ Verification successful

Ohayo! The event component module is properly implemented, sensei!

The verification shows that the component module contains well-structured implementations:

  • IDeployedEventImpl - Provides name resolution for events
  • IStoredEventImpl - Handles schema and layout for events
  • IEventImpl - Manages event definitions

The implementations align perfectly with the event upgradability objectives and follow Dojo's resource management patterns.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the contents and structure of the new event component module
fd "component.cairo" --type f --exec cat {} \; 

Length of output: 1945

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (1)

84-89: Clean implementation of deployed and stored model traits, sensei!

The separation between deployed and stored model implementations provides a clear boundary for managing model lifecycles, which is essential for the upgradability system.

Let's verify that these traits are consistently implemented across other models:

✅ Verification successful

Ohayo! The model implementations are consistent across the codebase, sensei!

The search results confirm that both DojoDeployedModelImpl and DojoStoredModelImpl are consistently implemented in the codebase, following the same pattern as seen in:

  • The model patch template in crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo
  • The concrete implementation in crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo

Both implementations maintain the separation of concerns between deployed and stored models, with proper ABI embedding for external interaction.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in model implementations across the codebase

# Search for other model implementations to ensure they follow the same pattern
rg -A 2 "impl.*DojoDeployedModelImpl" --type cairo
rg -A 2 "impl.*DojoStoredModelImpl" --type cairo

Length of output: 163


Script:

#!/bin/bash
# Let's try a different approach using just pattern matching without file type
# Look for both implementations in any file
rg -A 2 "impl.*DojoDeployedModelImpl"
rg -A 2 "impl.*DojoStoredModelImpl"

# Also search for the trait definitions to understand the pattern better
rg "trait IDeployedModelImpl"
rg "trait IStoredModelImpl"

Length of output: 1955

crates/dojo/core/src/model/model.cairo (3)

1-3: Ohayo! Import changes align with schema type updates.

The switch from introspect::Ty to introspect::Struct properly supports the new model upgradability requirements.


Line range hint 108-116: Verify impact of version removal on existing model consumers.

The removal of versioning from ModelDef aligns with the PR objectives, sensei. However, we should ensure that no existing code relies on version information for model management.

✅ Verification successful

Version removal is safe to proceed, sensei!

The search results show no active version-related code in model definitions or implementations. The only reference found is a TODO comment in sozo/ops/src/auth.rs which is discussing a hypothetical future consideration, not actual implementation.

The removal of versioning from ModelDef appears to be a clean change with no impact on existing model consumers.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining version-related code that might need updating

echo "Checking for version-related model usage..."
rg -A 3 "version|Version" --type rust

echo "Checking for potential model version dependencies..."
ast-grep --pattern 'fn $name($_) -> u8 {
  $$$
}'

Length of output: 88826


Script:

#!/bin/bash
# Check for any model version-related code in the codebase
echo "Checking for model version references..."
rg -A 3 "model.*version|version.*model" --type rust

echo "Checking for version field usage in model definitions..."
ast-grep --pattern 'struct ModelDef {
  $$$
  version: $_,
  $$$
}'

echo "Checking for version-related model methods..."
ast-grep --pattern 'impl Model for $_ {
  $$$
  fn version() -> $_ {
    $$$
  }
  $$$
}'

Length of output: 971


39-39: Schema type change needs verification across model definitions.

The change from Ty to Struct is a significant modification that supports the new upgradability requirements. However, we should verify that all existing model definitions are compatible with this change.

Also applies to: 91-93

✅ Verification successful

Ohayo sensei! After analyzing the codebase, I can provide a definitive response about the schema type change:

Schema type change from Ty to Struct is safe to proceed

The search results show that while there are some Ty usages in the codebase, they are in utility/parsing functions and type conversion contexts, not in actual model schema implementations. The change from Ty to Struct in the Model trait's schema method appears to be an internal refactoring that doesn't affect existing model definitions.

  • The only Ty usages found are in utility functions in:
    • torii/graphql/src/types.rs
    • torii/graphql/src/query/mod.rs
    • torii/core/src/model.rs
    • dojo/types/src/schema.rs

No conflicting schema implementations were found that would be broken by this change.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for any remaining usages of Ty in model definitions
# that might need updating

echo "Checking for potentially incompatible model definitions..."
rg -l "-> Ty" --type rust

echo "Checking for struct implementations that might need updates..."
ast-grep --pattern 'impl $_ of Model<$_> {
  $$$
  fn schema() -> $ret {
    $$$
  }
  $$$
}'

Length of output: 88826


Script:

#!/bin/bash
# Search for schema() implementations and their return types
echo "Checking schema implementations and return types..."
ast-grep --pattern 'fn schema() -> $ret {
  $$$
}'

# Search for any remaining Ty usages in model definitions
echo "Checking for Ty usages in model definitions..."
rg -A 3 "-> Ty" --type rust

# Search for Model trait implementations
echo "Checking Model trait implementations..."
ast-grep --pattern 'impl $_ of Model<$_> {
  $$$
}'

Length of output: 846


Script:

#!/bin/bash
# Search for Ty usages with proper escaping
echo "Checking for Ty usages in model definitions..."
rg "\-> Ty" --type rust

# Search for schema implementations with Struct return type
echo "Checking schema implementations with Struct return type..."
ast-grep --pattern 'fn schema() -> Struct {
  $$$
}'

# Search for schema implementations with Ty return type
echo "Checking schema implementations with Ty return type..."
ast-grep --pattern 'fn schema() -> Ty {
  $$$
}'

Length of output: 1217

crates/torii/types-test/src/contracts.cairo (2)

Line range hint 1-5: Ohayo sensei! The interface changes look good!

The addition of the delete method to the IRecords trait is clean and consistent with the existing interface design.


112-113: Method chaining improvement looks clean, sensei!

The refactoring to use method chaining for event emission improves code readability while maintaining the same functionality.

crates/dojo/lang/src/attribute_macros/element.rs (2)

7-7: LGTM! Import organization looks clean.

Ohayo! The import reorganization improves code readability by grouping related AST types together.


Line range hint 1-150: Verify the impact of versioning removal.

The removal of versioning-related code (CommonStructParameters, DEFAULT_VERSION, etc.) aligns well with the PR objectives to simplify the upgrade process. However, we should verify that this change doesn't break existing contracts.

Consider documenting the new upgrade constraints in the module-level documentation:

  • Same layout type requirement (Struct/Fixed)
  • No changes to existing fields
  • New fields must be appended at the end

Would you like me to help draft this documentation?

✅ Verification successful

Ohayo sensei! After analyzing the git history and code changes, I can now provide a definitive response about the versioning removal:

The versioning removal is safe and won't break existing contracts

The git history shows that the removed versioning code was only used for validation during compile-time:

  • Removed DEFAULT_VERSION = 1 constant
  • Removed CommonStructParameters struct that only contained version validation
  • Removed get_version() function that prevented using versions > 1

This was purely compile-time validation code that didn't affect runtime behavior or contract storage. The removal aligns with simplifying the upgrade process since:

  1. No runtime versioning was actually being used
  2. The validation was artificially limiting upgrades
  3. The removed code wasn't part of the contract's storage or state

Keep coding with confidence, sensei! 🚀

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for any remaining version-related code or dependencies that might need updating

# Test 1: Look for any remaining version-related code
echo "Checking for remaining version references..."
rg -i "version|versioning" --type rust

# Test 2: Look for potential upgrade-related code that might be affected
echo "Checking for upgrade-related code..."
rg -i "upgrade|migration" --type rust

# Test 3: Look for any remaining CommonStructParameters usage
echo "Checking for CommonStructParameters usage..."
rg "CommonStructParameters" --type rust

Length of output: 71128


Script:

#!/bin/bash
# Let's check for any remaining versioning-related code in the element.rs file and its dependencies

# Check for version-related code in element.rs and related files
rg -l "version|CommonStructParameters" crates/dojo/lang/src/attribute_macros/

# Check for any imports or usages of versioning-related types
ast-grep --pattern 'use $$$version$$$;' crates/dojo/lang/src/attribute_macros/element.rs

# Check for any struct definitions or trait implementations related to versioning
ast-grep --pattern 'struct $name {
  $$$
  version: $_,
  $$$
}' crates/dojo/lang/src/attribute_macros/element.rs

# Look for any version-related function calls or methods
ast-grep --pattern 'fn $name($_) {
  $$$
  version$$$
  $$$
}' crates/dojo/lang/src/attribute_macros/element.rs

Length of output: 400


Script:

#!/bin/bash
# Let's check the git history to see what versioning code was removed

# Check git history for removed versioning code
git log -p crates/dojo/lang/src/attribute_macros/element.rs | rg -B 5 -A 5 "CommonStructParameters|version"

# Check for any remaining references to versioning in the entire attribute_macros directory
find crates/dojo/lang/src/attribute_macros -type f -exec grep -l "CommonStructParameters\|DEFAULT_VERSION\|version" {} \;

# Look for any remaining version-related imports
rg "use.*Common.*Parameters|use.*version" crates/dojo/lang/src/attribute_macros/

# Check for any version-related function parameters
ast-grep --pattern 'fn $name($$$version$$$)' crates/dojo/lang/src/attribute_macros/element.rs

Length of output: 4871

crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (2)

37-41: LGTM! Clean implementation of IDeployedResource

Ohayo, sensei! The implementation correctly follows the new resource management pattern introduced for model upgradability.


43-52: Name inconsistency between schema and dojo_name

crates/dojo/lang/src/attribute_macros/event.rs (2)

Line range hint 20-40: Ohayo! Clean simplification of EventParameters structure.

The removal of the common parameters and focus on just the historical field aligns perfectly with the PR's objective of removing versioning management. The simplified structure maintains backward compatibility while reducing complexity.


Line range hint 20-63: Verify complete removal of versioning logic.

The changes align with removing versioning management, but let's verify no residual versioning logic exists in related files.

✅ Verification successful

Ohayo sensei! The versioning removal is complete and clean

The codebase scan shows that versioning has been properly removed from event handling. The only remaining references are to historical flags, which are a separate feature for event tracking and not related to versioning management.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining version-related code in event implementations
rg -i "version" --type rust -g "event*.rs" -g "!target/*"

# Search for potential version-related types or traits
ast-grep --pattern 'trait $name {
  $$$
  version($$$) {
    $$$
  }
  $$$
}'

Length of output: 283


Script:

#!/bin/bash
# Let's check the event_message.rs file content for context
cat crates/torii/core/src/processors/event_message.rs

# Also check for any version-related imports or dependencies
rg -i "version" --type toml

# Check for any version-related structs or enums
ast-grep --pattern 'struct $name {
  $$$
  version: $_,
  $$$
}'

ast-grep --pattern 'enum $name {
  $$$
  Version($$$),
  $$$
}'

Length of output: 54380


Script:

#!/bin/bash
# Let's check for any historical version references in event-related files
rg -i "historical" --type rust -g "event*.rs" -A 2 -B 2

# Check for any version-related attributes or macros
ast-grep --pattern '#[derive($$$)]
struct $name {
  $$$
}'

# Look for any version-related constants or parameters
rg -i "const.*version|version.*=.*" --type rust -g "event*.rs"

Length of output: 8638

crates/dojo/world/src/contracts/model.rs (1)

176-176: Ohayo sensei! Verify schema parsing behavior for upgradability checks.

The change to wrap the result in Ty::Struct aligns with the PR's objective to enforce layout type consistency during upgrades. However, we should verify that this properly enforces the upgradability rules.

Let's check the schema parsing behavior:

Consider adding explicit validation in the schema parsing to enforce:

  1. No changes to existing field positions
  2. New fields only at the end of the resource
  3. Layout type consistency (Struct/Fixed)
✅ Verification successful

Ohayo sensei! Schema parsing change is correctly enforcing upgradability rules.

The change to wrap the result in Ty::Struct aligns with the comprehensive test suite that verifies schema validation during model upgrades. The tests confirm proper handling of:

  • Layout type consistency (test_upgrade_model_with_bad_layout_type)
  • Field position preservation (test_upgrade_model_with_member_moved)
  • Field removal prevention (test_upgrade_model_with_member_removed)
  • New field additions (test_upgrade_model_with_member_added)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify schema parsing and upgradability rules
# Look for any existing model upgrades to ensure they follow the new rules

# Search for model upgrade patterns
rg -A 5 "upgrade.*model|model.*upgrade" 

# Search for schema-related tests
fd -e rs | xargs rg -l "test.*schema|schema.*test"

Length of output: 19669


Script:

#!/bin/bash
# Let's verify the schema parsing implementation and test coverage

# Check schema parsing implementation
ast-grep --pattern 'fn parse_schema($$$) {
  $$$
}'

# Look for schema-related test cases specifically for upgrades
rg -B 2 -A 5 "test.*schema.*upgrade|upgrade.*schema.*test"

# Check for any schema validation logic
rg -A 5 "validate.*schema|schema.*validate"

# Look for struct layout validation
rg -A 5 "layout.*validate|validate.*layout"

Length of output: 206


Script:

#!/bin/bash
# Let's check the model.rs file directly and its test implementations

# Check the model schema parsing implementation
cat crates/dojo/world/src/contracts/model.rs

# Look for model upgrade test implementations
cat crates/dojo/core-cairo-test/src/tests/world/model.cairo

# Check for any schema validation in the model tests
cat crates/dojo/core-cairo-test/src/tests/helpers/model.cairo

Length of output: 25309

crates/dojo/lang/src/attribute_macros/model.rs (2)

18-24: Ohayo sensei! The import changes align with versioning removal.

The updated imports reflect the shift away from versioning management while maintaining the core model functionality. The code organization looks clean and focused.


Line range hint 31-70: Ohayo sensei! We need to add upgradability checks.

Based on the PR objectives, we should add validation to ensure:

  1. Layout type remains consistent
  2. Existing fields are not modified
  3. New fields are only appended at the end

This will prevent breaking changes during model upgrades.

Let's verify if there are any existing upgrade validations:

crates/dojo/world/src/contracts/abigen/model.rs (3)

Line range hint 627-636: LGTM! Schema return type properly updated.

The schema method's return type has been correctly updated to match the ModelDef struct changes, maintaining consistency throughout the codebase.


Line range hint 732-741: LGTM! Schema return type consistently updated in reader.

The schema method's return type has been properly synchronized with the ModelContract implementation, ensuring consistency across both contract interfaces.


Line range hint 176-217: LGTM! Version field removal aligns with PR objectives.

The changes correctly remove the version field from ModelDef and update the schema field type to be more specific (Struct instead of Ty). The serialization and deserialization logic has been properly updated to reflect these changes.

Let's verify that version-related code has been consistently removed:

✅ Verification successful

Let me gather more context about these remaining version references to ensure a thorough verification.


Ohayo sensei! After analyzing the results, I can now provide the final verification:

✅ Version field removal is properly implemented

The remaining version references found are either:

  • Test data validating version attribute parsing (plugin_test_data/model)
  • Comments discussing historical context (core-cairo-test/model.cairo)
  • A TODO comment about version handling (sozo/ops/auth.rs)

None of these indicate actual version field usage in the codebase. The ast-grep search also confirms no remaining version fields in structs.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining version-related code
# Expect: No occurrences of version in model-related files

rg -i "version.*model" 

Length of output: 603


Script:

#!/bin/bash
# Check the content of these files to understand the version references
cat crates/sozo/ops/src/auth.rs | grep -A 5 -B 5 "version.*model"
echo "---"
cat crates/dojo/lang/src/plugin_test_data/model | grep -A 5 -B 5 "version.*model"
echo "---"
cat crates/dojo/core-cairo-test/src/tests/helpers/model.cairo | grep -A 5 -B 5 "version.*model"

# Also check if there are any remaining version fields in model-related structs
ast-grep --pattern 'struct $_ {
  $$$
  version: $_,
  $$$
}'

Length of output: 1870

crates/dojo/core/src/world/world_contract.cairo (5)

42-45: LGTM! Clean import additions for resource upgradability.

The new imports from dojo::meta provide the necessary types and traits for implementing resource upgradability checks.


357-357: LGTM! Consistent entity ID calculation.

The change to use entity_id_from_keys aligns with the standard pattern used throughout the codebase.


436-436: LGTM! Improved type safety with IDeployedResourceDispatcher.

The consistent use of IDeployedResourceDispatcher across all resource-related functions enhances type safety and maintainability.

Also applies to: 482-482, 540-540, 586-586, 665-665, 720-720


508-511: LGTM! Robust upgradability checks added.

The addition of assert_resource_upgradability checks in both event and model upgrades ensures safe schema evolution.

Also applies to: 612-615


Line range hint 1028-1059: Consider improving error handling for non-Dojo contracts.

The current implementation assumes all contract callers are Dojo contracts. While this works for the current use cases, it might cause issues when integrating with external contracts.

Consider adding a try-catch mechanism:

-let d = IDeployedResourceDispatcher { contract_address: caller };
-format!("Contract `{}`", d.dojo_name())
+match try_selector_from_address(caller) {
+    Option::Some(name) => format!("Contract `{}`", name),
+    Option::None => format!("External contract `{:?}`", caller)
+}
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (3)

7-10: Ohayo, Sensei! Clarify the Usage of #[dojo::event] Attribute

The comments mention that the event contracts are written without the #[dojo::event] attribute to avoid naming conflicts, yet from line 21 onwards, the #[dojo::event] attribute is applied to the event structs. Please verify if this is intentional or if the attribute should be omitted to align with the initial comment and testing setup.


7-11: Duplicate Comment on #[dojo::event] Usage

Sensei, the comment regarding the use of the #[dojo::event] attribute appears redundant with earlier comments. Consider consolidating or rephrasing to maintain clarity and avoid repetition.


63-78: ⚠️ Potential issue

Ensure Correct Initialization of Event Resources

Sensei, in the deploy_world_for_event_upgrades function, you're registering event resources using TEST_CLASS_HASH from various modules like old_foo_event_bad_layout_type. Please confirm that these modules are correctly imported and their TEST_CLASS_HASH constants are properly initialized. Missing or incorrect class hashes could lead to issues during world deployment.

Run the following script to verify module imports and TEST_CLASS_HASH initialization:

✅ Verification successful

This will help us locate the module files and verify their TEST_CLASS_HASH definitions, even if they're in separate files rather than in the main event.cairo file.


This will help us verify if the event modules mentioned in the function are properly defined in the same file.


All Event Modules Properly Defined and Used, Sensei!

Ohayo! After verifying the codebase, I can confirm that all the event modules (old_foo_event_bad_layout_type, old_foo_event_member_removed, old_foo_event_member_added_but_removed, old_foo_event_member_added_but_moved, and old_foo_event_member_added) are properly defined in the same file. Each module follows the correct structure with proper storage and implementation traits. The usage of TEST_CLASS_HASH in the deploy_world_for_event_upgrades function is consistent with the module definitions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all old event modules are imported and have initialized TEST_CLASS_HASH.

# Expected: Each module should define TEST_CLASS_HASH.
for module in old_foo_event_bad_layout_type old_foo_event_member_removed old_foo_event_member_added_but_removed old_foo_event_member_added_but_moved old_foo_event_member_added; do
  rg -A 5 "pub mod $module" crates/dojo/core-cairo-test/src/tests/helpers/event.cairo | rg "const TEST_CLASS_HASH"
done

Length of output: 1586


Script:

#!/bin/bash
# Let's check if these modules exist in separate files
fd -e cairo old_foo_event

# Then let's check the content of these files for TEST_CLASS_HASH
rg "TEST_CLASS_HASH" -A 2 -B 2

Length of output: 61935


Script:

#!/bin/bash
# Let's check if these specific event modules exist and have TEST_CLASS_HASH defined
rg -A 5 "mod old_foo_event_" crates/dojo/core-cairo-test/src/tests/helpers/event.cairo

Length of output: 1047

crates/dojo/core-cairo-test/src/tests/world/event.cairo (1)

46-49: Ohayo, sensei! The #[should_panic] attribute syntax issue persists

The syntax for #[should_panic] attributes is incorrect in multiple places. Please refer to the previous comment regarding the correct syntax and apply the necessary changes throughout the file.

Also applies to: 129-134, 141-146, 153-158, 169-173, 181-185, 199-201, 220-221, 229-230

crates/dojo/core-cairo-test/src/tests/world/contract.cairo (8)

77-78: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the previous comment about the expected parameter being a string literal is still applicable here.


90-91: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the issue with the expected parameter needing to be a string literal persists in this code segment.


193-196: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the prior feedback regarding the expected parameter applies here as well.


225-226: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the earlier comment about using a string literal for the expected parameter remains relevant.


237-238: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the previous advice on the expected parameter is still valid for this segment.


290-295: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the issue with the expected parameter needing to be a string literal persists here.


322-327: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the previous comment about the expected parameter applies to this code segment as well.


343-344: Incorrect usage of expected parameter in #[should_panic]

Ohayo sensei, the prior feedback regarding the expected parameter is still applicable here.

Comment on lines +104 to +108
fn layout(self: @ContractState) -> dojo::meta::Layout {
// Should never happen as dojo::event always derive Introspect.
dojo::meta::Layout::Fixed([].span())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Review the Implementation of the layout Function

Sensei, the layout function returns dojo::meta::Layout::Fixed([].span()) with a comment stating it should never happen since #[dojo::event] always derives Introspect. However, returning an empty layout might lead to issues if this code path is ever executed. Consider implementing proper error handling or ensuring that this case cannot occur to prevent potential runtime errors.

Comment on lines +40 to +42
fn plz_more_tps(self: @ContractState) -> felt252 {
'daddy'
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential type mismatch: returning a string literal as felt252

Ohayo sensei, the function plz_more_tps is expected to return a felt252, but it returns a string literal 'daddy'. Please consider converting the string to a felt252 or returning an appropriate numeric value.

Comment on lines +71 to +73
let quantum_dispatcher = IQuantumLeapDispatcher { contract_address: base_address };
assert(quantum_dispatcher.plz_more_tps() == 'daddy', 'quantum leap failed');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential type mismatch in assertion

Ohayo sensei, in the assertion, you're comparing a felt252 to a string literal 'daddy'. Ensure both sides of the comparison are of the same type to avoid unexpected behavior.

@remybar remybar force-pushed the upgradeable_models branch 2 times, most recently from 431b031 to 8a20705 Compare November 4, 2024 21:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (25)
crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (1)

14-17: Ohayo! Implementation looks good but could use documentation.

The switch to IDeployedResource aligns well with the new upgradability system, sensei. The implementation is clean and minimal.

Consider adding a doc comment explaining this contract's role in testing selector attacks:

+/// Test contract implementing IDeployedResource for selector attack verification
 pub impl DojoDeployedModelImpl of dojo::meta::IDeployedResource<ContractState> {
crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (2)

7-11: Ohayo, sensei! Consider enhancing the documentation.

While the current comment explains why these models are defined without the dojo::model attribute, it would be helpful to document the specific test scenario each model is designed to validate (e.g., what makes FooModelBadLayoutType "bad").


58-71: Ohayo! Clean deployment function implementation.

The function effectively sets up a test world with all necessary model contracts. While unwrap() is used for error handling, this is acceptable in a test context. However, consider adding a comment explaining that panics are expected/acceptable here.

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (1)

110-115: Enhance documentation for ensure_unique, sensei!

While the implementation is solid, consider expanding the comment to explain:

  • Why unique class hashes are important for model upgradability
  • How the hash is computed from model and member names
  • What problems this prevents (e.g., accidental model collisions)
-        // Ensures the generated contract has a unique classhash, using
-        // a hardcoded hash computed on model and member names.
+        // Ensures the generated contract has a unique classhash to prevent accidental
+        // model collisions during upgrades. The hash is deterministically computed
+        // from the model name and its member names, making it consistent across
+        // deployments but unique to this model's structure.
crates/dojo/core/src/model/model.cairo (2)

1-3: Ohayo! The import changes align well with the new upgradability requirements, sensei!

The transition from introspect::Ty to introspect::Struct provides better type safety and validation capabilities, which are essential for enforcing the strict upgradability conditions mentioned in the PR objectives.


Line range hint 108-117: Clean removal of versioning from ModelDef, sensei!

The definition method now returns a version-free ModelDef, focusing on essential elements for upgradability validation: layout, schema, and size information. This aligns perfectly with the PR's goal of removing versioning management while maintaining strict upgrade controls.

crates/torii/types-test/src/contracts.cairo (1)

Ohayo sensei! The delete implementation needs some event emission! 🎯

Based on the codebase analysis, I can see that:

  1. The codebase extensively uses events for tracking model changes
  2. There's a StoreDelRecord event that's emitted in other delete operations
  3. The current delete implementation correctly erases the models but doesn't emit any events

Let's improve the implementation by adding event emission:

fn delete(ref self: ContractState, record_id: u32) {
    let mut world = self.world(@"types_test");

    let record: Record = world.read_model(record_id);
    let record_sibling: RecordSibling = world.read_model(record_id);

    let subrecord_id = record_id + 1;
    let subrecord: Subrecord = world.read_model((record_id, subrecord_id));

    world.erase_model(@record);
+   // Emit deletion event for record
+   world.emit_event(
+       @StoreDelRecord { 
+           selector: dojo::model::Model::<Record>::selector(), 
+           entity_id: record_id.into() 
+       }
+   );

    world.erase_model(@record_sibling);
+   // Emit deletion event for record_sibling
+   world.emit_event(
+       @StoreDelRecord { 
+           selector: dojo::model::Model::<RecordSibling>::selector(), 
+           entity_id: record_id.into() 
+       }
+   );

    world.erase_model(@subrecord);
+   // Emit deletion event for subrecord
+   world.emit_event(
+       @StoreDelRecord { 
+           selector: dojo::model::Model::<Subrecord>::selector(), 
+           entity_id: (record_id, subrecord_id).into() 
+       }
+   );
}
🔗 Analysis chain

Line range hint 116-131: Critical concerns in delete implementation, sensei! 🚨

The delete implementation has several potential issues that need attention:

  1. Missing error handling for non-existent records
  2. Hardcoded assumption that subrecord_id = record_id + 1
  3. No events emitted for deletion tracking

Consider applying these improvements:

 fn delete(ref self: ContractState, record_id: u32) {
     let mut world = self.world(@"types_test");
 
-    let record: Record = world.read_model(record_id);
-    let record_sibling: RecordSibling = world.read_model(record_id);
+    // Handle potential errors
+    match world.try_read_model::<Record>(record_id) {
+        Option::Some(record) => {
+            let record_sibling: RecordSibling = world.read_model(record_id);
 
-    let subrecord_id = record_id + 1;
-    let subrecord: Subrecord = world.read_model((record_id, subrecord_id));
+            // Read all subrecords associated with this record
+            let subrecords = world.get_models_with_key1::<Subrecord>(record_id);
 
-    world.erase_model(@record);
-    world.erase_model(@record_sibling);
-    world.erase_model(@subrecord);
+            world.erase_model(@record);
+            world.erase_model(@record_sibling);
+            
+            // Erase all associated subrecords
+            subrecords.iter().for_each(|subrecord| {
+                world.erase_model(@subrecord);
+            });
+
+            // Emit deletion event
+            world.emit_event(
+                @RecordDeleted { record_id }
+            );
+        },
+        Option::None => {
+            panic!("Record not found");
+        }
+    }
 }

Let's verify if there are any existing deletion events in the codebase:


Let me also check the actual model definitions and their usage:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any existing deletion events
rg -l "Deleted|Removal|Erased" --type cairo

Length of output: 75


Script:

#!/bin/bash
# Search for any event-related code patterns in Cairo files
fd "\.cairo$" | xargs cat | grep -i "event\|emit"

# Also search for struct definitions that might be events
fd "\.cairo$" | xargs cat | grep -i "struct.*deleted\|struct.*removed"

Length of output: 25719


Script:

#!/bin/bash
# Look for Record and Subrecord model definitions
fd "\.cairo$" | xargs cat | grep -A 5 "struct.*Record"

# Check if there are any existing delete or erase operations
fd "\.cairo$" | xargs cat | grep -i "delete\|erase"

Length of output: 9090

crates/dojo/lang/src/attribute_macros/element.rs (2)

86-90: Ohayo! Nice hash implementation, sensei!

The compute_unique_hash function provides a robust way to generate deterministic hashes for structs. The use of Poseidon hash with a combination of packing status and struct text ensures uniqueness and cryptographic security.

This hash can be effectively used for:

  • Detecting incompatible struct changes during upgrades
  • Verifying struct integrity across the system
  • Creating unique identifiers for struct versions

Consider documenting these use cases in the function's documentation to help other developers understand its importance in the upgradability system.


Line range hint 1-1: Ohayo! Good architectural decision on versioning removal, sensei!

The removal of version-related code (CommonStructParameters, DEFAULT_VERSION, etc.) aligns well with the new upgradability strategy. Instead of explicit versioning, the system now relies on structural compatibility checks, which is a more robust approach.

This change:

  • Reduces complexity by removing manual version management
  • Enforces compatibility through structural checks rather than version numbers
  • Makes upgrades more predictable and safer

Consider adding a migration guide in the documentation to help users understand how to handle upgrades in the new system.

crates/dojo/lang/src/attribute_macros/event.rs (1)

167-169: Document the unique hash computation purpose and parameters.

The addition of unique_hash is crucial for upgradability checks, but the purpose of the false parameter in compute_unique_hash needs documentation.

Add a comment explaining:

// Compute a unique hash for the event structure to enforce upgradability rules
// The `false` parameter indicates ...
let unique_hash = compute_unique_hash(&struct_ast.as_syntax_node().get_text(db), false).to_string();

Also applies to: 180-180

crates/dojo/lang/src/attribute_macros/model.rs (1)

Line range hint 1-207: Ohayo sensei! Consider documenting upgradability constraints.

While the code changes look solid, it would be beneficial to add documentation about the new upgradability constraints mentioned in the PR objectives:

  • Same layout type requirement (Struct/Fixed)
  • No changes/movements of existing fields
  • New fields must be appended at the end

Consider adding these as doc comments at the top of the file or in the DojoModel struct documentation.

 #[derive(Debug, Clone, Default)]
 pub struct DojoModel {}
+
+/// Upgradability constraints for models:
+/// - Must maintain the same layout type (Struct/Fixed)
+/// - Existing fields cannot be changed or moved
+/// - New fields can only be appended at the end of the resource
crates/dojo/core-cairo-test/src/tests/world/event.cairo (1)

48-97: Consider adding more edge cases for event registration.

Ohayo, sensei! While the current tests cover basic success and failure scenarios, consider adding tests for:

  • Registration with invalid class hash
  • Registration with empty event name
  • Multiple registrations of the same event
crates/dojo/core-cairo-test/src/tests/world/model.cairo (4)

74-86: Ohayo, sensei! Consider extracting event validation to a helper function

The event validation pattern is repeated across multiple tests. Consider extracting it into a helper function to improve maintainability and reduce code duplication.

fn assert_model_registered_event(
    event: Option<world::Event>,
    expected_name: felt252,
    expected_namespace: felt252,
    expected_class_hash: ClassHash
) {
    match event {
        Option::Some(world::Event::ModelRegistered(event)) => {
            assert(event.name == expected_name, 'bad event name');
            assert(event.namespace == expected_namespace, 'bad event namespace');
            assert(event.class_hash == expected_class_hash, 'bad event class_hash');
            assert(
                event.address != core::num::traits::Zero::<ContractAddress>::zero(),
                'bad event prev address'
            );
        },
        _ => core::panic_with_felt252('no ModelRegistered event')
    }
}

160-236: Ohayo, sensei! Well-organized upgrade test suite

The upgrade tests provide comprehensive coverage of various scenarios:

  • Basic model upgrades
  • Layout type validation
  • Field removal detection
  • Field movement detection
  • Field addition validation

Consider grouping these related tests using a test module to improve organization:

mod tests_model_upgrades {
    #[test]
    fn test_upgrade_model() { ... }

    #[test]
    fn test_upgrade_model_with_bad_layout_type() { ... }

    // ... other upgrade tests
}

283-285: Ohayo, sensei! Enhance security test documentation

The comment for the malicious contract test could be more detailed to better explain the security implications and expected behavior.

Consider expanding the comment to:

// This test verifies that malicious contracts cannot bypass access control by directly
// calling register_model. The test currently fails with CONTRACT_NOT_DEPLOYED since
// the calling contract is not a registered Dojo contract. In production, this prevents
// unauthorized contracts from registering models even if they somehow obtain owner permissions.

1-297: Ohayo, sensei! Excellent test coverage with room for minor improvements

The test suite provides comprehensive coverage of model registration and upgrades. A few suggestions to consider:

  1. Add edge cases for very large structs or complex field types
  2. Consider testing concurrent registration attempts
  3. Add performance tests for large-scale model operations

Would you like assistance in implementing any of these additional test cases?

crates/dojo/core-cairo-test/src/tests/world/contract.cairo (3)

167-189: Ohayo sensei! Consider adding more assertions for event validation

The event validation in test_deploy_contract_for_namespace_owner could be more thorough. Consider adding assertions to verify the deployer's address and timestamp.

Add these assertions after the existing ones:

    assert(
        event.address != core::num::traits::Zero::<ContractAddress>::zero(), 'bad contract address'
    );
+   assert(event.deployer == bob, 'wrong deployer');
+   assert(event.timestamp > 0, 'invalid timestamp');

275-287: Ohayo sensei! Enhance upgrade event validation

The event validation in test_upgrade_contract_from_resource_owner could be more thorough. Consider validating additional event fields.

Add these assertions within the event match block:

    if let world::Event::ContractUpgraded(event) = event.unwrap() {
        assert(
            event.selector == dojo::utils::selector_from_namespace_and_name(
                DOJO_NSH, @contract_name
            ),
            'bad contract selector'
        );
        assert(event.class_hash == class_hash, 'bad class_hash');
+       assert(event.upgrader == bob, 'wrong upgrader');
+       assert(event.timestamp > 0, 'invalid timestamp');
+       assert(event.contract_address == contract_address, 'wrong contract');
    } else {
        core::panic_with_felt252('no ContractUpgraded event');
    };

1-361: Ohayo sensei! Overall assessment looks good!

The test coverage is comprehensive, covering various scenarios for contract deployment and upgrades. The code effectively tests access control, error cases, and event emissions.

Consider adding these test scenarios in future updates:

  1. Upgrade to an invalid class hash
  2. Concurrent upgrade attempts
  3. Gas consumption benchmarks for upgrades
crates/dojo/core/src/world/world_contract.cairo (1)

975-1010: Ohayo, sensei! Robust upgradability checks implementation

The implementation thoroughly validates upgrade compatibility with clear requirements:

  • Same layout type preservation
  • Existing field protection
  • Append-only new fields

Consider enhancing error messages to include specific details about which validation failed (e.g., which fields were modified).

 fn assert_resource_upgradability(
     self: @ContractState,
     namespace: @ByteArray,
     name: @ByteArray,
     prev_address: ContractAddress,
     new_address: ContractAddress
 ) {
     let resource = IStoredResourceDispatcher { contract_address: prev_address };
     let old_layout = resource.layout();
     let old_schema = resource.schema();

     let new_resource = IStoredResourceDispatcher { contract_address: new_address };
     let new_layout = new_resource.layout();
     let new_schema = new_resource.schema();

     if !new_layout.is_same_type_of(@old_layout) {
-        panic_with_byte_array(@errors::invalid_resource_layout_upgrade(namespace, name));
+        panic_with_byte_array(@errors::invalid_resource_layout_upgrade_details(
+            namespace, 
+            name, 
+            @format!("Expected {}, got {}", old_layout, new_layout)
+        ));
     }

     if !new_schema.is_an_upgrade_of(@old_schema) {
-        panic_with_byte_array(@errors::invalid_resource_schema_upgrade(namespace, name));
+        panic_with_byte_array(@errors::invalid_resource_schema_upgrade_details(
+            namespace,
+            name,
+            @format!("Schema changes must be append-only")
+        ));
     }
 }
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (5)

9-9: Ohayo, Sensei! Correct Typo in Comment

The word "differenciate" is misspelled. It should be "differentiate".

Apply this diff to fix the typo:

-/// as the test runner does not differenciate them.
+/// as the test runner does not differentiate them.

32-37: Add 'pub' Visibility to FooEventMemberRemoved

Sensei, the struct FooEventMemberRemoved is not declared as pub. If this event struct needs to be accessible outside this module, consider adding the pub keyword.

Apply this diff if intended:

-struct FooEventMemberRemoved {
+pub struct FooEventMemberRemoved {

41-46: Add 'pub' Visibility to FooEventMemberAddedButRemoved

Sensei, the struct FooEventMemberAddedButRemoved is not declared as pub. If it should be accessible outside this module, please consider making it public.

Apply this diff if intended:

-struct FooEventMemberAddedButRemoved {
+pub struct FooEventMemberAddedButRemoved {

50-55: Add 'pub' Visibility to FooEventMemberAddedButMoved

Sensei, the struct FooEventMemberAddedButMoved is not declared as pub. If external access is required, adding the pub keyword would be beneficial.

Apply this diff if intended:

-struct FooEventMemberAddedButMoved {
+pub struct FooEventMemberAddedButMoved {

59-64: Add 'pub' Visibility to FooEventMemberAdded

Sensei, the struct FooEventMemberAdded is currently private. If it's meant to be used outside this module, please consider declaring it as pub.

Apply this diff if intended:

-struct FooEventMemberAdded {
+pub struct FooEventMemberAdded {
🛑 Comments failed to post (3)
crates/dojo/core-cairo-test/src/tests/world/event.cairo (1)

235-254: ⚠️ Potential issue

Misleading test name and error message.

Ohayo, sensei! The test name test_upgrade_event_from_random_account suggests testing an upgrade operation, but the test actually verifies duplicate event registration. Consider either:

  1. Renaming the test to test_register_duplicate_event, or
  2. Modifying the test to actually test an upgrade from a random account
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (2)

98-98: ⚠️ Potential issue

Correct String Assignment Syntax

Ohayo, Sensei! In Cairo, strings should be enclosed in double quotes. The assignment s.name = 'FooEventBadLayoutType'; uses single quotes, which may cause a syntax error.

Apply this diff to fix the issue:

-                s.name = 'FooEventBadLayoutType';
+                s.name = "FooEventBadLayoutType";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

                s.name = "FooEventBadLayoutType";

66-79: 💡 Codebase verification

⚠️ Potential issue

Missing Module Declarations for Event Test Contracts

Ohayo sensei! After reviewing the codebase, I found that while the event structs are defined, the referenced modules (e_FooEventMemberRemoved, etc.) and their TEST_CLASS_HASH constants are missing. The code expects these modules to be defined similarly to the old_foo_event_bad_layout_type module, but they are not present.

  • Missing module declarations for:
    • e_FooEventMemberRemoved
    • e_FooEventMemberAddedButRemoved
    • e_FooEventMemberAddedButMoved
    • e_FooEventMemberAdded

Each of these modules should be defined with the #[starknet::contract] attribute and include the TEST_CLASS_HASH constant, following the pattern shown in the old_foo_event_bad_layout_type module.

🔗 Analysis chain

Verify References to Event Modules and Constants

Sensei, in the deploy_world_for_event_upgrades function, the code references TEST_CLASS_HASH from modules like e_FooEventMemberRemoved and others. Please ensure that these modules and their constants are correctly defined and imported.

Run the following script to verify the existence of the referenced modules and constants:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the referenced modules and constants are defined.

# Expected: The modules and constants should be found in the codebase.

# Check for module definitions
rg -F "mod e_FooEventMemberRemoved" --type cairo
rg -F "mod e_FooEventMemberAddedButRemoved" --type cairo
rg -F "mod e_FooEventMemberAddedButMoved" --type cairo
rg -F "mod e_FooEventMemberAdded" --type cairo

# Check for TEST_CLASS_HASH constants
rg -F "const TEST_CLASS_HASH" --type cairo

Length of output: 410


Script:

#!/bin/bash
# Let's try without the --type cairo flag since it's not recognized
# First, let's check for module definitions
rg -F "mod e_FooEventMemberRemoved"
rg -F "mod e_FooEventMemberAddedButRemoved"
rg -F "mod e_FooEventMemberAddedButMoved"
rg -F "mod e_FooEventMemberAdded"

# Check for TEST_CLASS_HASH constants
rg -F "const TEST_CLASS_HASH"

# Let's also check the directory structure to understand where these files might be
fd . crates/dojo/core-cairo-test/src/tests/

Length of output: 2050


Script:

#!/bin/bash
# Let's check the content of the event-related files for our modules and TEST_CLASS_HASH
rg -l "FooEvent" crates/dojo/core-cairo-test/src/tests/event/
cat crates/dojo/core-cairo-test/src/tests/event/event.cairo

# Also check the helpers directory since our file is there
rg -l "FooEvent" crates/dojo/core-cairo-test/src/tests/helpers/
cat crates/dojo/core-cairo-test/src/tests/helpers/event.cairo

Length of output: 4107

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (23)
crates/dojo/core/src/model/component.cairo (2)

5-11: Clean trait implementation for deployment concerns!

The separation of IDeployedModelImpl demonstrates good architectural design by isolating deployment-specific functionality. This separation will make future upgrades more manageable and safer.

This clean separation of concerns will be particularly valuable for the new upgradability checks, as it provides a clear boundary between deployment and storage aspects of the model.


Line range hint 27-39: Ohayo! Clean removal of versioning, sensei!

The implementation successfully removes version management while maintaining essential model functionality. This aligns perfectly with the PR objectives.

The removal of versioning in favor of structural upgrade checks is a more robust approach, as it enforces compatibility through actual schema structure rather than arbitrary version numbers.

crates/dojo/core-cairo-test/src/lib.cairo (1)

63-69: Consider documenting the commented-out modules, sensei! 📝

While the new module structure in the world namespace looks good, there are some commented-out modules (entities and world). It would be helpful to add a comment explaining why these are commented out and if they will be needed in the future.

Consider adding documentation like this:

-        //mod entities;
+        // TODO: entities module temporarily disabled until <reason>
-        //mod world;
+        // TODO: world module temporarily disabled until <reason>
crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1)

58-71: Ohayo! Consider enhancing error handling in deployment

The deployment function correctly includes all test models, but the error handling could be more robust. The current .try_into().unwrap() pattern might panic silently.

Consider adding error context:

-            TestResource::Model(m_FooModelBadLayoutType::TEST_CLASS_HASH.try_into().unwrap()),
+            TestResource::Model(
+                m_FooModelBadLayoutType::TEST_CLASS_HASH
+                    .try_into()
+                    .expect('Failed to convert FooModelBadLayoutType class hash')
+            ),
crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (1)

84-89: Clean separation of model implementations, sensei!

The addition of separate implementations for deployed and stored models improves the architecture by clearly distinguishing between the two states. This separation will make the upgradability checks more maintainable.

crates/dojo/core/src/model/model.cairo (1)

39-39: Schema type change enhances model structure validation.

The change from Ty to Struct in the schema method signature provides a more specific type that better represents the model's structure, enabling proper upgradability checks as required by the PR objectives.

This change will help enforce the PR's requirements that:

  • Layout type (Struct/Fixed) remains the same
  • Existing fields cannot be changed or moved
  • New fields can only be appended
crates/torii/types-test/src/contracts.cairo (1)

Line range hint 116-131: Ohayo sensei, we need to address some critical concerns in the delete implementation! 🚨

  1. The hardcoded subrecord_id = record_id + 1 assumption is risky:

    • It may not match the ID assigned during creation
    • Could lead to deleting wrong subrecords
  2. Missing error handling:

    • No checks if records exist before reading
    • Could panic if trying to delete non-existent records
  3. Observability:

    • No events are emitted for deletion tracking
    • Makes it difficult to audit/monitor deletions

Consider this safer implementation:

 fn delete(ref self: ContractState, record_id: u32) {
     let mut world = self.world(@"types_test");
+    // Verify record exists
+    assert(world.model_exists<Record>(record_id), 'Record does not exist');
 
     let record: Record = world.read_model(record_id);
     let record_sibling: RecordSibling = world.read_model(record_id);
 
-    let subrecord_id = record_id + 1;
+    // Read subrecord_id from the record if needed
+    // or maintain a mapping of record_id to subrecord_id
+    let subrecord_id = get_subrecord_id(record_id);
     let subrecord: Subrecord = world.read_model((record_id, subrecord_id));
 
     world.erase_model(@record);
     world.erase_model(@record_sibling);
     world.erase_model(@subrecord);
+
+    // Emit deletion event for tracking
+    world.emit_event(
+        @RecordDeleted { record_id, subrecord_id }
+    );
 }
crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (1)

45-47: Consider enhancing the layout implementation for better test coverage.

Ohayo, sensei! The current implementation returns an empty fixed layout, which might not provide sufficient test coverage for various upgrade scenarios. Consider adding test cases with different layout types and field configurations.

-            dojo::meta::Layout::Fixed([].span())
+            // Example layout with fields for testing upgrade scenarios
+            dojo::meta::Layout::Fixed([
+                ('caller', dojo::meta::abi::Ty::ContractAddress),
+                ('a', dojo::meta::abi::Ty::Felt252),
+                ('b', dojo::meta::abi::Ty::U128),
+            ].span())
crates/dojo/lang/src/attribute_macros/event.rs (1)

41-41: Ohayo! Nice simplification of EventParameters, sensei!

The removal of the common field and improved error handling aligns well with the PR's goal of removing versioning. The direct error reporting provides clearer diagnostics.

Consider adding a doc comment to the EventParameters struct to explain its purpose and the meaning of the historical field:

+/// Parameters for event configuration.
+/// - historical: Determines if the event should be stored in history.
 #[derive(Debug)]
 struct EventParameters {
     historical: bool,
 }

Also applies to: 58-65

crates/dojo/lang/src/attribute_macros/model.rs (2)

155-156: Excellent addition of packed model detection!

This change is crucial for enforcing layout type consistency during upgrades, ensuring that packed models remain packed and unpacked models remain unpacked.

Consider documenting this constraint in the model's documentation to make it clear that the packed/unpacked status cannot be changed during upgrades.


179-179: Effective integration of the unique hash!

The hash is now included in the model's generated code, which will be used for upgrade validation.

Consider adding a comment in the generated code to explain the significance of this hash for upgradability checks.

crates/dojo/core-cairo-test/src/tests/world/event.cairo (3)

99-136: Consider adding more assertions for event properties

Ohayo, sensei! While the test covers the basic upgrade flow, consider adding assertions for:

  • Event schema validation
  • Previous address preservation
  • Event metadata integrity

263-277: Consider enhancing malicious contract test documentation

Ohayo, sensei! The comment about CONTRACT_NOT_DEPLOYED could be more detailed. Consider explaining:

  • Why this specific error is expected
  • What security implications this test covers
  • How this relates to the contract deployment model

1-277: Consider adding missing test scenarios

Ohayo, sensei! While the test coverage is good, consider adding tests for:

  1. Concurrent upgrade attempts
  2. Upgrade with circular dependencies
  3. Gas consumption for large event upgrades
  4. Event removal scenarios
crates/dojo/core-cairo-test/src/tests/world/model.cairo (3)

11-56: Ohayo, sensei! Model structs look good, but could use documentation

The test model structs are well-structured to cover various upgrade scenarios. Consider adding doc comments to explain the purpose of each struct for better maintainability.

Add documentation like this:

+/// Tests model upgrade validation when layout type changes
 #[derive(Introspect, Copy, Drop, Serde)]
 #[dojo::model]
 pub struct FooModelBadLayoutType {

93-102: Consider extracting error messages into constants

Error message strings are duplicated across tests. Consider extracting them into constants for better maintainability and consistency.

Example:

const INVALID_NAME_ERROR: felt252 = 'Name `foo-bis` is invalid according to Dojo naming rules: ^[a-zA-Z0-9_]+$';

283-297: Improve malicious contract test documentation

The comment about CONTRACT_NOT_DEPLOYED could be more descriptive. Consider explaining why this is the current behavior and if it's the intended long-term solution.

Suggested comment:

-// It's CONTRACT_NOT_DEPLOYED for now as in this example the contract is not a dojo contract
-// and it's not the account that is calling the register_model function.
+// TODO: Currently fails with CONTRACT_NOT_DEPLOYED because:
+// 1. The contract is not a dojo contract
+// 2. The caller is not the account calling register_model
+// Consider if this is the desired error message for malicious contract detection
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (2)

252-287: Consider adding negative test cases for class hash validation

Ohayo sensei! While the test covers the happy path for contract upgrades, consider adding test cases for:

  • Upgrading to an invalid class hash
  • Upgrading to a class hash that doesn't implement required interfaces

341-361: Consider adding test for concurrent upgrade attempts

Ohayo sensei! To ensure robustness, consider adding a test case that verifies the behavior when multiple accounts attempt to upgrade the contract simultaneously. This would help validate the system's concurrency handling.

Would you like me to help create a test case that simulates concurrent upgrade attempts?

crates/dojo/core/src/world/world_contract.cairo (2)

436-436: Ohayo! Nice refactoring of resource dispatchers, sensei!

The unification of various dispatcher types (IEventDispatcher, IModelDispatcher) into IDeployedResourceDispatcher improves code maintainability and reduces duplication.

Consider adding a comment explaining the benefits of using IDeployedResourceDispatcher for future maintainers.

Also applies to: 482-482, 540-540, 586-586, 665-665, 720-720


975-1010: Consider enhancing error messages with specific validation failures.

The upgradability check implementation is solid, but error messages could be more descriptive to help developers understand exactly which validation failed:

  • Layout type mismatch
  • Schema incompatibility (field changes/moves)

Consider updating the error messages to include specific details:

-                panic_with_byte_array(@errors::invalid_resource_layout_upgrade(namespace, name));
+                panic_with_byte_array(@errors::invalid_resource_layout_upgrade_details(
+                    namespace, name, @format!("Expected {}, got {}", old_layout, new_layout)
+                ));
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (2)

9-9: Correct the typo in the comment

Sensei, there's a typo in the comment: 'differenciate' should be 'differentiate'.


32-32: Ensure consistent visibility for event structs

Sensei, some event structs are declared without the pub keyword (lines 32~, 41~, 50~, 59~), while FooEventBadLayoutType is declared as pub. For consistency, consider adding pub to these structs if they are intended to be public.

Also applies to: 41-41, 50-50, 59-59

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between df9efb8 and 8a20705.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (43)
  • Cargo.toml (1 hunks)
  • bin/sozo/src/commands/inspect.rs (0 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/Cargo.toml (1 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (2 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (5 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
💤 Files with no reviewable changes (4)
  • bin/sozo/src/commands/inspect.rs
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (22)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/lib.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/introspect.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo
  • crates/dojo/world/src/contracts/abigen/model.rs
  • crates/dojo/world/src/contracts/model.rs
  • examples/spawn-and-move/dojo_dev.toml
🔇 Additional comments (41)
crates/dojo/core/src/model/component.cairo (2)

1-2: Ohayo! Clean and focused imports, sensei!

The imports are well-organized and properly reflect the architectural changes, particularly the introduction of Struct from dojo::meta for schema representation.


14-24: Verify upgrade safety mechanisms, sensei!

The IStoredModelImpl provides essential schema and layout information, but let's verify if additional checks are needed for safe upgrades.

Let's check for any existing upgrade validation code:

✅ Verification successful

Upgrade safety is properly implemented, sensei!

The verification shows that the IStoredModelImpl is part of a robust upgrade safety system:

  1. The schema and layout information are used by the world contract to perform strict upgrade validation:

    • Schema upgrades are checked via is_an_upgrade_of method
    • Layout type compatibility is verified via is_same_type_of
    • New fields can only be appended at the end
    • Existing fields cannot be changed or moved
  2. The implementation is protected by error messages:

    • invalid_resource_schema_upgrade
    • invalid_resource_layout_upgrade

The codebase includes comprehensive test coverage for upgrade scenarios, including tests for:

  • Member removal
  • Member addition
  • Member reordering
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for upgrade-related validation code
echo "Searching for upgrade validation patterns..."
rg -l "upgrade|migration|compatibility" --type cairo

# Look for schema comparison logic
echo "Checking for schema comparison implementations..."
ast-grep --pattern 'fn $_(self: @$_, old_schema: Struct, new_schema: Struct)'

Length of output: 372


Script:

#!/bin/bash
# Let's try a more specific search for Cairo files
echo "Searching for upgrade patterns in .cairo files..."
fd -e cairo -x rg -l "upgrade|migration|compatibility" {} \;

# Search for schema-related implementations
echo "Looking for schema-related code..."
fd -e cairo -x rg -A 5 "schema|Struct" {} \;

# Check for any validation or comparison logic
echo "Checking validation patterns..."
fd -e cairo -x rg -A 5 "validate|compare|check" {} \;

Length of output: 34728

crates/dojo/lang/Cargo.toml (1)

39-39: Ohayo sensei! The starknet-crypto dependency addition looks good!

The dependency is properly configured using workspace-level version management.

Let's verify the workspace configuration:

✅ Verification successful

Ohayo sensei! The starknet-crypto dependency is properly configured in the workspace!

The workspace-level version is correctly defined as 0.7.1 in the root Cargo.toml, which matches with the workspace reference in crates/dojo/lang/Cargo.toml.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify starknet-crypto workspace configuration
# Expected: Find workspace definition of starknet-crypto version

# Test: Search for starknet-crypto in workspace Cargo.toml
rg -A 2 "starknet-crypto.*=" ./Cargo.toml

Length of output: 150

crates/dojo/core-cairo-test/src/lib.cairo (2)

43-59: Ohayo! Nice module organization, sensei! 🎋

The new helpers module structure looks well-organized with clear separation of concerns between general helpers, event-specific, and model-specific functionality. This aligns perfectly with the PR's objective of implementing upgradability checks.


46-49: Verify the exported helper entities, sensei! 🔍

The large number of exported entities from the helpers module suggests these are commonly used test utilities. Let's verify they're all being used to avoid maintaining unused exports.

✅ Verification successful

Ohayo sensei! All helper entities are actively used in tests, no cleanup needed! 🎯

The search results show that all exported helper entities are being used in test files under crates/dojo/core-cairo-test/src/tests/, serving various testing purposes:

  • Test utilities like DOJO_NSH, deploy_world, drop_all_events are widely used across many test files
  • Model entities (Foo, Character, Sword, etc.) are used in benchmark and model tests
  • Contract-related helpers (test_contract, foo_setter) are used in contract and ACL tests
  • Event-related helpers (SimpleEvent, e_SimpleEvent) are used in event tests

None of these entities appear in implementation files under crates/dojo/core/src/, confirming they are properly scoped as test utilities.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage of exported helper entities
# Expected: Each entity should be used in at least one test file

# Search for each exported entity
for entity in "DOJO_NSH" "SimpleEvent" "e_SimpleEvent" "Foo" "m_Foo" "foo_invalid_name" "foo_setter" \
             "test_contract" "test_contract_with_dojo_init_args" "Sword" "Case" "Character" "Abilities" \
             "Stats" "Weapon" "Ibar" "bar" "deploy_world" "deploy_world_and_bar" "deploy_world_and_foo" \
             "drop_all_events" "IFooSetter" "IFooSetterDispatcher" "IFooSetterDispatcherTrait"; do
    echo "Checking usage of $entity:"
    rg "\b$entity\b" --type cairo
done

Length of output: 12140


Script:

#!/bin/bash
# Let's try searching without specifying file type since Cairo files might have different extensions
for entity in "DOJO_NSH" "SimpleEvent" "e_SimpleEvent" "Foo" "m_Foo" "foo_invalid_name" "foo_setter" \
             "test_contract" "test_contract_with_dojo_init_args" "Sword" "Case" "Character" "Abilities" \
             "Stats" "Weapon" "Ibar" "bar" "deploy_world" "deploy_world_and_bar" "deploy_world_and_foo" \
             "drop_all_events" "IFooSetter" "IFooSetterDispatcher" "IFooSetterDispatcherTrait"; do
    echo "=== Checking usage of $entity: ==="
    rg "\b${entity}\b"
done

# Also let's check what files we have in the test directory
echo -e "\n=== Cairo files in the repository: ==="
fd ".*\.cairo$"

Length of output: 187631


Script:

#!/bin/bash
# Let's search for actual usage of these entities in test files
for entity in "DOJO_NSH" "SimpleEvent" "e_SimpleEvent" "Foo" "m_Foo" "foo_invalid_name" "foo_setter" \
             "test_contract" "test_contract_with_dojo_init_args" "Sword" "Case" "Character" "Abilities" \
             "Stats" "Weapon" "Ibar" "bar" "deploy_world" "deploy_world_and_bar" "deploy_world_and_foo" \
             "drop_all_events" "IFooSetter" "IFooSetterDispatcher" "IFooSetterDispatcherTrait"; do
    echo "=== Testing usage of $entity in test files: ==="
    rg -l "\b${entity}\b" "crates/dojo/core-cairo-test/src/tests/"
done

# Let's also check if these are used in actual implementation files
echo -e "\n=== Checking usage in implementation files: ==="
for entity in "DOJO_NSH" "SimpleEvent" "e_SimpleEvent" "Foo" "m_Foo" "foo_invalid_name" "foo_setter" \
             "test_contract" "test_contract_with_dojo_init_args" "Sword" "Case" "Character" "Abilities" \
             "Stats" "Weapon" "Ibar" "bar" "deploy_world" "deploy_world_and_bar" "deploy_world_and_foo" \
             "drop_all_events" "IFooSetter" "IFooSetterDispatcher" "IFooSetterDispatcherTrait"; do
    echo "=== Implementation usage of $entity: ==="
    rg -l "\b${entity}\b" "crates/dojo/core/src/"
done

Length of output: 30029

crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (3)

1-11: Ohayo, sensei! Clean and well-documented imports!

The file's purpose is clearly documented, and the imports are minimal and necessary.


21-55: Ohayo! Well-structured test models for upgrade scenarios

The models are well-designed to test different upgrade scenarios:

  • Member removal (FooModelMemberRemoved)
  • Member addition with removal (FooModelMemberAddedButRemoved)
  • Member movement (FooModelMemberAddedButMoved)
  • Clean member addition (FooModelMemberAdded)

Each model maintains consistent base fields (caller, a, b) which is good for testing upgrades.


12-19: Ohayo! Verify layout type compatibility in upgrade tests

The FooModelBadLayoutType uses IntrospectPacked while other models use Introspect. This difference is intentional for testing layout type incompatibility during upgrades.

Let's verify that no other models in the codebase mix these layout types:

✅ Verification successful

Let me try a different approach to verify this more thoroughly:

This will help us see all model structs and their layout types in context, making it easier to verify if there are any conflicts or if the different layout types are used intentionally for testing purposes.


Ohayo! Layout type usage is intentionally distinct

The search results confirm that IntrospectPacked and Introspect are used deliberately in different contexts:

  1. Test files in core-cairo-test/src/tests/meta/introspect.cairo specifically test both layout types
  2. The only struct using both traits is StructIncompatibleAttrs in test data, which is intentionally used to test incompatibility scenarios
  3. Other models consistently use either one trait or the other, with no unintended mixing

The FooModelBadLayoutType in the test helpers follows this pattern correctly for testing layout type changes during upgrades.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for models using both IntrospectPacked and Introspect
echo "Checking for potential layout type conflicts..."
ast-grep --pattern '#[derive(IntrospectPacked, $$$)] struct $NAME' | \
  while read -r packed; do
    if ast-grep --pattern "#[derive(Introspect, $$$)] struct $NAME" > /dev/null; then
      echo "Warning: Found potential layout type conflict for struct: $NAME"
    fi
done

Length of output: 190


Script:

#!/bin/bash
# Search for all model structs and their layout types
echo "=== Models with IntrospectPacked ==="
rg -B1 "struct.*\{" -A1 | rg -B1 "IntrospectPacked" --context 1

echo -e "\n=== Models with Introspect ==="
rg -B1 "struct.*\{" -A1 | rg -B1 "Introspect[^P]" --context 1

Length of output: 14091

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (2)

33-39: Ohayo! Nice type safety improvement, sensei!

The schema function now correctly enforces that models must be structs and provides a clear error message if this constraint is violated. This change aligns well with the PR's objective of implementing stricter upgradability checks.


110-115: Verify hash computation mechanism, sensei!

The ensure_unique function is a crucial safeguard for model upgradability. Please verify:

  1. How the $unique_hash$ is computed during code generation
  2. Whether the hash includes all necessary model attributes to prevent conflicting upgrades
✅ Verification successful

Let me check the hash computation implementation more thoroughly.


Hash computation mechanism is robust, sensei!

The ensure_unique function's hash is computed securely through:

  1. A Poseidon hash combining:
    • A flag indicating if the model is packed (0 or 1)
    • A hash of the entire struct text (including all members and attributes)
  2. The struct text is converted to a ByteArray and hashed using poseidon_hash_many

This implementation ensures uniqueness based on the complete model definition, preventing conflicting upgrades since any change to model attributes, members, or packing will result in a different hash.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for hash computation logic in the codebase
rg -A 5 "unique_hash" --type rust

Length of output: 3690


Script:

#!/bin/bash
# Get the implementation of compute_bytearray_hash and poseidon_hash_many
rg -A 5 "fn compute_bytearray_hash|fn poseidon_hash_many" --type rust

# Check if there are any tests for the hash computation
rg -A 10 "test.*unique_hash" --type rust

Length of output: 1097

crates/dojo/core/src/model/model.cairo (3)

1-3: Ohayo sensei! The import changes look good for upgradability checks.

The switch from Ty to Struct and addition of layout utilities aligns well with the PR's objective of implementing model upgradability checks. The Struct type provides better structural representation needed for comparing model layouts during upgrades.


91-93: Schema implementation maintains simplicity.

The implementation cleanly delegates to ModelDefinition, maintaining good separation of concerns while supporting the new upgradability checks.


Line range hint 109-116: Model definition correctly reflects versioning removal.

The ModelDef construction has been updated to remove the version field, which aligns with the PR's goal of removing versioning management. The remaining fields provide all necessary information for upgradability checks.

Let's verify that version field references have been consistently removed:

✅ Verification successful

Version field has been completely removed from ModelDef and related code, sensei!

After thorough inspection of the codebase, I can confirm that:

  • The ModelDef struct in model/mod.cairo only contains the expected fields: name, layout, schema, packed_size, and unpacked_size
  • No version-related methods or traits exist in the Model implementation
  • All related files in the model directory are free of version/versioning references

The changes align perfectly with the PR's goal of removing versioning management while maintaining all necessary fields for upgradability checks.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining version-related code
# Expect: No occurrences of version in model definitions or traits

# Search for version-related code in model files
rg -i "version|versioning" "crates/dojo/core/src/model/"

Length of output: 56


Script:

#!/bin/bash
# Let's verify version removal more thoroughly by:
# 1. Check model.cairo for any version-related code
# 2. Search for ModelDef struct definition
# 3. Look for any version-related traits or implementations

# Check the specific model.cairo file content
cat crates/dojo/core/src/model/model.cairo

# Search for ModelDef struct definition using ast-grep
ast-grep --pattern 'struct ModelDef {
    $$$
}'

# Search for any version-related traits or impls
ast-grep --pattern 'trait $_ {
    fn version($$$) $$$
}'

ast-grep --pattern 'impl $_ {
    fn version($$$) $$$
}'

Length of output: 4777


Script:

#!/bin/bash
# Let's check the ModelDef struct definition in the entire codebase
# and any related files that might contain version references

# Find and check content of files containing ModelDef
fd ModelDef --exec cat {}

# Also check the model directory for any other files that might contain version references
fd . crates/dojo/core/src/model/ --exec cat {}

Length of output: 13675

crates/dojo/core-cairo-test/src/tests/contract.cairo (3)

37-37: Ohayo! New import looks good, sensei!

The addition of IDeployedResource aligns perfectly with the PR's objective of enhancing resource management capabilities.


62-63: Empty implementation is zen-like, sensei!

The empty ContractImpl implementation aligns with the PR's goal of simplifying the system by removing unnecessary versioning management.


64-68: New implementation looks solid, sensei!

The Contract_DeployedContractImpl provides the required dojo_name method, which is essential for resource identification in the new system. The implementation is clean and follows the established pattern.

Let's verify the consistency of the dojo_name implementation across other resources:

✅ Verification successful

The previous search failed because the file type wasn't recognized. Let's try a more generic approach to find all dojo_name implementations and the trait definition to verify the consistency.


Ohayo! Implementation is consistent with the dojo way, sensei!

The dojo_name implementation in your contract follows the same pattern as other resources in the codebase. I can see that:

  • The trait IDeployedResource is properly defined in core/src/meta/interface.cairo
  • All implementations consistently return a ByteArray with a descriptive name
  • Your implementation matches the pattern used in other test contracts and components

The implementation is particularly aligned with other test contracts that use similar straightforward string returns, like in world/contract.cairo and other test files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent dojo_name implementations
# Expect: Similar implementations in other resource files

rg -A 2 "fn dojo_name.*->.*ByteArray" --type cairo

Length of output: 82


Script:

#!/bin/bash
# Let's try a more generic search for dojo_name implementations
rg -A 2 "fn dojo_name"

# Also search for trait definitions that might require dojo_name
rg "trait.*DeployedResource"

Length of output: 5862

crates/torii/types-test/src/contracts.cairo (2)

Line range hint 1-5: Ohayo! The interface changes look solid, sensei! 🎋

The new delete method in the IRecords trait is well-defined and maintains consistency with the existing code structure.


112-113: Method chaining looks clean, sensei! ✨

The refactored event emission using method chaining improves code readability while maintaining the same functionality.

crates/dojo/lang/src/attribute_macros/element.rs (3)

7-7: Ohayo! Import changes look good, sensei!

The new imports support the transition from version-based to hash-based identification of structs.

Also applies to: 12-13


Line range hint 1-90: Verify complete removal of versioning, sensei!

The removal of versioning code aligns with the PR objectives. Let's verify no versioning references remain.

#!/bin/bash
# Description: Check for any remaining version-related code
echo "Checking for remaining version references..."
rg -i 'version|versioning' --type rust

86-90: Excellent hash computation implementation, sensei!

The function provides a robust way to uniquely identify structs by combining:

  1. Packing information (as a flag)
  2. Struct content hash

This approach is more reliable than version-based identification.

Let's verify the uniqueness of hashes across different structs:

✅ Verification successful

Excellent hash implementation verified, sensei!

The compute_unique_hash function is used consistently across the codebase for:

  • Model structs (with packing flag consideration)
  • Event structs (always unpacked)

The implementation ensures uniqueness by combining:

  1. A packing flag (0 or 1)
  2. The struct's text content hash

This provides reliable struct identification without any risk of collisions between packed/unpacked versions of the same struct or between different structs.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential hash collisions in struct definitions
# Look for struct definitions and their packing attributes
ast-grep --pattern 'struct $name {
  $$$
}'

Length of output: 38337


Script:

#!/bin/bash
# Let's search for struct definitions and their hashing in the codebase
ast-grep --pattern 'compute_unique_hash($$$)'

# Also search for any references to this hash computation
rg -A 3 "compute_unique_hash"

Length of output: 2231

crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (2)

66-68: LGTM! Clean implementation of the new model definition pattern.

Ohayo, sensei! The changes effectively integrate the new trait methods while removing version management, aligning perfectly with the PR objectives.


Line range hint 37-68: Verify test coverage for upgrade scenarios.

Ohayo, sensei! Let's ensure we have comprehensive test coverage for the new upgrade constraints mentioned in the PR objectives.

✅ Verification successful

Test coverage for upgrade scenarios is properly implemented

Ohayo, sensei! After analyzing the codebase, I can confirm that the test coverage for upgrade scenarios is comprehensive:

  • The test helper file is part of a well-structured test suite in core-cairo-test/src/tests/
  • Upgrade scenarios are thoroughly tested in:
    • crates/dojo/core-cairo-test/src/tests/world/model.cairo - tests model upgrades with member removal, addition and movement
    • crates/dojo/core-cairo-test/src/tests/world/event.cairo - tests event upgrades with member removal, addition and movement
  • The implementation properly validates schema and layout compatibility during upgrades in crates/dojo/core/src/world/world_contract.cairo
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for test cases covering upgrade scenarios

# Test: Search for upgrade-related test cases
echo "Searching for upgrade-related test cases..."
rg -l "upgrade|layout|schema" --type cairo

# Test: Check test files for different layout types
echo "Checking test coverage for different layout types..."
rg -A 5 "Layout::(Fixed|Struct)" --type cairo

Length of output: 364


Script:

#!/bin/bash
# Let's try without file type filtering since cairo isn't recognized
echo "Searching for upgrade-related test cases..."
rg -l "upgrade|layout|schema"

echo "Checking test coverage for different layout types..."
rg -A 5 "Layout::Fixed|Layout::Struct"

# Also search for model definitions and schemas
echo "Searching for model definitions and schemas..."
rg -A 5 "ModelDef|schema"

Length of output: 260035

crates/dojo/lang/src/attribute_macros/event.rs (2)

21-21: Ohayo! The import addition looks good, sensei!

The compute_unique_hash import aligns with the PR's objective of implementing upgradability checks.


167-169: Verify the unique hash computation implementation.

The hash computation is crucial for upgradability checks. Let's verify its consistency with other resource types.

Also, consider adding a comment explaining the false parameter's purpose in the hash computation.

Also applies to: 180-180

✅ Verification successful

Let me gather more context about the is_packed parameter by checking its usage and documentation.


Hash computation is correctly implemented for events, sensei!

The false parameter in compute_unique_hash for events is correct because:

  • Events are never packed, unlike models which can be packed or unpacked
  • Models use is_packed flag based on presence of DOJO_PACKED_DERIVE
  • The implementation in element.rs uses this boolean to include Felt::ONE or Felt::ZERO in the hash computation

The consistent pattern across the codebase shows:

  • Models: Variable packing based on derives
  • Events: Always unpacked (false)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if unique hash computation is consistent across different resource types

# Test: Search for other compute_unique_hash usages
echo "Checking compute_unique_hash usage patterns:"
rg -A 2 "compute_unique_hash\(" 

# Test: Verify the second parameter (false) usage pattern
echo "\nChecking the boolean parameter patterns:"
ast-grep --pattern 'compute_unique_hash($_, false)'

Length of output: 1309


Script:

#!/bin/bash
# Check for documentation or comments about is_packed parameter
echo "Checking for documentation about is_packed:"
rg -B 3 "is_packed" 

# Check the implementation of compute_unique_hash
echo "\nChecking compute_unique_hash implementation:"
ast-grep --pattern 'fn compute_unique_hash($$$)'

# Check for any model attributes that might set is_packed
echo "\nChecking for model attributes related to packing:"
rg "#\[model\]" -A 10

Length of output: 3728

crates/dojo/lang/src/attribute_macros/model.rs (3)

18-19: Ohayo! Nice modularization of element-related functionality, sensei!

The separation of compute_unique_hash into the element module promotes better code organization and reusability.


Line range hint 1-214: Ohayo sensei! A note about versioning removal.

The removal of ModelParameters and versioning aligns with the PR objectives. However, to ensure a smooth transition:

Let's check for any remaining version-related code that might need cleanup:

#!/bin/bash
# Description: Check for any remaining version-related code

# Test: Search for version-related code in model implementations
rg -i "version.*model" 

# Test: Search for version-related types or traits
ast-grep --pattern "trait $_ {
  $$$
  version
  $$$
}"

160-162: Strategic implementation of unique hash computation!

The unique hash computation considers both the struct's text and packing status, which effectively enforces the upgrade constraints:

  1. Same layout type (packed/unpacked)
  2. No changes to existing fields (captured in struct text)
  3. Only allows appending new fields (any modification to existing fields changes the hash)

Let's verify the hash computation behavior:

✅ Verification successful

Ohayo sensei! After analyzing the implementation, I can now provide a definitive response about the hash computation.

The unique hash computation is correctly implemented for model upgrades!

The implementation in element.rs shows that compute_unique_hash uses:

  1. A Poseidon hash combining:
    • Layout type flag (is_packed: bool) -> Felt::ONE for packed, Felt::ZERO for unpacked
    • Struct text hash (computed from the entire struct definition)

This ensures:

  • Layout type changes are detected (packed/unpacked flag)
  • Any modification to existing fields is detected (struct text hash changes)
  • Only appending new fields is allowed (existing field text remains unchanged)

The implementation in the codebase matches exactly what the review comment stated about enforcing upgrade constraints through the hash computation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the hash computation correctly detects field modifications

# Test: Search for test cases that verify hash computation
rg -A 5 "compute_unique_hash.*test"

# Test: Search for examples of model upgrades in tests
rg -A 10 "model.*upgrade.*test"

Length of output: 624


Script:

#!/bin/bash
# Let's search for the compute_unique_hash implementation and its tests
ast-grep --pattern 'fn compute_unique_hash($_) {
  $$$
}'

# Search for model upgrade tests with more context
rg -A 15 "test.*model.*upgrade"

# Search for hash computation in test files
fd "test" --exec rg -l "compute_unique_hash" {}

# Look for model attribute tests
fd "test" --exec rg -l "model.*attribute" {}

Length of output: 2884


Script:

#!/bin/bash
# Let's look at the implementation of compute_unique_hash
rg -A 10 "fn compute_unique_hash"

# Check the model test files more specifically
fd "model.*test" --exec cat {}

# Look for model upgrade validation tests
rg -A 10 "test.*model.*validation"

# Search for any hash comparison in tests
rg -A 5 "assert.*hash.*model"

Length of output: 34560

crates/dojo/core-cairo-test/src/tests/world/event.cairo (3)

10-46: LGTM! Well-structured event definitions

Ohayo, sensei! The event structs are well-defined with appropriate attributes and field types. Each struct serves a specific purpose in testing different upgrade scenarios:

  • FooEventMemberRemoved: Tests field removal
  • FooEventMemberAddedButRemoved: Tests field addition and removal
  • FooEventMemberAddedButMoved: Tests field movement
  • FooEventMemberAdded: Tests field addition

48-80: LGTM! Comprehensive event registration test

The test properly verifies:

  • Event registration by namespace owner
  • Event properties (name, namespace, class_hash)
  • Owner role assignment

165-214: LGTM! Thorough upgrade validation tests

The tests effectively cover various upgrade scenarios:

  • Layout type changes
  • Member removal
  • Member addition and removal
  • Member movement

Each test properly verifies that invalid upgrades are rejected with appropriate error messages.

crates/dojo/core-cairo-test/src/tests/world/model.cairo (3)

72-72: Fix typo in assertion message


136-136: Fix typos in assertion messages

Also applies to: 169-169


121-297: Ohayo, sensei! Comprehensive test coverage for model upgrades

The test suite thoroughly covers various upgrade scenarios including:

  • Valid upgrades from model owner
  • Permission checks
  • Invalid schema changes
  • Malicious attempts

Great job on ensuring robust validation of model upgrades!

crates/dojo/core-cairo-test/src/tests/world/contract.cairo (2)

159-189: LGTM! Well-structured test with good event validation

The test case properly validates the contract deployment process and event emission. Good job on checking all relevant fields in the event.


40-42: ⚠️ Potential issue

Fix type mismatch in return value

Ohayo sensei! The function returns a string literal where a felt252 is expected. While this might work due to implicit conversion, it's better to be explicit about the type.

Apply this diff to fix the type:

fn plz_more_tps(self: @ContractState) -> felt252 {
-    'daddy'
+    'daddy'.into()
}

Likely invalid or redundant comment.

crates/dojo/core/src/world/world_contract.cairo (3)

42-45: LGTM! Well-structured imports for resource comparison.

The new imports from dojo::meta provide the necessary traits for comparing resource layouts and schemas during upgrades.


Line range hint 755-759: Previous comment about non-Dojo contract handling is still valid.


Line range hint 1028-1059: Previous comment about non-Dojo caller handling is still valid.

crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (2)

105-108: Duplicate comment: Review the implementation of the layout function


70-75: ⚠️ Potential issue

Verify the module names for event class hashes

Sensei, the module names e_FooEventMemberRemoved, e_FooEventMemberAddedButRemoved, e_FooEventMemberAddedButMoved, and e_FooEventMemberAdded used when retrieving TEST_CLASS_HASH may not correspond to actual modules defined in the code. Please verify that these modules are correctly defined and accessible.

Run the following script to verify the existence of the modules:

✅ Verification successful

The previous search was too specific. Let's broaden our search to find any related event definitions and understand the context better. This will help us verify if these modules exist under different names or in different forms.


I see the event structs are defined, but let's verify the complete file content to ensure we understand how these events are structured and used.


All event modules are correctly defined and used

Ohayo sensei! After careful verification, I can confirm that all the event modules referenced in the code are correctly defined and used. The file shows that:

  • All event structs are properly defined with the #[dojo::event] attribute
  • The TEST_CLASS_HASH references in the deploy_world_for_event_upgrades function correspond to the defined event structs
  • The module names match exactly with the usage: e_FooEventMemberRemoved, e_FooEventMemberAddedButRemoved, e_FooEventMemberAddedButMoved, and e_FooEventMemberAdded
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the modules are defined in the codebase.

# Expected result: The module definitions should be found.

rg -A 3 $'mod e_FooEventMemberRemoved'
rg -A 3 $'mod e_FooEventMemberAddedButRemoved'
rg -A 3 $'mod e_FooEventMemberAddedButMoved'
rg -A 3 $'mod e_FooEventMemberAdded'

Length of output: 171


Script:

#!/bin/bash
# Let's try a broader search for these event-related modules and structs
# First, let's search for any file that might contain these event definitions
fd -e cairo | xargs rg -l "FooEvent"

# Then let's look for any struct or mod definitions related to these events
rg -A 3 "(?:struct|mod).*FooEvent.*"

# Finally, let's check for TEST_CLASS_HASH usage in cairo files
rg "TEST_CLASS_HASH" -A 2 -g "*.cairo"

Length of output: 42794


Script:

#!/bin/bash
# Let's check the specific file content to understand the event structure definitions
cat crates/dojo/core-cairo-test/src/tests/helpers/event.cairo

Length of output: 3322

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (17)
crates/dojo/core-cairo-test/src/lib.cairo (1)

64-64: Consider cleaning up commented code

There are commented-out module declarations:

//mod entities;
//mod world;

If these modules are no longer needed, consider removing them entirely. If they're planned for future implementation, please add a TODO comment explaining the plan.

Also applies to: 69-69

crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (1)

Line range hint 44-63: Clean implementation of the new resource-based architecture!

The implementation nicely ties together all aspects:

  • Correctly delegates to specialized traits
  • Removes versioning as per PR objectives
  • Maintains clear separation of concerns between deployment, storage, and model definitions

Consider documenting this pattern as it serves as a good example of the new resource-based architecture.

crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (1)

64-87: Excellent architectural design for event upgradability, sensei!

The new implementation structure with separate concerns (Deployed, Stored, and base Event) provides a solid foundation for managing upgradable events. The ensure_abi and ensure_unique functions are particularly valuable safeguards:

  • ensure_abi: Maintains ABI compatibility during upgrades
  • ensure_unique: Prevents class hash collisions

Consider documenting these upgrade-safety mechanisms in the module-level documentation to help other developers understand the importance of these safeguards.

crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1)

32-64: Consider making all event structs public, sensei!

The FooEventMemberRemoved, FooEventMemberAddedButRemoved, FooEventMemberAddedButMoved, and FooEventMemberAdded structs are missing the pub modifier, while FooEventBadLayoutType is public. For consistency and to ensure proper accessibility in tests, consider making all event structs public.

-struct FooEventMemberRemoved {
+pub struct FooEventMemberRemoved {

-struct FooEventMemberAddedButRemoved {
+pub struct FooEventMemberAddedButRemoved {

-struct FooEventMemberAddedButMoved {
+pub struct FooEventMemberAddedButMoved {

-struct FooEventMemberAdded {
+pub struct FooEventMemberAdded {
crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (1)

84-89: Excellent separation of concerns, sensei!

The addition of distinct implementations for deployed and stored models provides a clean architecture for handling model upgradability. The ABI embedding ensures proper external accessibility.

This separation will make it easier to manage model upgrades and maintain backward compatibility.

crates/dojo/core/src/model/model.cairo (1)

39-39: Excellent change to schema return type, sensei!

The switch from Ty to Struct is a key enabler for implementing model upgradability checks. This change will allow for more precise layout validation when upgrading models.

This change enables:

  • Strict layout type checking (Struct vs Fixed)
  • Field position validation
  • New field appendability verification
crates/torii/types-test/src/contracts.cairo (1)

Ohayo! The delete implementation needs refinement, sensei!

Looking at the model definitions, I can see that:

  1. Subrecord has a composite key of (record_id, subrecord_id), so the assumption of record_id + 1 is incorrect
  2. There's no direct relationship field between Record and Subrecord in the model definitions
fn delete(ref self: ContractState, record_id: u32) {
    let mut world = self.world(@"types_test");

-    let record: Record = world.read_model(record_id);
-    let record_sibling: RecordSibling = world.read_model(record_id);
-
-    let subrecord_id = record_id + 1;
-    let subrecord: Subrecord = world.read_model((record_id, subrecord_id));
-
-    world.erase_model(@record);
-    world.erase_model(@record_sibling);
-    world.erase_model(@subrecord);
+    // Delete main record if it exists
+    if let Option::Some(record) = world.try_read_model::<Record>(record_id) {
+        // Delete sibling if it exists
+        if let Option::Some(record_sibling) = world.try_read_model::<RecordSibling>(record_id) {
+            world.erase_model(@record_sibling);
+        }
+        
+        // Delete the main record last
+        world.erase_model(@record);
+        
+        // Note: Subrecords cannot be automatically deleted since there's no way to 
+        // know which subrecord_ids are associated with this record_id
+    }
}
🔗 Analysis chain

Line range hint 116-131: Critical concerns in delete implementation, sensei!

The delete implementation has several potential issues that need attention:

  1. The hardcoded subrecord_id = record_id + 1 assumption is risky and might lead to incorrect deletions. Consider retrieving the correct subrecord_id from the record data or maintaining a proper relationship.

  2. Missing error handling for non-existent records. The current implementation will panic if any of the models don't exist.

  3. No transaction safety - if any erase operation fails, the system could be left in an inconsistent state.

Consider implementing this safer version:

fn delete(ref self: ContractState, record_id: u32) {
    let mut world = self.world(@"types_test");

-    let record: Record = world.read_model(record_id);
-    let record_sibling: RecordSibling = world.read_model(record_id);
-
-    let subrecord_id = record_id + 1;
-    let subrecord: Subrecord = world.read_model((record_id, subrecord_id));
-
-    world.erase_model(@record);
-    world.erase_model(@record_sibling);
-    world.erase_model(@subrecord);
+    // Check if record exists first
+    match world.try_read_model::<Record>(record_id) {
+        Option::Some(record) => {
+            // Get associated records
+            if let Option::Some(record_sibling) = world.try_read_model::<RecordSibling>(record_id) {
+                world.erase_model(@record_sibling);
+            }
+            
+            // Get all subrecords associated with this record
+            // Note: Proper subrecord relationship should be implemented
+            if let Option::Some(subrecord) = world.try_read_model::<Subrecord>((record_id, record.subrecord_id)) {
+                world.erase_model(@subrecord);
+            }
+            
+            // Delete the main record last
+            world.erase_model(@record);
+        },
+        Option::None => {
+            // Handle non-existent record case
+            panic!("Record not found");
+        }
+    }
}

Let's verify the subrecord relationship implementation:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for subrecord relationship definition
rg -t cairo "struct.*Record.*{" --context 5

Length of output: 143


Script:

#!/bin/bash
# Search for Record struct definition with fixed pattern
rg -t cairo "struct Record" -A 5

# Search for Subrecord struct definition
rg -t cairo "struct Subrecord" -A 5

# Search for RecordSibling struct definition
rg -t cairo "struct RecordSibling" -A 5

# Search for any model registration of these types
rg -t cairo "world\.register_model" -A 2

Length of output: 277


Script:

#!/bin/bash
# Search for Record struct definition without file type filter
rg "struct Record" -A 5

# Search for Subrecord struct definition
rg "struct Subrecord" -A 5

# Search for RecordSibling struct definition
rg "struct RecordSibling" -A 5

# Search for any model registration
rg "world\.register_model" -A 2

Length of output: 19375

crates/dojo/lang/src/attribute_macros/element.rs (1)

86-107: Solid implementation of unique hash computation, but could use documentation, sensei!

The implementation correctly captures all structural aspects needed for upgradability verification (element name, packed status, and member details). However, adding documentation would help explain:

  • The purpose of this hash in upgradability checks
  • Why each component (name, packed status, members) is essential
  • How this relates to the upgradability conditions mentioned in the PR description

Consider adding documentation like:

/// Computes a unique hash for a Dojo element that's used to verify upgradability.
/// This hash captures the immutable structural properties that must remain unchanged during upgrades:
/// - Element name
/// - Packed/unpacked status
/// - Member names and types in their original order
///
/// This ensures that upgrades maintain backward compatibility by:
/// - Preserving the same layout type
/// - Preventing changes to existing fields
/// - Only allowing new fields to be appended
crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (1)

Line range hint 37-68: Well-structured foundation for upgradability checks.

Ohayo, sensei! The separation of concerns between DeployedModelImpl and StoredModelImpl provides a solid foundation for implementing the upgradability checks mentioned in the PR objectives. This structure will make it easier to:

  1. Enforce layout type consistency
  2. Prevent changes to existing fields
  3. Allow new fields only at the end of the resource

Consider documenting these constraints in the code comments to help future maintainers understand the upgrade rules.

crates/dojo/lang/src/attribute_macros/event.rs (1)

167-170: Ohayo! Please add documentation for the unique hash computation.

The unique hash is crucial for upgradability checks, but its purpose and significance aren't documented. Consider adding comments explaining:

  • How the hash is used in upgradability verification
  • Why false is used for the packed parameter
  • What changes would affect/not affect the hash

This documentation would help maintainers understand the upgrade constraints.

Also applies to: 181-181

crates/dojo/lang/src/attribute_macros/model.rs (2)

160-163: Essential for upgradability: Unique hash computation.

The compute_unique_hash implementation is a key component for enforcing model upgradability rules. It generates a unique identifier based on the model's structure and packing status, which will help detect incompatible changes.

Consider documenting the hash computation strategy in the codebase to help developers understand which model changes are allowed during upgrades.


Line range hint 1-224: Ohayo sensei! Consider adding upgrade-specific validation.

While the changes lay the groundwork for model upgradability checks, we might want to add explicit validation logic to ensure:

  1. Layout type (Struct/Fixed) remains consistent
  2. Existing fields aren't modified or moved
  3. New fields are only appended at the end

Consider adding a validation function like this:

fn validate_model_upgrade(
    old_model: &ItemStruct,
    new_model: &ItemStruct,
    db: &dyn SyntaxGroup
) -> Result<(), String> {
    // Validate layout type consistency
    if old_model.is_packed() != new_model.is_packed() {
        return Err("Cannot change model layout type during upgrade".to_string());
    }
    
    // Validate existing fields
    let old_members = parse_members(db, &old_model.members(db).elements(db));
    let new_members = parse_members(db, &new_model.members(db).elements(db));
    
    // Check that all old fields exist unchanged in new model
    for old_member in old_members {
        if let Some(new_member) = new_members.iter().find(|m| m.name == old_member.name) {
            if new_member.ty != old_member.ty {
                return Err(format!("Field {} type cannot be changed", old_member.name));
            }
        } else {
            return Err(format!("Field {} cannot be removed", old_member.name));
        }
    }
    
    Ok(())
}
crates/dojo/core-cairo-test/src/tests/world/event.cairo (1)

216-277: Consider enhancing error message validation

Ohayo, sensei! While the error cases are well-tested, consider extracting the expected error messages into constants. This would:

  • Make the tests more maintainable
  • Reduce duplication of error strings
  • Make it easier to update error messages across all tests

Example:

const ERROR_UNAUTHORIZED: (&str, &str) = ("Account does NOT have OWNER role", "ENTRYPOINT_FAILED");
const ERROR_INVALID_LAYOUT: (&str, &str) = ("Invalid new layout", "ENTRYPOINT_FAILED");
crates/dojo/core-cairo-test/src/tests/world/model.cairo (3)

11-56: Ohayo, sensei! Model structs are well-structured but could use documentation.

The model structs effectively cover different upgrade scenarios. Consider adding doc comments to explain the purpose of each struct and what upgrade scenario it tests.

Add documentation like this:

+/// Tests model upgrade with incompatible layout type changes
 #[derive(Introspect, Copy, Drop, Serde)]
 #[dojo::model]
 pub struct FooModelBadLayoutType {

121-236: Ohayo, sensei! Consider adding test for field type changes.

The upgrade tests comprehensively cover structural changes, but there's an opportunity to add a test case for field type modifications (e.g., changing u128 to u256).

Would you like me to help create a test case for field type changes?


283-284: Ohayo, sensei! Enhance the explanatory comment.

The current comment could be more descriptive about the security implications.

Consider updating the comment to:

-// It's CONTRACT_NOT_DEPLOYED for now as in this example the contract is not a dojo contract
-// and it's not the account that is calling the register_model function.
+// This test verifies that malicious contracts cannot bypass permission checks by impersonating
+// authorized accounts. The CONTRACT_NOT_DEPLOYED error occurs because the calling contract
+// is not a registered dojo contract, preventing potential security exploits.
crates/dojo/core/src/world/world_contract.cairo (1)

Line range hint 1028-1059: Consider handling non-Dojo contracts more gracefully.

The error handling assumes the caller is either an account or a Dojo contract. As noted in the comments, this could be improved using SRC5 interface detection.

Consider implementing this improvement:

-                let d = IDeployedResourceDispatcher { contract_address: caller };
-                format!("Contract `{}`", d.dojo_name())
+                // Check if contract implements IDescriptor using SRC5
+                match ISRC5Dispatcher { contract_address: caller }
+                    .supports_interface(IDescriptor::ID) {
+                    true => {
+                        let d = IDeployedResourceDispatcher { contract_address: caller };
+                        format!("Contract `{}`", d.dojo_name())
+                    },
+                    false => format!("Contract `{:?}`", caller)
+                }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8a20705 and 21369dc.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (43)
  • Cargo.toml (1 hunks)
  • bin/sozo/src/commands/inspect.rs (0 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/Cargo.toml (1 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (2 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (5 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
💤 Files with no reviewable changes (4)
  • bin/sozo/src/commands/inspect.rs
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (23)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/tests/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/event/event.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/lib.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/introspect.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/component.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/Cargo.toml
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
  • crates/dojo/world/src/contracts/model.rs
  • examples/spawn-and-move/dojo_dev.toml
🔇 Additional comments (39)
crates/dojo/core-cairo-test/src/lib.cairo (2)

43-59: Ohayo! Clean and well-organized module structure, sensei! 🎋

The new helpers module structure is well-organized with clear separation into sub-modules (helpers, event, and model) and explicit public exports. This modular approach enhances maintainability and makes the testing utilities more accessible.


63-63: LGTM! Well-structured world module organization

The world module's organization with separate concerns for acl, contract, event, metadata, model, and namespace follows good separation of concerns principles.

Also applies to: 65-68

crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (2)

14-17: Ohayo! Implementation looks clean, sensei!

The switch from ContractImpl to DojoDeployedModelImpl aligns well with the new resource-based architecture. The implementation is minimal and focused.


35-40: Verify if empty layout and schema are intended for testing, sensei.

The implementation returns empty spans for both layout and schema attributes. While this might be intentional for testing selector attacks, we should verify this is the desired behavior.

✅ Verification successful

Empty layout and schema are intentional for selector attack tests, sensei!

The empty layout and schema implementation is correct and intentional for this test case. The evidence shows:

  1. Similar empty layouts are used in other test files:

    • event.cairo: Uses empty layout for testing events
    • helpers.cairo: Uses empty layout/schema for test helpers
    • selector_attack.cairo: Our current test case
  2. The pattern is specifically used in test files to:

    • Test edge cases and attack vectors
    • Mock simple implementations for testing
    • Verify behavior with minimal structures
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other test files to see if empty layouts/schemas are common in tests
rg -t cairo "Layout::Fixed\(\[\]\.span\(\)\)" --context 3
rg -t cairo "children: \[\]\.span\(\)" --context 3

Length of output: 172


Script:

#!/bin/bash
# Search for layout and schema patterns without file type restriction
rg "Layout::Fixed\(\[\]\.span\(\)\)" --context 3
rg "children: \[\]\.span\(\)" --context 3

# Also search for similar patterns to catch variations
rg "Layout::Fixed\(" --context 3
rg "struct \{.*children:.*span\(\)" --context 3

Length of output: 52413

crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (1)

22-28: Ohayo! Nice type safety enhancement, sensei!

The change from Ty to Struct with explicit type checking improves safety and aligns well with the upgradability requirements. The panic message is clear and helpful for debugging.

crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (3)

1-19: Ohayo! The base event structure looks solid, sensei!

The imports are clean, and the FooBaseEvent structure is well-documented with proper field types and key attributes.


105-108: Previous comment about the layout function implementation is still valid.

The concern about returning an empty layout and potential runtime issues remains unaddressed.


66-79: Verify module naming consistency and existence, sensei!

There's an inconsistency in module references:

  • old_foo_event_bad_layout_type is used directly
  • Other modules use the e_ prefix

Let's verify that all referenced modules exist and follow consistent naming.

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (1)

33-39: Ohayo! Nice type safety improvement, sensei!

The schema function now explicitly returns a Struct and includes runtime validation, which aligns well with the model upgradability requirements. The panic message is clear and helpful for debugging.

crates/dojo/core/src/model/model.cairo (2)

1-3: Ohayo! Import changes look good, sensei!

The switch from Ty to Struct aligns perfectly with the new model upgradability requirements.


Line range hint 91-115: Definition implementation is properly adapted, sensei!

The removal of versioning is cleanly implemented, and the ModelDef structure retains all necessary fields for upgradability validation (layout, schema, sizes).

Let's verify that versioning is consistently removed across related files:

✅ Verification successful

Ohayo! Version removal is perfectly executed, sensei!

The verification confirms that:

  • No version-related references remain in the model directory
  • ModelDef struct in definition.cairo is cleanly defined without any version field
  • All essential fields (name, layout, schema, packed_size, unpacked_size) are present and properly structured
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining version-related code in model definitions
# Expect: No occurrences of version in model-related files

echo "Checking for remaining version references in model files..."
rg -i 'version' --type rust --type cairo crates/dojo/core/src/model/

Length of output: 227


Script:

#!/bin/bash
# Let's try a more direct approach without file type filtering
echo "Checking for version references in model directory..."
rg -i 'version' crates/dojo/core/src/model/

# Also check for ModelDef struct definition to ensure version field is removed
echo -e "\nChecking ModelDef struct definition..."
rg 'struct ModelDef' -A 10 crates/dojo/core/src/model/

Length of output: 789

crates/torii/types-test/src/contracts.cairo (2)

Line range hint 1-5: Ohayo! Clean interface extension, sensei!

The addition of the delete method to the IRecords trait is well-structured and maintains consistency with the existing types.


112-113: Method chaining improves readability, sensei!

The refactored event emission using method chaining enhances code readability while maintaining the same functionality.

crates/dojo/lang/src/attribute_macros/element.rs (2)

7-7: Ohayo! New imports look good, sensei!

The addition of MemberAst and hash-related imports aligns perfectly with the new functionality for computing unique hashes and handling model upgradability.

Also applies to: 12-13


Line range hint 1-107: Verify complete removal of versioning references

The versioning-related code has been removed as intended, but let's verify there are no remaining references that might cause confusion.

✅ Verification successful

Let me search more specifically for versioning in the element module and related code:


Ohayo sensei! After checking the codebase, I can now provide a clear response about the versioning removal:

✓ Versioning removal is complete and correct

The code changes in element.rs and related files show no remaining versioning references that would need attention. The only version-related entry found is the standard workspace version configuration in Cargo.toml, which is expected and should remain.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining version-related code in the codebase
# that might need to be updated for consistency

# Search for version-related terms in the codebase
echo "Searching for potential version references..."
rg -i "version|versioning" \
   --type rust \
   --glob "!target/" \
   -g "!Cargo.toml" \
   -g "!Cargo.lock"

Length of output: 38269


Script:

#!/bin/bash
# Search for version-related code in element.rs and related files
rg -i "version" \
   --type rust \
   -g "crates/dojo/lang/src/attribute_macros/element.rs" \
   -g "crates/dojo/lang/src/attribute_macros/mod.rs" \
   -g "crates/dojo/lang/src/lib.rs" \
   -A 3 -B 3

# Check if there are any version-related imports or dependencies
rg -i "version" \
   --type rust \
   -g "crates/dojo/lang/Cargo.toml"

Length of output: 280

crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3)

37-41: LGTM! Test-specific implementation noted.

Ohayo, sensei! The implementation of DeployedModelImpl looks good. The intentionally different name ("foo-bis") appears to be for testing purposes, which is appropriate in this context.


66-68: LGTM! Clean delegation to specialized implementations.

Ohayo, sensei! The definition method has been nicely refactored to use the new specialized implementations, which aligns well with the PR's objective of improving resource management.


44-47: Verify the empty fixed layout implementation.

Ohayo, sensei! The layout method returns an empty fixed layout. Please confirm if this is intentional for testing purposes or if it should include the actual model fields.

✅ Verification successful

Empty fixed layout is correct for this test helper

Ohayo, sensei! After analyzing the codebase, I can confirm that the empty fixed layout is intentional and correct for this test helper. Here's why:

  1. This is in a test helper file (core-cairo-test/src/tests/helpers/helpers.cairo) specifically designed for testing purposes
  2. Other test files like selector_attack.cairo also use empty fixed layouts for similar test scenarios
  3. The empty layout pattern (Layout::Fixed([].span())) is used in test contexts where the actual layout implementation is not relevant for the test case
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if other test files use non-empty layouts
rg -A 3 "Layout::Fixed\(" --type cairo

Length of output: 70


Script:

#!/bin/bash
# Search for Layout::Fixed pattern in cairo files using ast-grep
ast-grep --pattern 'Layout::Fixed($$$)'

# Also search for any Layout implementations to understand the context
ast-grep --pattern 'fn layout($$$) -> dojo::meta::Layout {'

Length of output: 733


Script:

#!/bin/bash
# Let's search for any test files or examples that might show the intended usage
rg -g "*.cairo" "IStoredResource" -A 5

# Also check for any documentation or comments about Layout::Fixed
rg -g "*.cairo" "Layout::Fixed" -B 2 -A 2

Length of output: 24261

crates/dojo/lang/src/attribute_macros/event.rs (2)

21-21: Ohayo sensei! LGTM on the compute_unique_hash import!

The addition of compute_unique_hash import aligns well with the PR's objective of implementing upgradability checks.


Line range hint 167-181: Verify impact on existing events.

The removal of versioning and addition of unique hash computation represents a significant change in how events are handled.

Let's verify the impact on existing events:

crates/dojo/lang/src/attribute_macros/model.rs (3)

18-22: Ohayo sensei! LGTM on the import changes!

The new imports align well with the PR's objective of implementing model upgradability checks. The compute_unique_hash import is particularly relevant for tracking model changes.


180-180: LGTM on hash integration!

The unique hash is properly integrated into the RewriteNode interpolation, ensuring it's available for upgrade validation.


155-156: Verify packed model handling implications.

The is_packed flag determination is crucial for model upgradability. We should ensure that changing a model's packed status is properly restricted during upgrades.

✅ Verification successful

Ohayo sensei! Based on the evidence gathered from the codebase, I can now provide a conclusive response:

Model packed status changes are properly validated during upgrades

The codebase shows robust validation for model upgrades through:

  • Schema validation that prevents invalid upgrades (as seen in world/errors.cairo)
  • Test coverage for bad layout types and invalid schema changes
  • Unique hash computation that includes the packed status (compute_unique_hash function takes is_packed as a parameter)

The packed status is part of the model's identity and schema validation, making it impossible to change during upgrades without proper validation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any existing upgrade validation logic related to packed models
rg -A 5 "is_packed.*upgrade" 
ast-grep --pattern 'fn $upgrade_fn($_, $_) {
  $$$
  is_packed
  $$$
}'

Length of output: 104


Script:

#!/bin/bash
# Let's search more broadly for packed model handling
rg -A 10 "is_packed" 

# Also search for upgrade-related functionality
rg -A 10 "upgrade.*model"

# Look for model validation logic
ast-grep --pattern 'fn validate($$$) {
  $$$
}'

Length of output: 34786


Script:

#!/bin/bash
# Let's look for model upgrade validation logic in the core tests
rg -A 10 "test.*upgrade.*model.*bad|test.*model.*upgrade.*invalid" crates/dojo/core-cairo-test/

# Search for model upgrade implementation details
ast-grep --pattern 'fn upgrade_model($$$) {
  $$$
}'

# Look for packed model specific validation
rg -A 5 "packed.*model.*valid|valid.*packed.*model"

Length of output: 1176


Script:

# Let's check how model upgrades are validated in the world contract
rg -A 15 "Invalid new schema.*upgrade" crates/dojo/core/src/world/

# Look for model schema validation logic
ast-grep --pattern 'fn validate_schema($$$) {
  $$$
}'

# Search for packed model specific checks during upgrades
rg -B 5 -A 10 "is_packed.*validate|validate.*is_packed" crates/dojo/core/

Length of output: 1492

crates/dojo/core-cairo-test/src/tests/world/event.cairo (3)

10-46: Ohayo, sensei! Excellent test coverage with event structs!

The event structs are well-designed to test various upgrade scenarios, including:

  • Field removal (FooEventMemberRemoved)
  • Field addition and removal (FooEventMemberAddedButRemoved)
  • Field movement (FooEventMemberAddedButMoved)
  • Valid field addition (FooEventMemberAdded)

This comprehensive set ensures robust testing of the upgrade constraints.


48-98: Ohayo! Comprehensive permission testing for event registration!

The test cases effectively validate:

  • Successful registration by namespace owner
  • Failed registration attempt by namespace writer
  • Proper event emission and ownership assignment

The permission checks align well with the security requirements.


99-214: Ohayo! Excellent coverage of upgrade constraints!

The upgrade tests thoroughly validate the PR's key requirements:

  • Same layout type must be maintained
  • Existing fields cannot be changed/moved
  • New fields can only be appended at the end

Each constraint is tested with both positive and negative cases.

crates/dojo/core-cairo-test/src/tests/world/model.cairo (1)

58-120: Ohayo, sensei! Registration tests look comprehensive!

The test cases effectively validate model registration with proper permission checks and name validation.

crates/dojo/core-cairo-test/src/tests/world/contract.cairo (5)

60-100: Well-structured test coverage for upgrade scenarios

Ohayo sensei! The test cases effectively cover both successful and failed upgrade scenarios, including:

  • Upgrades from world
  • Direct upgrades
  • Invalid provider upgrades

102-157: Well-structured invalid model test contracts

Ohayo sensei! The invalid model contracts are well-organized and provide good test coverage for error scenarios.


159-361: Excellent security coverage in namespace management tests

Ohayo sensei! The test suite demonstrates excellent security considerations:

  • Proper access control validation
  • Protection against malicious contracts
  • Comprehensive event validation
  • Edge case handling for unregistered namespaces

This thorough testing helps ensure the security of the upgrade system.


71-72: ⚠️ Potential issue

Fix type mismatch in assertion

Ohayo sensei! The assertion compares a felt252 with a string literal which could lead to unexpected behavior.

Apply this diff to fix the comparison:

-    assert(quantum_dispatcher.plz_more_tps() == 'daddy', 'quantum leap failed');
+    assert(quantum_dispatcher.plz_more_tps() == 123_felt252, 'quantum leap failed'); // Replace with expected felt252 value

Likely invalid or redundant comment.


40-42: ⚠️ Potential issue

Fix type mismatch in return value

Ohayo sensei! The function returns a string literal where a felt252 is expected. This could lead to runtime issues.

Apply this diff to fix the type:

fn plz_more_tps(self: @ContractState) -> felt252 {
-    'daddy'
+    123_felt252 // Replace with appropriate felt252 value
}

Likely invalid or redundant comment.

crates/dojo/world/src/contracts/abigen/model.rs (3)

Line range hint 627-637: Schema method update looks clean, sensei!

The return type change from Ty to Struct is consistent with the ModelDef changes and maintains the established pattern for contract methods.


Line range hint 732-742: ModelContractReader schema changes are consistent!

The schema method changes mirror those in ModelContract, maintaining symmetry between the two implementations.


Line range hint 176-217: Ohayo sensei! The ModelDef changes look good.

The removal of versioning and the schema type change from Ty to Struct aligns well with the PR objectives. The serialization/deserialization logic has been properly updated to handle these changes.

Let's verify no versioning references remain:

✅ Verification successful

Let me verify the remaining references with more context to ensure they're not problematic.


Let me verify the remaining version references in the model plugin code to ensure they're just test cases.


Let me try one more search with a different path pattern:


Ohayo sensei! Based on the verification results, I can now provide a conclusive response:

The version removal changes are safe and properly implemented.

The remaining version references are only in test files (plugin_test_data/model) which are specifically designed to test error handling for invalid version attributes. These test cases ensure the model plugin correctly rejects invalid version usage, which is exactly what we want.

The only other version reference is in a comment about Torii versioning, which is unrelated to the model versioning being removed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining version references in model-related files
# Expect: No occurrences of version in model definitions

rg -i "version.*model" 

Length of output: 453


Script:

#!/bin/bash
# Get context around version references in model files
rg -B 3 -A 3 -i "version.*model" 

# Check for any version-related structs or fields in model.rs
ast-grep --pattern 'struct $_ {
  $$$
  version: $_,
  $$$
}'

# Check model plugin for version handling
fd "model.rs" --exec cat {}

Length of output: 135533


Script:

# Check model plugin implementation for version handling
rg -B 2 -A 2 "version" crates/dojo/lang/src/plugin/model.rs

# Check if there are any version-related structs or fields in the model plugin
ast-grep --pattern 'struct $_ {
  $$$
  version: $_,
  $$$
}'

Length of output: 200


Script:

# Check for version references in model-related files
fd "model.rs" --exec rg -B 2 -A 2 "version" {}

# Check test data for version references
rg -B 2 -A 2 "version" crates/dojo/lang/src/plugin_test_data/model

Length of output: 3226

crates/dojo/core/src/world/world_contract.cairo (4)

42-45: LGTM! Import changes align with new resource management approach.

The updated imports support the new resource management system, particularly the Layout and dispatcher types needed for upgradability checks.


975-1010: LGTM! Robust resource upgradability checks.

The assert_resource_upgradability function implements essential checks:

  1. Layout type consistency (Struct/Fixed)
  2. Existing field preservation
  3. New field append-only policy

Line range hint 540-615: Verify model upgrade compatibility checks.

Similar to events, model upgrades now include proper validation. The implementation correctly prevents breaking changes in existing fields.

#!/bin/bash
# Description: Check if all model contracts implement IStoredResource interface
# Expected: All model contracts should have layout() and schema() methods

# Search for model contract implementations
ast-grep --pattern 'impl $_ of IStoredResource<$_> {
  fn layout($_, $_) -> Layout {
    $$$
  }
  fn schema($_, $_) -> Schema {
    $$$
  }
}'

Line range hint 436-511: Verify event upgrade compatibility checks.

The event upgrade process now includes proper validation through assert_resource_upgradability. However, we should verify that all event contracts implement the required interfaces.

✅ Verification successful

Let me search for event-related code patterns to verify the implementation requirements. The previous pattern might have been too specific, so I'm broadening the search to find event contracts and their implementations.


Ohayo! Let me try again without the file type restriction, sensei! This should help us find the event contracts and their implementations to verify the compatibility checks.


Event contracts properly implement required interfaces

Ohayo sensei! After analyzing the codebase, I can confirm that event contracts are properly implementing the required interfaces. The verification shows:

  1. Events automatically implement IDeployedResource through the event component macro (see crates/dojo/core/src/event/component.cairo)
  2. Events implement IStoredResource as shown in test implementations (e.g., crates/dojo/core-cairo-test/src/tests/helpers/event.cairo)
  3. The upgrade process in world_contract.cairo correctly validates both interfaces through assert_resource_upgradability

The implementation is consistent and safe across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if all event contracts implement IStoredResource interface
# Expected: All event contracts should have layout() and schema() methods

# Search for event contract implementations
ast-grep --pattern 'impl $_ of IStoredResource<$_> {
  fn layout($_, $_) -> Layout {
    $$$
  }
  fn schema($_, $_) -> Schema {
    $$$
  }
}'

Length of output: 145


Script:

#!/bin/bash
# Let's try a different approach to find event contracts and their implementations

# First, find all event contracts
rg -A 5 "contract\s+\w+Event\s+" --type cairo

# Also search for IStoredResource trait implementations
rg -A 5 "impl.*IStoredResource" --type cairo

# And check for any event-related interfaces
rg -A 5 "trait\s+I\w*Event\w*\s+" --type cairo

Length of output: 233


Script:

#!/bin/bash
# Let's try without specifying file type since cairo isn't recognized

# Find all event contracts
rg -A 5 "contract\s+\w+Event\s+"

# Search for IStoredResource trait implementations
rg -A 5 "impl.*IStoredResource"

# Check for event-related interfaces
rg -A 5 "trait\s+I\w*Event\w*\s+"

# Also search for deployed event references
rg -A 5 "IDeployedResource"

Length of output: 18981

Comment on lines +110 to +115
// Ensures the generated contract has a unique classhash, using
// a hardcoded hash computed on model and member names.
#[external(v0)]
fn ensure_unique(self: @ContractState) {
let _hash = $unique_hash$;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Documentation needed for unique hash computation, sensei!

The unique hash is computed using Poseidon hash with the following inputs:

  1. A flag indicating if the model is packed (0 or 1)
  2. The model name as a bytearray hash
  3. For each member: Poseidon hash of (member_name_hash, member_type_hash)

This hash is critical for model upgradability as it ensures:

  • Different model names produce different hashes
  • Changes to member names or types produce different hashes
  • Packed vs unpacked models produce different hashes

Please add this documentation to help other developers understand the hash computation and its role in model upgrades.

🔗 Analysis chain

Consider documenting the hash computation, sensei!

While the unique hash implementation is a great addition for preventing accidental deployments of incompatible models, it would be helpful to document:

  1. How the hash is computed from model and member names
  2. When and how this uniqueness check is used during upgrades

Let's check if this is documented elsewhere:


Let me search for more specific information about the unique hash implementation.


Let me check the macro implementation to understand how the unique hash is computed.


Let me check the actual implementation of the hash computation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for documentation about the unique hash computation
rg -g '!*.cairo' -g '*.md' -i "model.*hash|unique.*hash|classhash"

Length of output: 953


Script:

#!/bin/bash
# Search for unique hash implementation details in model-related files
rg -g '*.cairo' -B 5 -A 5 "unique.*hash|ensure_unique"

# Also check for any comments or documentation in the model patch file
cat crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo

Length of output: 8091


Script:

#!/bin/bash
# Search for the macro that processes the model and generates the unique hash
rg -g '*.rs' -B 5 -A 5 "unique.*hash|ensure_unique" crates/dojo/lang/src/

# Also check for any documentation in the Rust implementation
fd -e rs . crates/dojo/lang/src/ -x cat {} | rg -B 5 -A 5 "model.*hash|unique.*hash"

Length of output: 11929


Script:

#!/bin/bash
# Check the implementation of compute_unique_hash function
cat crates/dojo/lang/src/attribute_macros/element.rs

Length of output: 6936

Comment on lines 58 to 65
diagnostics.push(PluginDiagnostic {
stable_ptr: arg.stable_ptr().0,
message: format!(
"Unexpected parameter {} for {attribute_name}.",
arg.as_syntax_node().get_text(db)
),
severity: Severity::Warning,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using Error severity for unexpected parameters, sensei!

While the error handling implementation is good, unexpected parameters in event definitions could lead to silent failures or misconceptions about the event's behavior. Consider changing the severity from Warning to Error to ensure these issues are caught early in development.

-                    severity: Severity::Warning,
+                    severity: Severity::Error,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
diagnostics.push(PluginDiagnostic {
stable_ptr: arg.stable_ptr().0,
message: format!(
"Unexpected parameter {} for {attribute_name}.",
arg.as_syntax_node().get_text(db)
),
severity: Severity::Warning,
});
diagnostics.push(PluginDiagnostic {
stable_ptr: arg.stable_ptr().0,
message: format!(
"Unexpected parameter {} for {attribute_name}.",
arg.as_syntax_node().get_text(db)
),
severity: Severity::Error,
});

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (14)
crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (1)

59-65: Clean interface separation, sensei!

The three-tier event implementation (Deployed, Stored, and General) provides a solid foundation for managing event upgradability while maintaining clear separation of concerns.

Consider documenting the responsibility of each interface in the module-level documentation to help other developers understand when to use each one.

crates/dojo/core/src/model/model.cairo (1)

1-3: Ohayo! The import changes align well with the upgradability requirements, sensei!

The switch from Ty to Struct provides better type safety and validation capabilities for ensuring layout compatibility during model upgrades.

The use of Struct type will help enforce the PR's upgrade conditions by providing stronger type checking for layout modifications.

crates/torii/types-test/src/contracts.cairo (1)

Line range hint 119-132: Ohayo! A few suggestions to enhance the delete implementation, sensei!

The delete implementation has several areas that could be improved:

  1. Consider adding existence checks before deletion
  2. The assumption that subrecord_id = record_id + 1 seems brittle
  3. Missing error handling for failed operations
  4. Consider emitting a deletion event for consistency with create

Here's a suggested improvement:

 fn delete(ref self: ContractState, record_id: u32) {
     let mut world = self.world(@"types_test");
+    // Validate record exists
+    assert(world.model_exists<Record>(record_id), 'Record does not exist');
 
     let record: Record = world.read_model(record_id);
     let record_sibling: RecordSibling = world.read_model(record_id);
 
-    let subrecord_id = record_id + 1;
+    // Read subrecord_id from record if available
     let subrecord: Subrecord = world.read_model((record_id, subrecord_id));
 
     world.erase_model(@record);
     world.erase_model(@record_sibling);
     world.erase_model(@subrecord);
+
+    // Emit deletion event for tracking
+    world.emit_event(
+        @RecordDeleted { record_id }
+    );
 }

You'll also need to add the event definition:

#[derive(Drop, Serde, starknet::Event)]
#[dojo::event]
struct RecordDeleted {
    #[key]
    record_id: u32,
}
crates/dojo/lang/src/attribute_macros/element.rs (2)

86-107: Ohayo sensei! Please add documentation for the new hash function.

The implementation looks solid and aligns well with the upgradability checking requirements. However, it would be beneficial to add documentation explaining:

  • The purpose of this hash computation
  • How it contributes to upgradability checking
  • The significance of the packed flag
  • The format of the resulting hash

Add documentation like this:

+/// Computes a unique hash for a struct based on its name, packing status, and member types.
+/// This hash is used to verify upgradability by ensuring that new versions maintain
+/// compatibility with existing field layouts.
+///
+/// # Arguments
+///
+/// * `db` - The syntax database
+/// * `element_name` - Name of the struct
+/// * `is_packed` - Whether the struct uses packed layout
+/// * `members` - List of struct members
+///
+/// # Returns
+///
+/// A Felt containing the unique hash for this struct layout
 pub fn compute_unique_hash(

Line range hint 1-107: Ohayo sensei! The architectural changes align perfectly with the PR objectives!

The removal of versioning code and introduction of the compute_unique_hash function creates a more robust system for checking model and event upgradability. The hash-based approach ensures that:

  1. Layout type consistency is maintained
  2. Existing fields remain unchanged
  3. New fields can only be appended

This is a cleaner solution compared to the previous version-based approach.

crates/dojo/lang/src/attribute_macros/model.rs (1)

155-156: Nice addition of packed model detection, sensei!

The is_packed flag is crucial for model upgradability as packed and unpacked models have different layouts. This distinction helps prevent incompatible upgrades between different layout types.

Consider documenting this constraint in the model's metadata or schema to make it explicit for developers attempting upgrades.

crates/dojo/core-cairo-test/src/tests/world/event.cairo (2)

62-62: Fix typo in assertion message.

Ohayo! There's a typo in the assertion message: 'no event)' appears with an extra parenthesis.

-    assert(event.is_some(), 'no event)');
+    assert(event.is_some(), 'no event');

Also applies to: 114-114


99-163: Consider extracting common event verification logic.

Ohayo, sensei! The event verification logic is duplicated between test_upgrade_event and test_upgrade_event_from_event_owner. Consider extracting it into a helper function.

fn verify_event_upgrade(
    world: IWorldDispatcher, 
    event: Option<world::Event>
) {
    assert(event.is_some(), 'no event');
    
    if let world::Event::EventUpgraded(event) = event.unwrap() {
        assert(
            event.selector == Event::<FooEventMemberAdded>::selector(DOJO_NSH),
            'bad model selector'
        );
        assert(
            event.class_hash == e_FooEventMemberAdded::TEST_CLASS_HASH.try_into().unwrap(),
            'bad model class_hash'
        );
        assert(
            event.address != core::num::traits::Zero::<ContractAddress>::zero(),
            'bad model address'
        );
    } else {
        core::panic_with_felt252('no EventUpgraded event');
    }
}
crates/dojo/core-cairo-test/src/tests/world/model.cairo (2)

11-56: Ohayo, sensei! Model structs are well-structured for testing upgrade scenarios

The test models effectively cover various upgrade scenarios including layout changes, field modifications, and field additions. Consider adding doc comments to explain the purpose of each test model.

Add documentation comments like this:

+/// Tests model upgrade with incompatible layout type
 #[derive(Introspect, Copy, Drop, Serde)]
 #[dojo::model]
 pub struct FooModelBadLayoutType {

121-185: Ohayo, sensei! Model upgrade tests look solid

The tests thoroughly validate the upgrade process and event emission. Consider adding a test for concurrent upgrades to ensure thread safety.

Add a test like:

#[test]
fn test_concurrent_model_upgrades() {
    let world = deploy_world_for_model_upgrades();
    // Simulate concurrent upgrades and verify last upgrade wins
    // ...
}
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (3)

8-20: Consider consolidating duplicate contract patterns

Ohayo sensei! I notice similar patterns across multiple contract modules where each implements a metadata-related trait with minimal variation. Consider consolidating these into a more maintainable structure.

Consider using a macro to generate these contract implementations to reduce code duplication. For example:

#[macro_export]
macro_rules! implement_metadata_contract {
    ($mod_name:ident, $dojo_name:expr) => {
        #[starknet::contract]
        mod $mod_name {
            #[storage]
            struct Storage {}

            #[abi(embed_v0)]
            impl MetadataImpl of super::IMetadataOnly<ContractState> {
                fn dojo_name(self: @ContractState) -> ByteArray {
                    $dojo_name
                }
            }
        }
    };
}

This would allow you to define contracts more concisely:

implement_metadata_contract!(invalid_model, "invalid_model");
implement_metadata_contract!(invalid_model_world, "invalid_model_world");

Also applies to: 27-58, 108-118, 121-131, 134-144, 147-157


164-164: Consider using named constants for test addresses

Ohayo sensei! The test addresses are currently hardcoded using starknet::contract_address_const. Consider defining these as named constants at the module level for better maintainability and readability.

const BOB_ADDRESS: felt252 = 0xb0b;
const ALICE_ADDRESS: felt252 = 0xa11ce;
const MALICIOUS_CONTRACT_ADDRESS: felt252 = 0xdead;

// Then use them in tests
let bob = starknet::contract_address_const::<BOB_ADDRESS>();

Also applies to: 200-200, 217-217, 242-242, 258-258, 301-301, 334-334, 349-349


171-171: Consider creating a test helper for event cleanup

Ohayo sensei! The drop_all_events call is repeated in multiple test functions. Consider wrapping this in a test helper that combines setup and event cleanup.

fn setup_test_with_clean_events() -> IWorldDispatcher {
    let world = deploy_world();
    drop_all_events(world.contract_address);
    world
}

Also applies to: 268-268

crates/dojo/world/src/contracts/abigen/model.rs (1)

Ohayo sensei! Schema type inconsistencies detected across the codebase

The change from Ty to Struct in ModelDef requires corresponding updates in several other files that still use the Ty type for schema:

  • crates/torii/core/src/sql/mod.rs
  • crates/torii/core/src/sql/cache.rs
  • crates/torii/grpc/src/types/mod.rs
  • crates/dojo/types/src/schema.rs

These files need to be updated to maintain consistency with the new schema type changes in ModelDef.

🔗 Analysis chain

Line range hint 176-217: LGTM! Changes align with versioning removal.

Ohayo sensei! The removal of the version field and the schema type change from Ty to Struct align perfectly with the PR objectives. Let's verify that all model definitions in the codebase are compatible with this change.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify model definitions in the codebase are compatible with the new schema type.

# Test: Search for model definitions that might still use the old Ty type
rg -A 5 'schema:\s*Ty'

Length of output: 1554


Script:

#!/bin/bash
# Let's check if these files have been updated in the PR
git diff origin/main -- crates/torii/core/src/sql/mod.rs crates/torii/core/src/sql/cache.rs crates/torii/grpc/src/types/mod.rs crates/dojo/types/src/schema.rs

# Also check for any pending changes in the current branch
git diff -- crates/torii/core/src/sql/mod.rs crates/torii/core/src/sql/cache.rs crates/torii/grpc/src/types/mod.rs crates/dojo/types/src/schema.rs

Length of output: 309

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 21369dc and c0eafe1.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (42)
  • Cargo.toml (1 hunks)
  • bin/sozo/src/commands/inspect.rs (0 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/Cargo.toml (1 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (2 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
💤 Files with no reviewable changes (4)
  • bin/sozo/src/commands/inspect.rs
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (24)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/lib.cairo
  • crates/dojo/core-cairo-test/src/tests/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/component.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/Cargo.toml
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
  • crates/dojo/world/src/contracts/model.rs
  • examples/spawn-and-move/dojo_dev.toml
🔇 Additional comments (34)
crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (2)

77-82: Clever unique hash enforcement mechanism, sensei!

The hardcoded hash based on event and member names effectively prevents accidental or malicious event collisions during upgrades.

Let's verify the uniqueness of these hashes across all events:

#!/bin/bash
# Extract and compare unique hashes across all event implementations
rg -A 1 "fn ensure_unique.*\{" | rg "let _hash = .*;" | sort | uniq -d

22-28: Ohayo! Schema type enforcement looks solid, sensei!

The stricter return type and runtime check ensure events maintain their structure, which is crucial for the upgradability requirements.

Let's verify no events are using non-struct types:

crates/dojo/core/src/lib.cairo (3)

12-13: Ohayo! Clean module addition, sensei!

The new component module under event follows the established module structure pattern nicely.


25-30: Verify the integration of new resource interfaces, sensei!

The new resource interfaces (IDeployedResource and IStoredResource) are crucial for the upgradability checks. Let's ensure they're properly integrated.


32-32: Ohayo! Please verify upgrade rule enforcement in comparison traits.

The StructCompareTrait and LayoutCompareTrait exports are crucial for implementing the upgrade conditions. Let's verify they properly enforce:

  1. Same layout type (Struct/Fixed) requirement
  2. No changes to existing fields
  3. New fields only allowed at the end

Also applies to: 35-35

✅ Verification successful

Let me search for the trait definitions since the implementations weren't found.


Let me search for the Layout type and any comparison traits for it.


Let me check the layout module for the implementation details.


Ohayo! The upgrade rules are properly enforced, sensei!

The verification shows that both traits correctly enforce the upgrade rules:

  1. StructCompareTrait enforces:

    • Same name and attributes check (self.name != old.name || self.attrs != old.attrs)
    • No removal of existing fields ((*self.children).len() < (*old.children).len())
    • No changes to existing fields (*old.children[i] != *self.children[i])
    • New fields only at the end (loop checks up to old length only)
  2. LayoutCompareTrait enforces:

    • Same layout type requirement through is_same_type_of method
    • Matches Fixed/Struct/Tuple/Array/ByteArray/Enum types

The implementation is used in assert_resource_upgradability which validates both layout and schema upgrades before allowing any resource upgrade.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of upgrade rules in comparison traits
# Expected: Find trait implementations with upgrade rule checks

echo "Checking StructCompareTrait implementation..."
ast-grep --pattern 'impl StructCompareTrait for $_ {
  $$$
}'

echo "Checking LayoutCompareTrait implementation..."
ast-grep --pattern 'impl LayoutCompareTrait for $_ {
  $$$
}'

Length of output: 329


Script:

#!/bin/bash
# Search for trait definitions
echo "Searching for StructCompareTrait definition..."
rg "trait StructCompareTrait" -A 10

echo "Searching for LayoutCompareTrait definition..."
rg "trait LayoutCompareTrait" -A 10

# Search in introspect module
echo "Checking introspect module contents..."
fd "introspect.cairo" --exec cat {}

Length of output: 13799


Script:

#!/bin/bash
# Search for Layout type definition and comparison traits
echo "Searching for Layout type..."
fd "Layout" --exec rg -l "enum Layout" {}

echo "Checking Layout file contents..."
fd "Layout" --exec cat {}

echo "Searching for LayoutCompareTrait..."
rg -g "!target" "LayoutCompareTrait"

Length of output: 654


Script:

#!/bin/bash
echo "Checking layout.cairo contents..."
cat crates/dojo/core/src/meta/layout.cairo

echo "Checking world_contract.cairo for usage..."
cat crates/dojo/core/src/world/world_contract.cairo

Length of output: 49230

crates/dojo/core/src/model/model.cairo (2)

91-93: Clean implementation, sensei!

The schema implementation correctly delegates to ModelDefinition, maintaining simplicity.


Line range hint 108-116: ModelDef construction updated correctly to remove versioning!

The removal of the version field aligns with the PR objectives to eliminate versioning management.

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3)

84-89: Clean trait separation for deployed and stored models, sensei!

The split between deployed and stored model implementations provides better separation of concerns and clearer interfaces.


110-115: Referencing existing documentation request.

The previous review comment about documenting the unique hash computation is still valid and applicable here.


33-39: LGTM! Enhanced type safety for model schema, sensei!

The schema function now properly enforces that models must be structs, which is essential for the upgradability checks.

Let's verify no models are using non-struct types:

crates/torii/types-test/src/contracts.cairo (1)

112-113: Ohayo! Clean method chaining implementation, sensei!

The method chaining pattern for emit_event improves code readability while maintaining the same functionality.

crates/dojo/lang/src/attribute_macros/event.rs (3)

20-20: Ohayo! The import looks good, sensei!

The addition of compute_unique_hash aligns well with the PR's objective of implementing upgradability checks for events.


127-127: Verify the EVENT_PATCH template usage, sensei!

The unique hash is now included in the event patch, but we should verify:

  1. How this hash is used in the EVENT_PATCH template
  2. Whether it properly enforces the upgradability constraints mentioned in the PR objectives
#!/bin/bash
# Description: Check the EVENT_PATCH template content and usage
echo "Checking EVENT_PATCH content:"
cat crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo

echo "\nChecking usage of unique_hash in patch files:"
rg "unique_hash" --type cairo

114-116: Ohayo! Let's enhance the documentation and verification, sensei!

The hash computation is crucial for upgradability checks, but a few improvements would help:

  1. Document the purpose of the false flag parameter
  2. Add a comment explaining how this hash ensures upgradability constraints
  3. Consider adding validation to ensure the hash meets expected format/requirements
✅ Verification successful

Ohayo! The hash computation is well-implemented, sensei!

After reviewing the implementation, the false parameter in compute_unique_hash is actually well-defined and serves a clear purpose. Looking at the source code:

  1. The false parameter indicates this is an event (not a packed struct), which is correct
  2. The hash computation is properly implemented to ensure upgradability constraints by:
    • Using the event name and member information
    • Including member types and names in the hash calculation
    • Using Poseidon hash for cryptographic uniqueness

The implementation is secure and follows best practices. No changes needed! 🎋

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the compute_unique_hash function is documented in the codebase
rg -A 5 "compute_unique_hash" --type rust

Length of output: 2832


Script:

#!/bin/bash
# Let's search for the compute_unique_hash function definition and its usages
ast-grep --pattern 'fn compute_unique_hash($$$) { $$$ }'

# Also search for any comments or documentation about this function
rg -B 3 "compute_unique_hash" --type rust

Length of output: 1865


Script:

#!/bin/bash
# Let's check if there are any tests or examples using this function
fd -e rs -x rg -l "compute_unique_hash" {}

Length of output: 193


Script:

#!/bin/bash
# Let's check the module where this function might be defined
rg "mod.*\{" crates/dojo/lang/src/attribute_macros/event.rs

Length of output: 61


Script:

#!/bin/bash
# Let's look at the entire event.rs file to understand the context
cat crates/dojo/lang/src/attribute_macros/event.rs

Length of output: 6117


Script:

#!/bin/bash
# Let's check the element.rs file where compute_unique_hash is defined
cat crates/dojo/lang/src/attribute_macros/element.rs

Length of output: 6936


Script:

#!/bin/bash
# Let's also check if there are any tests for this functionality
fd test -e rs -x rg -l "compute_unique_hash" {}

Length of output: 49


Script:

#!/bin/bash
# Let's check if there are any comments about hash computation in the model implementation
rg -B 5 "compute_unique_hash.*is_packed" --type rust

Length of output: 609

crates/dojo/lang/src/attribute_macros/element.rs (1)

7-7: Ohayo sensei! The import changes look good!

The new imports are well-organized and properly support the hash computation functionality introduced in this PR.

Also applies to: 12-13

crates/dojo/core/src/meta/introspect.cairo (2)

38-39: Ohayo! The trait generation looks good, sensei!

The #[generate_trait] attribute and trait implementation declaration follow Cairo best practices.


40-61: 🛠️ Refactor suggestion

The upgrade validation implementation needs additional safeguards, sensei!

While the implementation correctly ensures that existing fields remain unchanged and new fields can only be appended, there are a few concerns:

  1. The implementation doesn't explicitly validate the layout type (Struct/Fixed) as mentioned in the PR objectives
  2. The member comparison at line 54 uses exact matching, but we should document this strict behavior

Consider applying these improvements:

 fn is_an_upgrade_of(self: @Struct, old: @Struct) -> bool {
     if self.name != old.name
         || self.attrs != old.attrs
         || (*self.children).len() < (*old.children).len() {
         return false;
     }

+    // Validate that all existing fields remain unchanged
+    // New fields can only be appended at the end
     let mut i = 0;

     loop {
         if i >= (*old.children).len() {
             break true;
         }

         if *old.children[i] != *self.children[i] {
             break false;
         }

         i += 1;
     }
 }

Let's verify the usage of this implementation:

crates/dojo/lang/src/attribute_macros/model.rs (3)

18-18: Ohayo! Import changes look good, sensei!

The addition of compute_unique_hash import aligns well with the PR's objective of implementing model upgradability checks.


180-180: Hash interpolation is perfectly placed, sensei!

The addition of unique_hash to the interpolation map ensures the hash is available in generated code for upgradability checks.


160-163: Unique hash computation looks solid but needs formatting adjustment, sensei!

The hash computation correctly incorporates model type, packed status, and members for upgradability checks. However, the indentation could be more consistent with the surrounding code.

Consider adjusting the indentation to match the surrounding code style:

-        let unique_hash =
-            compute_unique_hash(db, &model_type, is_packed, &struct_ast.members(db).elements(db))
-                .to_string();
+        let unique_hash = compute_unique_hash(
+            db,
+            &model_type,
+            is_packed,
+            &struct_ast.members(db).elements(db)
+        ).to_string();

Let's verify the hash computation implementation:

crates/dojo/core-cairo-test/src/tests/world/event.cairo (3)

10-46: LGTM! Well-structured event definitions for upgrade testing scenarios.

Ohayo, sensei! The event structs are thoughtfully designed to test different upgrade scenarios:

  • FooEventMemberRemoved: Tests field removal
  • FooEventMemberAddedButRemoved: Tests field addition and removal
  • FooEventMemberAddedButMoved: Tests field movement
  • FooEventMemberAdded: Base event structure

48-97: LGTM! Comprehensive event registration tests.

The test cases effectively verify:

  • Event registration by namespace owner
  • Permission checks for writers
  • Event emission and property validation

216-277: LGTM! Thorough permission and edge case testing.

Ohayo! The test suite effectively covers:

  • Permission checks for writers and random accounts
  • Unregistered namespace handling
  • Malicious contract interactions
crates/dojo/core-cairo-test/src/tests/world/model.cairo (2)

58-120: Ohayo, sensei! Comprehensive model registration test coverage

The registration tests effectively validate:

  • Ownership requirements
  • Name validation rules
  • Permission checks
  • Event emission

Note: There's an existing comment about the typo in assertion messages.


187-297: Ohayo, sensei! Excellent error case coverage for model upgrades

The tests comprehensively validate all upgrade constraints mentioned in PR objectives:

  • Layout type consistency
  • Field preservation
  • Field ordering
  • Permission requirements
  • Security against malicious contracts
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1)

159-361: LGTM! Comprehensive test coverage

Ohayo sensei! The test suite provides excellent coverage of various scenarios including:

  • Contract deployment permissions
  • Upgrade permissions
  • Namespace ownership
  • Security checks for malicious contracts
  • Event verification

The tests are well-structured and cover both happy and error paths.

crates/dojo/world/src/contracts/abigen/model.rs (2)

Line range hint 627-636: LGTM! Schema method return type updated consistently.

The schema method's return type change from Ty to Struct maintains consistency with the ModelDef changes.


Line range hint 732-741: LGTM! Schema method return type updated consistently.

The schema method's return type change from Ty to Struct maintains consistency with both ModelDef and ModelContract changes.

crates/dojo/core/src/world/world_contract.cairo (6)

42-45: LGTM! Import changes align with new functionality.

The new imports from dojo::meta provide the necessary types and traits for implementing resource upgradability checks.


Line range hint 429-433: Consistent dispatcher type updates across resource handlers.

The change from specific dispatchers (IEventDispatcher, IModelDispatcher, IContractDispatcher) to the unified IDeployedResourceDispatcher improves code consistency and maintainability.

Also applies to: 475-479, 533-537, 579-583, 658-662, 713-717


501-504: LGTM! Strategic placement of upgradability check.

The assert_resource_upgradability check is correctly placed before updating the resource in storage, ensuring that invalid upgrades are rejected early.


1053-1088: Ohayo, sensei! Robust implementation of resource upgradability checks.

The implementation aligns perfectly with the PR objectives by enforcing:

  1. Layout type consistency (Struct or Fixed)
  2. Preservation of existing fields
  3. Append-only new fields

The error messages are descriptive and will help developers understand upgrade constraints.


1106-1108: Consistent error message formatting for resource types.

The error message formatting is consistent across different resource types (contract, event, model), improving the debugging experience.

Also applies to: 1112-1114, 1118-1120


1137-1139: Consider handling non-Dojo callers in permission checks.

This comment was previously made and is still valid. The code assumes the caller is a Dojo contract when formatting error messages, which could cause issues with non-Dojo callers.

/// Returns the schema of the model.
fn schema() -> Ty;
fn schema() -> Struct;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Ohayo! We need to update test data implementations, sensei!

The schema return type change from Ty to Struct needs attention in test files. Found:

  • Core implementations in definition.cairo and event.cairo are correctly using Struct
  • Test data files still use the old Ty return type:
    • plugin_test_data/model: 11 implementations
    • plugin_test_data/event: 3 implementations

The patch files show the correct implementation pattern using Struct, but test data hasn't been updated yet.

🔗 Analysis chain

Let's verify the impact of schema return type change, sensei!

The change from Ty to Struct return type is correct, but we should verify all implementations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining implementations using the old Ty return type
ast-grep --pattern 'fn schema() -> Ty'

# Search for all schema implementations to ensure they're updated
rg -l "fn schema\(\)"

Length of output: 402


Script:

#!/bin/bash
# Let's check the actual implementation of schema() in these files
rg "fn schema\(\)" -A 5 crates/dojo/core/src/model/definition.cairo crates/dojo/core/src/event/event.cairo

# Also check the test data and patches to see their implementations
rg "fn schema\(\)" -A 5 crates/dojo/lang/src/plugin_test_data/event crates/dojo/lang/src/plugin_test_data/model crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo

Length of output: 8917

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (11)
crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (2)

59-65: Clean interface separation, sensei!

The split into Deployed, Stored, and base Event implementations provides a clear separation of concerns and better modularity. This structure will make upgrades more manageable.

Consider documenting the responsibility of each interface in the module-level documentation to help other developers understand when to use each one.


77-82: The unique hash implementation needs more context, sensei!

While the unique hash implementation is a good addition for preventing collisions, it would benefit from documentation explaining:

  • How the hash is computed
  • Why it's necessary for upgradability
  • What developers should consider when modifying events

Add documentation above the ensure_unique function:

        // Ensures the generated contract has a unique classhash, using
        // a hardcoded hash computed on event and member names.
+       /// Ensures uniqueness of this event contract by incorporating a hash
+       /// computed from the event name and its member names.
+       /// This prevents accidental collisions during upgrades and ensures
+       /// each event version has a distinct identity.
        #[external(v0)]
        fn ensure_unique(self: @ContractState) {
crates/torii/types-test/src/contracts.cairo (1)

Line range hint 117-131: Ohayo sensei! A few concerns about the delete implementation.

The delete implementation has several potential issues:

  1. The subrecord_id calculation (record_id + 1) assumes sequential IDs, which might not always be true.
  2. There's no error handling for non-existent records.
  3. Consider emitting a deletion event for tracking purposes.

Here's a suggested improvement:

 fn delete(ref self: ContractState, record_id: u32) {
     let mut world = self.world(@"types_test");
-    let record: Record = world.read_model(record_id);
-    let record_sibling: RecordSibling = world.read_model(record_id);
-    let subrecord_id = record_id + 1;
-    let subrecord: Subrecord = world.read_model((record_id, subrecord_id));
+    // Check if record exists
+    match world.try_read_model::<Record>(record_id) {
+        Option::Some(record) => {
+            let record_sibling: RecordSibling = world.read_model(record_id);
+            
+            // Find associated subrecord
+            let subrecords = world.get_models::<Subrecord>()
+                .filter(|s| s.record_id == record_id);
+            
+            // Perform deletion
+            world.erase_model(@record);
+            world.erase_model(@record_sibling);
+            for subrecord in subrecords {
+                world.erase_model(@subrecord);
+            }
+            
+            // Emit deletion event
+            world.emit_event(
+                @RecordDeleted { record_id }
+            );
+        },
+        Option::None => {
+            panic_with_felt252('Record not found')
+        }
+    }
-    world.erase_model(@record);
-    world.erase_model(@record_sibling);
-    world.erase_model(@subrecord);
 }

Don't forget to add the deletion event structure:

#[derive(Drop, Serde, starknet::Event)]
#[dojo::event]
struct RecordDeleted {
    #[key]
    record_id: u32,
}
crates/dojo/lang/src/attribute_macros/model.rs (2)

18-19: Ohayo sensei! Nice modularization of hash computation logic.

The extraction of compute_unique_hash into a shared module is a good architectural decision, as it enables consistent hash generation across both models and events.


180-180: Excellent integration of unique hash in model generation.

The unique hash is correctly integrated into the RewriteNode interpolation, which will be used to enforce upgradability constraints.

Consider documenting the hash format and its role in upgradability checks in the code comments to help future maintainers understand the importance of this value.

crates/dojo/core-cairo-test/src/tests/world/event.cairo (3)

48-82: Consider enhancing test assertions, sensei!

The test verifies basic registration functionality, but consider adding assertions for:

  • Event schema validation
  • Resource name format validation

103-167: Consider improving error messages for better debugging

Ohayo! The error messages in assertions could be more descriptive. For example:

-    assert(event.is_some(), 'no event)');
+    assert(event.is_some(), 'Event emission missing after upgrade');

169-287: Consider grouping related test cases, sensei!

The error case tests could be organized into logical groups using nested modules:

  • Layout validation tests
  • Permission tests
  • Schema validation tests

This would improve test organization and readability.

Example structure:

mod layout_tests {
    #[test]
    fn test_upgrade_event_with_bad_layout_type() {
        // ... existing code
    }
}

mod permission_tests {
    #[test]
    fn test_upgrade_event_from_event_writer() {
        // ... existing code
    }
}
crates/dojo/core-cairo-test/src/tests/world/entities.cairo (1)

248-248: Consistent dispatcher usage looks good, but could be improved, sensei!

The consistent usage of world.dispatcher improves code clarity by making it explicit that we're working with the dispatcher interface. However, there's a repetitive pattern that could be simplified.

Consider modifying the deploy_world() helper to return the dispatcher directly, eliminating the need for the repetitive assignment:

// In the test helpers module
-fn deploy_world() -> World {
+fn deploy_world() -> IWorldDispatcher {
-    // existing implementation
+    let world = // existing implementation
+    world.dispatcher
}

// In test functions
-let world = deploy_world();
-let world = world.dispatcher;
+let world = deploy_world();

This would:

  1. Reduce code repetition
  2. Make the interface usage more explicit
  3. Prevent potential mistakes where someone forgets to get the dispatcher

Also applies to: 267-268, 283-284, 299-300, 317-318, 335-336, 361-362, 379-380, 397-398, 415-416, 444-445, 470-471, 491-492, 512-513, 534-535, 559-560, 585-586, 608-609, 632-633, 655-656, 678-679, 702-702, 719-719, 736-736, 748-748, 761-761, 772-772, 784-784, 797-797, 813-813, 829-829

crates/dojo/core/src/world/world_contract.cairo (2)

42-45: Ohayo, sensei! Excellent architectural improvement with unified resource dispatchers.

The transition to IDeployedResourceDispatcher improves code maintainability by providing a unified interface for all resources.


1053-1088: Consider enhancing error messages with specific validation details.

The upgradability checks are well-implemented, but the error messages could be more informative by including:

  • Which specific layout type changed (from/to)
  • Which schema fields are incompatible
-                panic_with_byte_array(@errors::invalid_resource_layout_upgrade(namespace, name));
+                panic_with_byte_array(@errors::invalid_resource_layout_upgrade_details(
+                    namespace, 
+                    name, 
+                    @format!("Layout type changed from {} to {}", old_layout, new_layout)
+                ));
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c0eafe1 and f6cff5f.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (43)
  • Cargo.toml (1 hunks)
  • bin/sozo/src/commands/inspect.rs (0 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/entities.cairo (32 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/Cargo.toml (1 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (2 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
💤 Files with no reviewable changes (4)
  • bin/sozo/src/commands/inspect.rs
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (30)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/lib.cairo
  • crates/dojo/core-cairo-test/src/tests/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/lib.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/component.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/Cargo.toml
  • crates/dojo/lang/src/attribute_macros/element.rs
  • crates/dojo/lang/src/attribute_macros/event.rs
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
  • crates/dojo/world/src/contracts/abigen/model.rs
  • crates/dojo/world/src/contracts/model.rs
  • examples/spawn-and-move/dojo_dev.toml
🔇 Additional comments (18)
crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (1)

22-28: Ohayo! The schema type enforcement looks solid, sensei!

The strict type checking ensures events can only use struct types, which aligns well with the upgradability requirements. The panic message provides clear feedback for invalid schemas.

Let's verify no events are using non-struct types:

crates/dojo/core/src/model/model.cairo (4)

1-3: Ohayo sensei! Import changes look good!

The switch from introspect::Ty to introspect::Struct aligns perfectly with the schema representation changes for upgradability checks.


39-39: Schema return type change is well-structured!

The transition from Ty to Struct enhances the model's schema representation capabilities for upgradability checks.


91-93: Clean implementation, sensei!

The schema implementation properly delegates to ModelDefinition, maintaining good separation of concerns.


Line range hint 108-116: Verify impact of version removal on existing models.

The removal of versioning from ModelDef aligns with the PR objectives. However, we should verify the impact on existing models in the system.

✅ Verification successful

Version removal from ModelDef is safe and consistent

Ohayo sensei! After careful verification of the codebase, the removal of the version field from ModelDef is safe and properly implemented. The ModelDef structure is consistently used across the codebase without any version-dependent code, and all implementations (Model, ModelValue, Component) have been updated to work with the new version-less ModelDef structure. No legacy version references remain in the model implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining version-related code or references
echo "Checking for remaining version references in models..."
rg -i "version|versioning" "crates/dojo/core/src/model"

echo "Checking for potential version-dependent code..."
ast-grep --pattern 'fn version'

Length of output: 315


Script:

#!/bin/bash
# Let's check for model implementations and their structure
echo "Checking model implementations..."
ast-grep --pattern 'impl $_ of Model'

# Check for any direct references to ModelDef
echo "Checking ModelDef usage..."
rg "ModelDef" -A 3 "crates/dojo/core/src/model"

# Look for test files that might be affected
echo "Checking test files..."
fd "test" "crates/dojo/core/src/model" --exec rg -l "ModelDef"

Length of output: 6049

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3)

84-89: Clean separation of model implementations, sensei!

The split into deployed and stored model implementations provides better separation of concerns and clearer resource management.


110-115: Consider enhancing unique hash implementation, sensei!

While the unique hash implementation is solid, let's make it even better:

  1. The previous documentation request about hash computation is still valid
  2. Consider adding a constant with a descriptive name for the hardcoded hash value
  3. Add an inline comment explaining what makes a hash unique (e.g., "Combines model name and member details")
+    /// Unique hash computed from model name and member details
+    const MODEL_UNIQUE_HASH: felt252 = $unique_hash$;
+
     #[external(v0)]
     fn ensure_unique(self: @ContractState) {
-        let _hash = $unique_hash$;
+        let _hash = MODEL_UNIQUE_HASH;
     }

33-39: Ohayo! Schema type enforcement looks good, sensei!

The stricter type checking with clear panic message aligns well with the upgradability requirements. Let's verify the schema type handling across the codebase.

✅ Verification successful

Let me verify the schema type implementation details further.


Ohayo! Schema implementation is consistent across the codebase, sensei!

The schema type enforcement in the model patch aligns perfectly with the core implementations. The pattern is consistently used across models and events, with proper type checking and helpful panic messages. The change from Ty to Struct is properly reflected in all relevant interfaces and implementations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistent schema type handling
rg -g '*.cairo' "schema\(\).*->.*Struct" 

Length of output: 548


Script:

#!/bin/bash
# Check the actual implementation of schema() in model.cairo
rg -g '*.cairo' -B 2 -A 5 "fn schema\(\) -> (dojo::meta::introspect::)?Struct"

Length of output: 4073

crates/torii/types-test/src/contracts.cairo (2)

Line range hint 1-5: Ohayo! Clean trait definition, sensei!

The addition of the delete method to the IRecords trait is well-structured and maintains good symmetry with the existing create method.


112-113: Method chaining looks clean, sensei!

The refactored event emission using method chaining improves code readability while maintaining the same functionality.

crates/dojo/core/src/meta/introspect.cairo (2)

38-39: Ohayo sensei! The trait implementation looks good!

The generate_trait attribute and implementation naming follow best practices.


40-61: Ohayo sensei! The upgrade validation logic is solid but could be enhanced.

The implementation correctly enforces the upgrade rules by:

  • Preventing changes to existing fields
  • Allowing new fields only at the end
  • Maintaining structural integrity

However, consider these improvements:

  1. Consider a more functional approach using array::all:
-        let mut i = 0;
-        loop {
-            if i >= (*old.children).len() {
-                break true;
-            }
-            if *old.children[i] != *self.children[i] {
-                break false;
-            }
-            i += 1;
-        }
+        array::all(
+            *old.children,
+            |i, child| *child == *self.children[i]
+        )
  1. Consider adding detailed error reporting to help developers understand why an upgrade was rejected. This could be implemented by returning a Result instead of a bool.

Let's verify the upgrade rules are consistently applied across the codebase:

✅ Verification successful

Let me gather more information about the upgrade validation implementation to verify the review comment.


Let me try another search pattern to find upgrade-related implementations.


Let me try one more search without file type restriction.


Ohayo sensei! The upgrade validation implementation is indeed solid and well-tested!

The implementation correctly enforces the upgrade rules by:

  1. Maintaining structural integrity through name and attribute equality checks
  2. Ensuring backward compatibility by requiring new struct to have at least as many children
  3. Enforcing exact matches for existing fields in order

The suggested functional approach using array::all would not provide any significant benefits since:

  • The current loop implementation is clear and straightforward
  • Early return on mismatch provides better performance
  • The implementation is used in critical upgrade validation paths (world contract)

The error reporting suggestion is not necessary as the caller (world contract) already provides appropriate error messages when validation fails:

if !new_schema.is_an_upgrade_of(@old_schema) {
    panic_with_byte_array(@errors::invalid_resource_schema_upgrade(namespace, name));
}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other upgrade validation implementations
rg -A 5 "upgrade.*of|is.*upgrade" 

Length of output: 168844


Script:

#!/bin/bash
# Search for other upgrade validation patterns
ast-grep --pattern $'fn is_an_upgrade_of($_, $_) {
  $$$
}'

Length of output: 60


Script:

#!/bin/bash
# Search for upgrade validation implementations with more context
rg -A 10 "is_an_upgrade" --type cairo

Length of output: 67


Script:

#!/bin/bash
# Search for upgrade validation implementations with more context
rg -A 10 "is_an_upgrade"

# Also search for where this validation is used
rg -A 5 "if.*is_an_upgrade"

Length of output: 2331

crates/dojo/lang/src/attribute_macros/model.rs (2)

155-156: LGTM! Clear packed model detection.

The is_packed flag correctly determines the model's layout type based on derive attributes, which is crucial for upgradability checks.


160-163: Verify hash computation parameters.

The unique hash computation now includes the model type, packing status, and member elements, which aligns with the PR's upgradability requirements. However, let's verify that the hash remains consistent across compilations.

✅ Verification successful

Let me analyze the hash computation implementation to verify its consistency. I'll check the compute_unique_hash function implementation.


Let me try a different approach to examine the hash computation implementation.


Hash computation verified and consistent with upgradability requirements

Ohayo sensei! After reviewing the implementation, I can confirm that the hash computation is robust and deterministic:

  • The compute_unique_hash function uses a consistent formula combining:
    • A packed flag (0 or 1)
    • The element name hash (using compute_bytearray_hash)
    • Member hashes (combining member name and type hashes)
  • All components use deterministic Poseidon hashing
  • The implementation is used consistently in both model.rs and event.rs

The hash will remain stable across compilations as it only depends on the model's structural properties, not on implementation details.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if compute_unique_hash is used consistently across the codebase
# and verify its parameters match the upgradability requirements

# Search for compute_unique_hash usage
echo "Checking compute_unique_hash usage patterns:"
rg -A 3 "compute_unique_hash" 

# Search for any other hash computation methods to ensure consistency
echo "Checking for other hash computation methods:"
rg -A 3 "compute.*hash|hash.*compute"

Length of output: 57674


Script:

#!/bin/bash
# Check the compute_unique_hash implementation
ast-grep --pattern 'pub fn compute_unique_hash($$$)'

# Also check for any tests related to this function
rg -A 10 "test.*compute_unique_hash"

Length of output: 93


Script:

#!/bin/bash
# Check the compute_unique_hash implementation in element.rs
echo "Checking compute_unique_hash implementation:"
rg -A 15 "^pub fn compute_unique_hash" crates/dojo/lang/src/attribute_macros/element.rs

# Check how it's used in model.rs and event.rs
echo -e "\nChecking usage in model.rs:"
rg -A 5 "compute_unique_hash" crates/dojo/lang/src/attribute_macros/model.rs

echo -e "\nChecking usage in event.rs:"
rg -A 5 "compute_unique_hash" crates/dojo/lang/src/attribute_macros/event.rs

Length of output: 2032

crates/dojo/core-cairo-test/src/tests/world/event.cairo (1)

10-46: LGTM! Well-structured event definitions, sensei!

The event structs are well-organized with clear test cases for:

  • Member removal (FooEventMemberRemoved)
  • Member addition and removal (FooEventMemberAddedButRemoved)
  • Member movement (FooEventMemberAddedButMoved)
  • Member addition (FooEventMemberAdded)
crates/dojo/core-cairo-test/src/tests/world/entities.cairo (1)

12-12: Ohayo! Import statement looks good, sensei!

The import statement is well-organized and includes all necessary test helpers.

crates/dojo/core/src/world/world_contract.cairo (2)

Line range hint 1-15: LGTM! Clean enum implementation with proper traits.

The Permission enum and its display implementation are well-structured and follow best practices.


Line range hint 1106-1139: Skip: Issue already addressed in previous review.

The assumption about callers being Dojo contracts was already noted in past review comments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (21)
crates/dojo/core/src/lib.cairo (1)

25-30: Ohayo sensei! Well-structured resource management interfaces.

The separation between IDeployedResource and IStoredResource provides a clear distinction in resource lifecycle management, which is essential for implementing upgradability checks.

Consider documenting the following in your design docs:

  • The lifecycle flow between deployed and stored resources
  • The responsibilities of each interface in the upgradability process
  • The invariants that must be maintained during resource transitions
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (3)

7-19: Enhance documentation with upgrade constraints.

Ohayo! While the current documentation explains the purpose well, consider adding details about the upgrade constraints (e.g., layout type preservation, field ordering) to help future contributors understand the testing boundaries.


21-64: Document test scenarios for each event contract.

Ohayo sensei! Each event contract represents a specific upgrade test case, but their purposes aren't immediately clear from their names alone. Consider adding doc comments to explain what upgrade scenario each contract is testing.

For example:

/// Tests upgrade validation when attempting to change the layout type
#[derive(Copy, Drop, Serde, Debug)]
#[dojo::event]
pub struct FooEventBadLayoutType {
    // ...
}

66-79: Consider adding error handling for resource deployment.

Ohayo sensei! The deploy_world_for_event_upgrades function uses unwrap() on class hash conversions. While this might be acceptable for tests, consider handling potential errors explicitly to make test failures more informative.

- TestResource::Event(old_foo_event_bad_layout_type::TEST_CLASS_HASH.try_into().unwrap()),
+ TestResource::Event(old_foo_event_bad_layout_type::TEST_CLASS_HASH.try_into()
+     .expect("Failed to convert bad layout type class hash")),
crates/torii/types-test/src/contracts.cairo (2)

112-113: Clean method chaining style, sensei!

The refactored event emission using method chaining improves code readability while maintaining the same functionality.


Line range hint 116-131: Ohayo sensei, there are some concerns with the delete implementation!

  1. The subrecord_id calculation (record_id + 1) makes assumptions about ID generation patterns, which could lead to errors if the ID generation strategy changes.
  2. Missing error handling for non-existent records.
  3. Consider emitting a deletion event for tracking purposes.

Here's a suggested improvement:

 fn delete(ref self: ContractState, record_id: u32) {
     let mut world = self.world(@"types_test");
-    let record: Record = world.read_model(record_id);
-    let record_sibling: RecordSibling = world.read_model(record_id);
-    let subrecord_id = record_id + 1;
-    let subrecord: Subrecord = world.read_model((record_id, subrecord_id));
+    // Get the record first to verify it exists
+    match world.try_read_model::<Record>(record_id) {
+        Option::Some(record) => {
+            let record_sibling: RecordSibling = world.read_model(record_id);
+            
+            // Read all subrecords associated with this record_id
+            let subrecords = world.read_models_by_keys::<Subrecord>(record_id);
 
-    world.erase_model(@record);
-    world.erase_model(@record_sibling);
-    world.erase_model(@subrecord);
+            // Delete all related records
+            world.erase_model(@record);
+            world.erase_model(@record_sibling);
+            for subrecord in subrecords {
+                world.erase_model(@subrecord);
+            }
+            
+            // Emit deletion event
+            world.emit_event(
+                @RecordDeleted { record_id }
+            );
+        },
+        Option::None => {
+            panic!("Record not found");
+        }
+    }
 }

Note: You'll need to add the RecordDeleted event to your event definitions:

#[derive(Drop, Serde, starknet::Event)]
#[dojo::event]
struct RecordDeleted {
    #[key]
    record_id: u32,
}
crates/dojo/lang/src/attribute_macros/element.rs (1)

86-107: Ohayo sensei! Please add documentation for the new hash function.

The implementation looks solid and aligns well with the upgradability requirements. However, it would be beneficial to add documentation explaining:

  • The purpose of this hash (upgradability checking)
  • The components that make the hash unique
  • Why poseidon hash was chosen

Add this documentation above the function:

/// Computes a unique hash for an element based on its structure.
/// This hash is used to verify upgradability by ensuring structural compatibility.
///
/// # Arguments
///
/// * `db` - The syntax database
/// * `element_name` - Name of the element
/// * `is_packed` - Whether the element is packed
/// * `members` - List of element members
///
/// # Returns
///
/// A Felt containing the unique hash computed using poseidon for cryptographic uniqueness
crates/dojo/lang/src/attribute_macros/model.rs (2)

18-19: Ohayo sensei! Good architectural decision on code reuse.

The reuse of compute_unique_hash from the element module aligns well with the DRY principle and ensures consistent hash computation across models and elements.

Consider documenting the hash computation strategy in a central location since it's now shared between models and elements.


180-180: Ohayo sensei! Good integration of the unique hash.

The integration of unique_hash into the RewriteNode interpolation ensures that the hash is available at runtime for upgrade validation.

Consider adding a comment explaining how this hash is used during runtime validation of model upgrades.

crates/dojo/core-cairo-test/src/tests/world/event.cairo (2)

48-82: Consider enhancing event address verification.

Ohayo, sensei! While the test is comprehensive, consider adding an assertion to verify that the event's address matches the expected contract address.

 if let world::Event::EventRegistered(event) = event.unwrap() {
     assert(event.name == Event::<SimpleEvent>::name(), 'bad event name');
     assert(event.namespace == "dojo", 'bad event namespace');
     assert(
         event.class_hash == e_SimpleEvent::TEST_CLASS_HASH.try_into().unwrap(),
         'bad event class_hash'
     );
     assert(
         event.address != core::num::traits::Zero::<ContractAddress>::zero(),
         'bad event prev address'
     );
+    // Verify the specific contract address
+    assert(event.address == e_SimpleEvent::TEST_ADDRESS, 'bad event address');
 }

271-273: Consider tracking the CONTRACT_NOT_DEPLOYED comment.

Ohayo, sensei! The comment indicates a temporary state regarding CONTRACT_NOT_DEPLOYED behavior. This should be tracked for future updates.

Would you like me to create a GitHub issue to track this TODO item?

crates/dojo/core-cairo-test/src/tests/world/model.cairo (3)

11-56: Ohayo, sensei! Consider adding documentation for test model structs.

The model structs are well-designed to test various upgrade scenarios. However, adding documentation comments explaining the purpose of each struct would make the test cases more maintainable and easier to understand.

Add documentation like this:

/// Tests model upgrade validation when layout type changes
#[derive(Introspect, Copy, Drop, Serde)]
#[dojo::model]
pub struct FooModelBadLayoutType {
    // ... existing fields ...
}

127-282: Consider adding more edge cases for model upgrades.

While the current test suite is comprehensive, consider adding these scenarios:

  1. Upgrading a model with circular dependencies
  2. Upgrading a model that's actively being used
  3. Concurrent upgrade attempts

Would you like me to help implement these additional test cases?


293-295: Enhance the comment for clarity.

The current comment could be more descriptive about the security implications.

Consider updating the comment to:

// This test verifies that only properly deployed Dojo contracts can register models.
// The CONTRACT_NOT_DEPLOYED error occurs because the malicious contract is not a valid
// Dojo contract and is not the authenticated account calling register_model.
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (3)

47-49: Consider using a constant for the world contract address

Ohayo sensei! The hardcoded string literal 'world' in the contract address constant could be moved to a module-level constant for better maintainability.

+ const WORLD_ADDRESS: felt252 = 'world';

 fn world_dispatcher(self: @ContractState) -> IWorldDispatcher {
-    IWorldDispatcher { contract_address: starknet::contract_address_const::<'world'>() }
+    IWorldDispatcher { contract_address: starknet::contract_address_const::<WORLD_ADDRESS>() }
 }

162-194: Add descriptive test documentation

Ohayo sensei! Consider adding documentation to explain the test's purpose, preconditions, and expected outcomes. This will help other developers understand the test scenarios better.

 #[test]
+/// Tests that a contract can be deployed by a namespace owner.
+/// 
+/// # Preconditions
+/// - Bob is granted owner role for the DOJO namespace
+/// 
+/// # Expected Outcome
+/// - Contract is successfully deployed
+/// - ContractRegistered event is emitted with correct parameters
 fn test_deploy_contract_for_namespace_owner() {

276-298: Add event data validation

Ohayo sensei! The event validation could be more thorough. Consider checking additional fields and validating the event's timestamp if available.

 let event = starknet::testing::pop_log::<world::Event>(world.contract_address);
 assert(event.is_some(), 'no event)');

 if let world::Event::ContractUpgraded(event) = event.unwrap() {
+    // Validate all event fields
     assert(
         event
             .selector == dojo::utils::selector_from_namespace_and_name(
                 DOJO_NSH, @contract_name
             ),
         'bad contract selector'
     );
     assert(event.class_hash == class_hash, 'bad class_hash');
+    // Add additional validations
+    assert(event.timestamp > 0, 'invalid timestamp');
+    assert(event.caller == bob, 'unexpected caller');
 } else {
     core::panic_with_felt252('no ContractUpgraded event');
 };
crates/dojo/core-cairo-test/src/tests/world/entities.cairo (3)

248-248: Ohayo sensei! Consider refactoring the repeated dispatcher assignment.

The pattern world = world.dispatcher is repeated across all test functions. This could be simplified by modifying the deploy_world() helper to return the dispatcher directly.

fn deploy_world() -> IWorldDispatcher {
-   World::deploy()
+   World::deploy().dispatcher
}

Also applies to: 267-267, 283-283, 299-299, 317-317, 335-335, 361-361, 379-379, 397-397, 415-415, 444-444, 470-470, 491-491, 512-512, 534-534, 559-559, 585-585, 608-608, 632-632, 655-655, 678-678, 702-702, 719-719, 736-736, 748-748, 761-761, 772-772, 784-784, 797-797, 813-813, 829-829


Line range hint 701-844: Consider enhancing panic messages for better debugging.

The error handling tests use generic messages like "Unexpected layout type for a model". Consider making these messages more specific by including the actual vs expected layout types.

Example for test_set_entity_with_unexpected_array_model_layout:

-#[should_panic(expected: ("Unexpected layout type for a model.", 'ENTRYPOINT_FAILED'))]
+#[should_panic(expected: ("Expected Struct layout, got Array layout for model.", 'ENTRYPOINT_FAILED'))]

Line range hint 248-291: Consider introducing a model registration helper.

Many tests follow the pattern of deploying the world and registering a model. This could be extracted into a helper function to reduce duplication.

fn deploy_world_with_model<T>(class_hash: felt252) -> IWorldDispatcher {
    let world = deploy_world();
    world.register_model(class_hash.try_into().unwrap());
    world
}

Usage example:

-let world = deploy_world();
-world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap());
+let world = deploy_world_with_model(foo::TEST_CLASS_HASH);
crates/dojo/core/src/world/world_contract.cairo (1)

1053-1088: Ohayo, sensei! Excellent implementation of resource upgradability checks!

The implementation enforces three key rules for upgrades:

  1. Layout type must remain the same (Struct or Fixed)
  2. Existing fields cannot be changed or moved
  3. New fields can only be appended at the end

The code effectively uses is_same_type_of and is_an_upgrade_of to verify these conditions.

Consider adding a mechanism to emit events when upgrades are rejected due to incompatibility, which could help with monitoring and debugging upgrade failures.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f6cff5f and 5947c2e.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (44)
  • Cargo.toml (1 hunks)
  • bin/sozo/src/commands/inspect.rs (0 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/entities.cairo (32 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/Cargo.toml (1 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (2 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/simple/src/lib.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
💤 Files with no reviewable changes (4)
  • bin/sozo/src/commands/inspect.rs
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (26)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/lib.cairo
  • crates/dojo/core-cairo-test/src/tests/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/component.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/Cargo.toml
  • crates/dojo/lang/src/attribute_macros/event.rs
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo
  • crates/dojo/world/src/contracts/abigen/model.rs
  • crates/dojo/world/src/contracts/model.rs
  • examples/spawn-and-move/dojo_dev.toml
🔇 Additional comments (27)
crates/dojo/core/src/lib.cairo (3)

35-35: Verify the layout comparison implementation.

The addition of LayoutCompareTrait is essential for enforcing layout type consistency during upgrades. Let's verify its implementation.

#!/bin/bash
# Description: Check the layout comparison implementation
# Expected: Find comparison logic that enforces layout type consistency

# Search for the trait implementation
ast-grep --pattern 'trait LayoutCompareTrait {
  $$$
  fn compare($$$) {
    $$$
  }
  $$$
}'

12-13: Ohayo sensei! Verify the event component implementation.

The addition of the component module aligns with the PR's objective of implementing upgradability checks for events. Let's verify its implementation.


32-32: Verify the struct comparison implementation.

The addition of StructCompareTrait is crucial for enforcing layout compatibility during upgrades. Let's verify its implementation.

✅ Verification successful

StructCompareTrait implementation verified and looks solid, sensei!

The implementation in introspect.cairo properly enforces layout compatibility by checking:

  • Struct name equality
  • Attributes equality
  • All existing fields remain unchanged (no field removals or modifications)
  • Allows new fields to be added at the end (backward compatible)

The comparison logic is strict and ensures safe upgrades by preventing breaking changes to existing struct layouts. The trait is correctly exposed through the public API for use during upgrades.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the struct comparison implementation
# Expected: Find comparison logic that enforces layout compatibility rules

# Search for the trait implementation
ast-grep --pattern 'trait StructCompareTrait {
  $$$
  fn compare($$$) {
    $$$
  }
  $$$
}'

Length of output: 190


Script:

#!/bin/bash
# Let's try a different approach to find the trait and its implementation
# First, let's search for files containing StructCompareTrait
rg "StructCompareTrait" -A 5

# Also search for any struct comparison related code
rg "struct.*compare" -A 5

Length of output: 3073


Script:

#!/bin/bash
# Let's examine the full implementation and trait definition
cat crates/dojo/core/src/meta/introspect.cairo

# Also check if there are any tests for this functionality
rg "test.*struct.*compare" -A 10

Length of output: 7009

examples/simple/src/lib.cairo (1)

24-24: Ohayo sensei! Please verify the implications of removing historical event tracking.

The removal of historical: true from the EH event aligns with the PR's goal of removing versioning management. However, we should ensure this change doesn't impact systems that might depend on historical event data.

Let's verify if there are any other historical events in the codebase:

Consider adding a comment explaining why historical tracking isn't needed for this event, to help future developers understand the design decision.

✅ Verification successful

Ohayo sensei! The removal of historical: true is safe and aligns with the framework's direction.

Based on the codebase analysis:

  • No other events are using historical: true attribute
  • The EH event is only used in the simple example and doesn't have any dependent systems
  • The framework's test data shows explicit support for historical: false events
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other historical events that might need similar updates
rg -l 'historical:\s*true' --type cairo

# Check for potential event consumers that might expect historical data
ast-grep --pattern 'fn $FUNC($_) {
  $$$
  $EVENT: EH = $$$
  $$$
}'

Length of output: 142


Script:

#!/bin/bash
# Search for historical events with proper file type
rg -l "historical:\s*true"

# Look for EH event usage patterns
rg -A 5 "struct EH"

# Check for any event-related patterns
rg "#\[dojo::event"

Length of output: 1833

crates/dojo/core/src/model/model.cairo (3)

1-3: Ohayo sensei! The import changes look good!

The switch from Ty to Struct aligns perfectly with our upgradability implementation goals.


39-39: Verify test implementations for schema changes, sensei!

The schema return type change from Ty to Struct looks good, but we need to ensure all test implementations are updated.

#!/bin/bash
# Description: Check for any remaining Ty return types in test files
# Expected: No occurrences of old return type

echo "Checking for old schema return types in test files..."
rg "fn schema\(\)\s*->\s*Ty" crates/dojo/lang/src/plugin_test_data/

Line range hint 91-116: Implementation looks clean and consistent, sensei!

The schema implementation and ModelDef construction properly reflect our move away from versioning while maintaining all essential fields.

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3)

84-89: Clean implementation of deployed and stored model interfaces, sensei!

The separation between deployed and stored model implementations provides a clear boundary for upgrade management.


110-115: Consider adding upgrade compatibility tests, sensei!

While the unique hash implementation looks good, consider adding tests that verify:

  1. Compatible model changes (e.g., adding fields at the end) produce different hashes
  2. Incompatible changes (e.g., reordering fields) also produce different hashes
  3. Edge cases like empty models or models with all optional fields

Let's check if such tests exist:

#!/bin/bash
# Search for upgrade compatibility tests
rg -g '*.cairo' "test.*upgrade|test.*compatibility" tests/

33-39: Ohayo! The schema function looks good, sensei!

The change to return Struct instead of Ty with proper type checking aligns well with the PR's upgradability goals. The panic message is clear and helpful for debugging.

Let's verify all model implementations use this correctly:

✅ Verification successful

Let me try a different pattern with ast-grep:

Let me also check for any test files that might verify schema behavior:


Ohayo! The schema function implementation is properly used across the codebase, sensei!

Based on the search results, I can confirm that:

  1. The schema function is correctly implemented in the model trait and returns Struct type
  2. All model implementations use this schema function consistently through the Model<M>::schema() pattern
  3. The schema is properly used in world contracts for model verification
  4. Test files show proper usage in model registration and validation

The change to return Struct instead of Ty is safely implemented across the entire codebase with proper type checking.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any direct usage of schema() that might not handle the Struct type
ast-grep --pattern 'fn $name($_) {
  $$$
  schema()
  $$$
}'

Length of output: 259


Script:

#!/bin/bash
# Search for schema() function calls in cairo files
rg -g '*.cairo' 'schema\(\)' -A 2 -B 2

# Also search for any model implementations
rg -g '*.cairo' 'impl.*Model' -A 5 -B 5

Length of output: 49417


Script:

#!/bin/bash
# Search for schema function implementations
ast-grep --pattern 'fn schema() -> $return_type$ {
  $$$
}'

Length of output: 61


Script:

#!/bin/bash
# Find test files
fd -e cairo test

# Search for model-related tests
rg -g '*.cairo' '#\[test\].*model' -A 5

Length of output: 205

crates/torii/types-test/src/contracts.cairo (1)

Line range hint 1-5: Ohayo! The interface changes look solid, sensei!

The addition of the delete method to the IRecords trait with a u32 record_id parameter aligns well with the existing Record structure.

crates/dojo/lang/src/attribute_macros/element.rs (2)

7-7: Ohayo sensei! The new imports look good!

The added imports support the new hashing functionality and are well-organized.

Also applies to: 12-13


86-107: Consider adding validation for empty members list.

The hash computation might be less effective if the members list is empty. Consider adding validation to ensure meaningful hash generation.

Let's check if there are any test cases with empty members:

Consider adding this validation at the start of the function:

if members.is_empty() {
    // Either return a special hash or handle as needed
    return poseidon_hash_many(&[
        if is_packed { Felt::ONE } else { Felt::ZERO },
        compute_bytearray_hash(element_name),
    ]);
}
crates/dojo/core/src/meta/introspect.cairo (1)

38-61: Verify integration with layout checks, sensei!

The PR objectives mention maintaining the same layout type (Struct/Fixed), but this implementation doesn't explicitly verify this requirement. We should ensure this is handled elsewhere in the codebase.

Let's check how layout types are verified:

✅ Verification successful

Ohayo sensei! The layout type verification is properly handled elsewhere

The implementation is correct as the layout type verification is handled in the world contract's assert_resource_upgradability function, which checks both:

  1. Layout type preservation via is_same_type_of (in LayoutCompareTrait)
  2. Schema compatibility via is_an_upgrade_of (the implementation we're reviewing)

The code works together with these components to ensure:

  • Same layout type is maintained (Fixed/Struct)
  • No changes to existing fields
  • New fields only at the end
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for layout type checks in the codebase
echo "Searching for layout type handling..."
rg -A 5 "Layout::(Struct|Fixed)" --type cairo

# Search for other upgrade validation logic
echo "Searching for other upgrade validation..."
rg -A 5 "is_an_upgrade|can_upgrade|validate_upgrade" --type cairo

Length of output: 353


Script:

#!/bin/bash
# Search for layout type checks without file type restriction
echo "Searching for layout type handling..."
rg -A 5 "Layout::(Struct|Fixed)"

# Search for other upgrade validation logic
echo "Searching for other upgrade validation..."
rg -A 5 "is_an_upgrade|can_upgrade|validate_upgrade"

# Let's also check the specific file and its imports
echo "Checking the specific file and related imports..."
cat crates/dojo/core/src/meta/introspect.cairo

# Search for layout-related code in the meta module
echo "Checking meta module for layout handling..."
fd . crates/dojo/core/src/meta/ -t f -x cat {}

Length of output: 81580


Script:

#!/bin/bash
# Let's check how the layout type is verified during upgrades
echo "Checking world contract upgrade validation..."
cat crates/dojo/core/src/world/world_contract.cairo

# Let's also check if there are any layout comparison implementations
echo "Checking layout comparison implementations..."
cat crates/dojo/core/src/meta/layout.cairo

# Search for any other upgrade-related code
echo "Searching for upgrade-related code..."
rg "upgrade" --type rust --type cairo

Length of output: 49413

crates/dojo/lang/src/attribute_macros/model.rs (2)

160-162: Essential mechanism for upgrade validation.

The unique_hash computation is a crucial addition that enables enforcement of upgrade rules. It creates a deterministic hash based on the model's structure, which can be used to validate that:

  1. Existing fields remain unchanged
  2. New fields are only added at the end
  3. Layout type remains consistent

Let's verify the hash computation implementation:

#!/bin/bash
# Description: Verify hash computation consistency
# Expected: Hash computation should be identical across models and elements

# Compare hash computation in models and elements
ast-grep --pattern 'compute_unique_hash($_, $_, $_, $_)'

155-156: Critical addition for layout type enforcement.

The is_packed flag is essential for enforcing layout type consistency during upgrades. This aligns with the PR objective of maintaining the same layout type (Struct or Fixed) across upgrades.

Let's verify the derive attribute handling:

✅ Verification successful

Ohayo sensei! Based on the code analysis, I can now provide a final response:

The is_packed flag is indeed critical for layout consistency

The flag is used in compute_unique_hash to generate a unique hash that incorporates the model's layout type (packed vs unpacked). This hash is essential because:

  • It's computed during model definition using the is_packed status
  • The same hash computation is used during upgrades to ensure layout consistency
  • Events explicitly prevent packed layouts (is_packed = false) while models can be either packed or unpacked

This verification confirms that the review comment is accurate in highlighting the importance of is_packed for maintaining layout consistency during upgrades.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent DOJO_PACKED_DERIVE usage across models
# Expected: Models should maintain consistent packing across versions

# Search for model definitions with DOJO_PACKED_DERIVE
rg --type rust "derive.*DOJO_PACKED_DERIVE" -B 2 -A 2

Length of output: 446


Script:

#!/bin/bash
# Let's check the definition and usage of DOJO_PACKED_DERIVE constant
rg "DOJO_PACKED_DERIVE" -B 2 -A 2

# Also check where compute_unique_hash is defined to understand its role
ast-grep --pattern 'fn compute_unique_hash($$$) {
  $$$
}'

# Check for any model upgrade related code
rg "upgrade" --type rust -B 2 -A 2

Length of output: 27685


Script:

#!/bin/bash
# Let's check the compute_unique_hash implementation to understand how is_packed is used
ast-grep --pattern 'fn compute_unique_hash($$$) {
  $$$
}'

# Also check for any model upgrade related code that uses is_packed
rg "compute_unique_hash.*is_packed" -B 2 -A 2

Length of output: 499


Script:

#!/bin/bash
# Let's check the model upgrade implementation to understand how layout consistency is enforced
rg "model.*upgrade" --type rust -A 10 -B 2 crates/dojo/world/

# Also check for any hash comparison during upgrades
rg "unique_hash" --type rust -A 5 -B 5

Length of output: 7976

crates/dojo/core-cairo-test/src/tests/world/event.cairo (2)

10-46: LGTM! Well-structured event definitions for upgrade testing scenarios.

Ohayo, sensei! The event structs are well-designed with:

  • Consistent use of #[dojo::event] attribute
  • Proper field types and #[key] attributes
  • Strategic field variations to test different upgrade scenarios

84-101: Previous comment about #[should_panic] syntax is still applicable.

crates/dojo/core-cairo-test/src/tests/world/model.cairo (1)

58-125: Ohayo! Comprehensive test coverage for model registration.

The test cases effectively validate:

  • Namespace owner permissions
  • Model name format validation
  • Namespace writer permissions
  • Event emission
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1)

251-261: Consider additional security checks for malicious contracts

Ohayo sensei! While the test verifies that malicious contracts cannot deploy contracts, consider adding more test cases to cover:

  1. Malicious contracts attempting to impersonate legitimate contracts
  2. Replay attack scenarios
  3. Contract address spoofing attempts
crates/dojo/core-cairo-test/src/tests/world/entities.cairo (1)

Line range hint 1-844: Excellent test coverage, sensei!

The test suite provides comprehensive coverage across various scenarios:

  • Different data types and layouts
  • Error cases and edge conditions
  • Entity operations (set, delete, get)
  • Complex data structures including arrays, enums, and nested types
crates/dojo/core/src/world/world_contract.cairo (6)

42-45: LGTM! Required imports for upgradability checks.

The new imports from dojo::meta provide the necessary types and traits for implementing resource upgradability checks.


Line range hint 429-434: LGTM! Improved event registration with IDeployedResourceDispatcher.

The switch to IDeployedResourceDispatcher provides a unified interface for resource management.


Line range hint 533-538: LGTM! Consistent model registration with IDeployedResourceDispatcher.

The implementation maintains consistency with event handling using the same dispatcher type.


Line range hint 1106-1137: LGTM! Consistent resource name resolution.

The implementation uses IDeployedResourceDispatcher consistently across different resource types (contract, event, model) for name resolution.

Note: The existing comment about handling non-Dojo callers is still valid here.


605-608: Verify upgradability check for models.

The upgradability check ensures model layouts and schemas remain compatible during upgrades.

✅ Verification successful

Upgradability checks for models are properly implemented, sensei!

The codebase shows robust model upgrade validation through:

  • Schema compatibility check via is_an_upgrade_of ensuring new schemas maintain backward compatibility
  • Layout validation comparing old and new model layouts
  • Comprehensive error handling with specific messages for schema and layout violations
  • Test coverage including positive and negative upgrade scenarios

The implementation in assert_resource_upgradability ensures safe model upgrades by validating both the schema and layout remain compatible, protecting against breaking changes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify model upgrades maintain compatibility
# Test: Search for model upgrade calls to ensure they're checked
rg -A 5 'upgrade_model.*assert_resource_upgradability'

Length of output: 56


Script:

#!/bin/bash
# Let's search for the assert_resource_upgradability function definition and its usage
ast-grep --pattern 'fn assert_resource_upgradability($$$)'

# Also search for upgrade_model function to see its implementation
ast-grep --pattern 'fn upgrade_model($$$)'

# Search for any calls to upgrade_model
rg "upgrade_model\(" -A 5

# Let's also check for any resource upgrade related functions
rg "resource.*upgrade" -A 5

Length of output: 12397


Script:

#!/bin/bash
# Let's check the assert_resource_upgradability implementation
rg -A 10 "fn assert_resource_upgradability"

# Also check for any schema compatibility checks
rg -A 5 "is_an_upgrade_of"

# And look for any layout compatibility checks
rg -A 5 "layout.*compatible"

Length of output: 2064


501-504: Verify upgradability check for events.

The new upgradability check ensures event layouts and schemas remain compatible during upgrades.

Comment on lines +95 to +103
fn schema(self: @ContractState) -> dojo::meta::introspect::Struct {
if let dojo::meta::introspect::Ty::Struct(mut s) =
dojo::meta::introspect::Introspect::<super::FooBaseEvent>::ty() {
s.name = 'FooEventBadLayoutType';
s
} else {
panic!("Unexpected schema.")
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve schema conversion error handling.

Ohayo sensei! The schema conversion uses a panic for unexpected types. Consider returning a Result instead to handle errors more gracefully:

- fn schema(self: @ContractState) -> dojo::meta::introspect::Struct {
+ fn schema(self: @ContractState) -> Result<dojo::meta::introspect::Struct, ByteArray> {
     if let dojo::meta::introspect::Ty::Struct(mut s) =
         dojo::meta::introspect::Introspect::<super::FooBaseEvent>::ty() {
         s.name = 'FooEventBadLayoutType';
-        s
+        Ok(s)
     } else {
-        panic!("Unexpected schema.")
+        Err("Expected struct type for schema conversion".into())
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn schema(self: @ContractState) -> dojo::meta::introspect::Struct {
if let dojo::meta::introspect::Ty::Struct(mut s) =
dojo::meta::introspect::Introspect::<super::FooBaseEvent>::ty() {
s.name = 'FooEventBadLayoutType';
s
} else {
panic!("Unexpected schema.")
}
}
fn schema(self: @ContractState) -> Result<dojo::meta::introspect::Struct, ByteArray> {
if let dojo::meta::introspect::Ty::Struct(mut s) =
dojo::meta::introspect::Introspect::<super::FooBaseEvent>::ty() {
s.name = 'FooEventBadLayoutType';
Ok(s)
} else {
Err("Expected struct type for schema conversion".into())
}
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (14)
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (2)

21-64: Add documentation for each event's test purpose.

Ohayo sensei! While the event structures are well-defined, it would be helpful to add documentation comments for each event struct explaining its specific test scenario (e.g., what kind of upgrade failure it's meant to test).

Example documentation:

/// Tests upgrade validation when layout type changes
pub struct FooEventBadLayoutType {
    // ...
}

/// Tests upgrade validation when a member is removed
struct FooEventMemberRemoved {
    // ...
}

66-79: Consider using a const array for test resources.

Ohayo sensei! To improve maintainability, consider extracting the test resources into a const array:

const EVENT_RESOURCES: Array<TestResource> = [
    TestResource::Event(old_foo_event_bad_layout_type::TEST_CLASS_HASH.try_into().unwrap()),
    TestResource::Event(e_FooEventMemberRemoved::TEST_CLASS_HASH.try_into().unwrap()),
    // ... other resources
];

pub fn deploy_world_for_event_upgrades() -> IWorldDispatcher {
    let namespace_def = NamespaceDef {
        namespace: "dojo",
        resources: EVENT_RESOURCES.span()
    };
    spawn_test_world([namespace_def].span()).dispatcher
}
crates/dojo/lang/src/attribute_macros/element.rs (1)

17-40: Ohayo! The hash computation looks solid, but could use more documentation, sensei!

While the implementation is robust, considering both structure and content for uniqueness, it would be beneficial to add documentation about:

  • The significance of the packed/unpacked flag in the hash
  • How this hash helps enforce upgradability rules
  • Potential hash collision considerations

Consider adding these clarifying comments:

 /// Compute a unique hash based on the element name and types and names of members.
 /// This hash is used in element contracts to ensure uniqueness.
+/// 
+/// The hash combines:
+/// 1. A flag indicating if the structure is packed (1) or unpacked (0)
+/// 2. The element name
+/// 3. For each member: a hash of its name and type
+/// 
+/// This ensures that any changes to existing fields or their order will result in a different hash,
+/// enforcing the upgradability rules where only appending new fields is allowed.
xtask/generate-test-db/src/main.rs (2)

57-59: Ohayo! Nice improvement to error readability, sensei!

The hex formatting of the world address makes debugging easier. However, we could make this even more helpful by showing both addresses side by side.

Consider enhancing the error message further:

-            "The deterministic world address is different from the config world address. Please \
-             review the `dojo_dev.toml` file of spawn-and-move example. \nComputed world address: \
-             {:x}",
-            deterministic_world_address
+            "World address mismatch in spawn-and-move example. Please review `dojo_dev.toml`:\n\
+             Deterministic: 0x{:x}\n\
+             Config:        0x{:x}",
+            deterministic_world_address,
+            config_world_address

56-60: Consider enhancing error handling for better testing feedback, sensei!

Given this utility's role in testing model/event upgradability, we might want to provide more structured error handling instead of panic.

Consider:

  1. Creating a custom error type for migration issues:
#[derive(Debug, thiserror::Error)]
pub enum MigrationError {
    #[error("World address mismatch: expected {expected:x}, got {actual:x}")]
    WorldAddressMismatch {
        expected: Felt,
        actual: Felt,
    },
    // ... other migration-specific errors
}
  1. Propagating errors instead of panicking to allow test frameworks to handle them appropriately:
if deterministic_world_address != config_world_address {
    return Err(MigrationError::WorldAddressMismatch {
        expected: config_world_address,
        actual: deterministic_world_address,
    }.into());
}
crates/dojo/core/src/meta/introspect.cairo (1)

38-61: Ohayo sensei! Consider adding upgrade validation tests.

To ensure the upgrade rules are properly enforced, we should add comprehensive tests covering:

  1. Valid upgrades with new fields added at the end
  2. Invalid upgrades attempting to modify existing fields
  3. Invalid upgrades attempting to insert fields in between
  4. Layout type compatibility checks

Would you like me to help create these test cases?

crates/dojo/lang/src/attribute_macros/model.rs (1)

180-180: Excellent integration of the unique hash, sensei!

The hash is properly integrated into the model generation process, which will enable runtime upgradability checks. This is a clean way to enforce layout compatibility without requiring explicit versioning.

Consider documenting the hash computation and verification process in the model's generated code comments to help users understand upgrade constraints.

crates/dojo/core-cairo-test/src/tests/world/event.cairo (2)

10-46: LGTM! Consider adding documentation for event structures.

Ohayo, sensei! The event structures are well-defined and serve their testing purposes effectively. However, adding documentation comments explaining the purpose of each event structure would make the test cases more maintainable.

Add documentation like this:

+/// Event structure for testing member removal scenarios
 #[derive(Copy, Drop, Serde, Debug)]
 #[dojo::event]
 pub struct FooEventMemberRemoved {

48-82: Extract event verification logic into a helper function.

Ohayo, sensei! The event verification logic in test_register_event_for_namespace_owner is duplicated across multiple tests. Consider extracting it into a reusable helper function.

fn assert_event_registered(
    event: Option<world::Event>,
    expected_name: felt252,
    expected_namespace: felt252,
    expected_class_hash: ClassHash
) {
    assert(event.is_some(), 'no event)');
    if let world::Event::EventRegistered(event) = event.unwrap() {
        assert(event.name == expected_name, 'bad event name');
        assert(event.namespace == expected_namespace, 'bad event namespace');
        assert(event.class_hash == expected_class_hash, 'bad event class_hash');
        assert(
            event.address != core::num::traits::Zero::<ContractAddress>::zero(),
            'bad event prev address'
        );
    } else {
        core::panic_with_felt252('no EventRegistered event');
    }
}
crates/dojo/core-cairo-test/src/tests/world/model.cairo (1)

127-242: Ohayo, sensei! Consider enhancing upgrade verification

While the tests thoroughly cover upgrade scenarios, consider adding assertions to verify the state of the upgraded model's data to ensure no data corruption occurs during upgrades.

Example verification:

// After upgrade
let model = world.get_model("dojo");
assert(model.c == expected_value, 'upgrade corrupted data');
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (2)

162-194: Add assertions for contract state in deployment test

Ohayo sensei! While the test verifies the event emission, it should also verify the contract's state after deployment.

Add assertions to verify:

  1. The contract's class hash matches the deployed class hash
  2. The contract's address is registered in the world
  3. The contract's namespace ownership is correctly set

Example addition:

// Add after existing assertions
let stored_class_hash = world.get_class_hash(contract_address);
assert(stored_class_hash == class_hash, 'class hash mismatch');

let is_registered = world.is_contract_registered(contract_address);
assert(is_registered, 'contract not registered');

262-299: Add negative test cases for contract upgrades

Ohayo sensei! While the positive test case is good, consider adding tests for:

  1. Upgrading to an invalid class hash
  2. Upgrading a non-existent contract
  3. Upgrading with an incompatible contract implementation

Would you like me to help generate these additional test cases?

crates/dojo/world/src/contracts/abigen/model.rs (1)

Ohayo sensei! Schema type inconsistency detected across codebase

The schema type change from Ty to Struct in ModelDef is not consistently applied across the codebase. Found several files still using Ty:

  • crates/torii/core/src/sql/cache.rs: Uses schema: Ty
  • crates/torii/core/src/sql/mod.rs: Uses Ty::Struct
  • crates/torii/grpc/src/types/mod.rs: Deserializes into schema: Ty
  • crates/dojo/types/src/schema.rs: Uses schema: Ty in ModelMetadata

These inconsistencies need to be addressed to maintain type safety and prevent potential runtime errors.

🔗 Analysis chain

Line range hint 176-217: Ohayo sensei! Changes to ModelDef look good but let's verify the impact.

The removal of versioning and schema type change from Ty to Struct aligns well with the PR objectives. However, we should verify that all consumers of ModelDef are updated accordingly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of ModelDef to ensure compatibility with schema type change

# Search for ModelDef usage patterns
echo "Searching for ModelDef struct usage..."
rg -p "ModelDef.*schema" 

# Search for potential version field references that need cleanup
echo "Checking for any remaining version references..."
rg "version.*ModelDef|ModelDef.*version"

Length of output: 471


Script:

#!/bin/bash
# Let's dive deeper into the schema type changes

# Check for Ty to Struct migration patterns
echo "Checking schema type usage patterns..."
rg -p "schema: (Ty|Struct)" -A 2 -B 2

# Look for ModelDefinition implementations
echo "Checking ModelDefinition implementations..."
ast-grep --pattern 'impl ModelDefinition<$_> for $_'

# Check for any schema() method implementations
echo "Checking schema method implementations..."
ast-grep --pattern 'fn schema() -> $_ {
  $$$
}'

Length of output: 1996

crates/dojo/core/src/world/world_contract.cairo (1)

1053-1088: Ohayo, sensei! Excellent implementation of upgradability constraints

The assert_resource_upgradability function implements a robust upgrade validation system that enforces backward compatibility through three key constraints:

  1. Layout type consistency (Struct/Fixed)
  2. Existing field preservation
  3. Append-only new fields

This approach effectively prevents breaking changes while allowing for extensibility.

Consider adding a migration mechanism in the future to handle cases where breaking changes are necessary, such as field reordering or type changes.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5947c2e and 65b01e8.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (45)
  • Cargo.toml (1 hunks)
  • bin/sozo/src/commands/inspect.rs (0 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/entities.cairo (32 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/Cargo.toml (1 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (1 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/simple/src/lib.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
  • xtask/generate-test-db/src/main.rs (1 hunks)
💤 Files with no reviewable changes (4)
  • bin/sozo/src/commands/inspect.rs
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (30)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/lib.cairo
  • crates/dojo/core-cairo-test/src/tests/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/entities.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/lib.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/component.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/model/model.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/Cargo.toml
  • crates/dojo/lang/src/attribute_macros/event.rs
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo
  • crates/dojo/world/src/contracts/model.rs
  • crates/torii/types-test/src/contracts.cairo
  • examples/simple/src/lib.cairo
  • examples/spawn-and-move/dojo_dev.toml
🔇 Additional comments (25)
crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (2)

1-19: LGTM! Well-structured base event definition.

Ohayo sensei! The base event structure and imports are well-organized with clear documentation explaining the purpose of these test contracts.


105-108: Verify unreachable code path in layout function.

Ohayo sensei! The comment suggests this code path should never execute, but let's verify this assumption:

✅ Verification successful

Empty layout is indeed unreachable in event implementations

Ohayo sensei! After careful investigation, I can confirm that the empty layout is indeed unreachable. Here's why:

  1. All event structs in the codebase use the #[dojo::event] attribute macro
  2. The #[dojo::event] macro automatically implements the Event trait with proper layout derived from the struct's fields
  3. The empty layout implementation in the test file is only used as a placeholder for testing error cases

The comment "Should never happen as dojo::event always derive Introspect" is accurate because the macro system ensures proper layout implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for any calls to the layout function that might trigger the empty layout return

# Test 1: Search for direct calls to layout
rg -A 3 "layout\(" 

# Test 2: Search for trait implementations that might override this behavior
ast-grep --pattern 'impl $_ of dojo::meta::interface::IStoredResource<$_> {
    $$$
    fn layout($_) {
        $$$
    }
    $$$
}'

Length of output: 130077


Script:

#!/bin/bash
# Let's verify if dojo::event always derives Introspect by checking for event implementations

# Search for event implementations and their layout patterns
ast-grep --pattern 'impl $_ of dojo::event::Event<$_> {
  $$$
  fn layout() -> $_ {
    $$$
  }
  $$$
}'

# Search for #[derive] attributes on event types
rg "#\[derive.*\].*struct.*Event" -A 2

# Search for any event-related derive macros
rg "derive.*Event" -A 2

Length of output: 15004


Script:

#!/bin/bash
# Let's check for the dojo::event macro and its implementation

# Search for dojo::event macro usage
rg "#\[dojo::event\]" -B 2 -A 2

# Search for the event macro implementation
ast-grep --pattern 'macro_rules! event {
  $$$
}'

# Search for any files that implement event traits without Introspect
rg "impl.*Event.*\{" -A 5 --glob "*.cairo"

Length of output: 9394

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3)

33-39: Ohayo! Nice type safety improvement, sensei!

The updated schema() function now properly ensures the model has a Struct layout type, which aligns perfectly with the PR's objective of maintaining layout type consistency. The panic message is clear and helpful for debugging.


84-89: Clean separation of deployed and stored model implementations!

The addition of separate implementations for deployed and stored models with proper ABI embedding provides a clear distinction between the two states, which is essential for managing model upgradability.


110-115: Documentation request still applies, sensei!

A previous review already highlighted the need for documenting the unique hash computation. This is still relevant as the hash is critical for model upgradability.

crates/dojo/lang/src/attribute_macros/element.rs (2)

7-7: Ohayo! The new imports look good, sensei!

The additions of Member AST and dojo_types imports align well with the new hash computation functionality.

Also applies to: 12-12


31-35: 🛠️ Refactor suggestion

Consider normalizing type definitions, sensei!

While trim() handles leading/trailing whitespace, different spacing within type definitions could lead to different hashes. For example, Array<felt252> vs Array < felt252 >.

Let's check if there are any inconsistent type definitions in the codebase:

Consider normalizing type strings before hashing:

-                        m.type_clause(db).ty(db).as_syntax_node().get_text(db).trim(),
+                        &normalize_type_string(m.type_clause(db).ty(db).as_syntax_node().get_text(db).trim()),
crates/dojo/lang/src/attribute_macros/model.rs (2)

18-18: Ohayo! LGTM on the new import, sensei!

The addition of compute_unique_hash import aligns perfectly with the PR's objective of implementing model upgradability checks.


155-162: Verify hash computation for upgradability checks

The implementation looks solid with the hash computation considering:

  • Model type
  • Packed/unpacked status
  • Member structure

This aligns with the PR objectives of ensuring safe upgrades by maintaining layout compatibility.

Let's verify the hash computation implementation:

crates/dojo/core-cairo-test/src/tests/world/event.cairo (2)

169-218: LGTM! Comprehensive upgrade validation tests.

Ohayo, sensei! The upgrade tests effectively cover various scenarios including layout type changes, member removal, and field reordering. The error messages are clear and descriptive.


271-287: LGTM! Well-structured security validation tests.

Ohayo, sensei! The permission tests effectively validate security constraints, including protection against malicious contracts. The comment explaining the CONTRACT_NOT_DEPLOYED scenario is particularly helpful.

crates/dojo/core-cairo-test/src/tests/world/model.cairo (4)

11-56: Ohayo, sensei! Well-structured model definitions for testing upgrade scenarios

The model structs are thoughtfully designed to cover various upgrade scenarios including layout changes, field modifications, and structural alterations. Each struct serves a specific test case purpose.


74-74: Fix typo in assertion message

The assertion message contains an extraneous closing parenthesis in 'no event)'.


58-125: Ohayo, sensei! Comprehensive test coverage for model registration

The test cases effectively validate:

  • Registration by namespace owner
  • Invalid model name handling
  • Permission checks for writers

244-309: Ohayo, sensei! Robust security testing implementation

The access control tests effectively validate:

  • Writer permission restrictions
  • Protection against unauthorized upgrades
  • Malicious contract prevention
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (2)

78-79: Skip: Incorrect #[should_panic] attribute usage

These issues have been previously identified in past review comments.

Also applies to: 92-93, 198-201, 232-233, 246-247, 302-307, 336-341, 359-360


1-379: LGTM: Overall test structure and coverage

Ohayo sensei! The test file is well-structured and provides comprehensive coverage for contract upgrades and namespace management. The tests cover:

  • Contract deployment permissions
  • Upgrade permissions
  • Namespace ownership
  • Error cases and security checks
crates/dojo/world/src/contracts/abigen/model.rs (2)

Line range hint 627-636: LGTM! Clean schema method implementation.

The schema method's return type change to Struct is consistent with the ModelDef changes.


Line range hint 732-741: LGTM! Consistent implementation with ModelContract.

The schema method implementation maintains perfect symmetry with its ModelContract counterpart.

crates/dojo/core/src/world/world_contract.cairo (6)

42-45: LGTM! Clean import organization

The new imports from dojo::meta are well-organized and support the new upgradability checking functionality.


658-658: LGTM! Consistent contract handling

The contract registration and upgrade logic maintains consistency with other resource types through the use of IDeployedResourceDispatcher.

Also applies to: 713-713


748-748: LGTM! Improved error handling

The contract initialization error handling is improved through consistent use of IDeployedResourceDispatcher.


1106-1106: LGTM! Clear error messages

The error handling improvements provide clearer messages by using IDeployedResourceDispatcher to resolve resource names consistently.

Also applies to: 1112-1112, 1118-1118, 1137-1137


533-533: Verify model upgrade constraints

The implementation maintains consistency with event handling and correctly enforces upgradability constraints for models.

#!/bin/bash
# Description: Verify that model upgrades maintain backward compatibility
# Test: Search for model upgrade calls to ensure they handle layout changes correctly
rg -A 5 "upgrade_model"

Also applies to: 579-579, 605-608


429-429: Verify event upgrade constraints

The implementation correctly enforces upgradability constraints for events. The use of IDeployedResourceDispatcher improves type safety.

Also applies to: 475-475, 501-504

Comment on lines +38 to +61
#[generate_trait]
pub impl StructCompareImpl of StructCompareTrait {
fn is_an_upgrade_of(self: @Struct, old: @Struct) -> bool {
if self.name != old.name
|| self.attrs != old.attrs
|| (*self.children).len() < (*old.children).len() {
return false;
}

let mut i = 0;

loop {
if i >= (*old.children).len() {
break true;
}

if *old.children[i] != *self.children[i] {
break false;
}

i += 1;
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ohayo sensei! The struct comparison implementation needs enhancement to fully support the upgrade rules.

The current implementation doesn't fully enforce all the upgrade rules mentioned in the PR objectives. Here are the key issues:

  1. Missing layout type verification
  2. No explicit check that new fields are only added at the end
  3. Lacks documentation explaining the upgrade rules

Consider this enhanced implementation:

 #[generate_trait]
 pub impl StructCompareImpl of StructCompareTrait {
+    /// Checks if this struct is a valid upgrade of another struct.
+    /// Rules for valid upgrades:
+    /// 1. Same layout type must be maintained
+    /// 2. Existing fields must remain unchanged (name, type, position)
+    /// 3. New fields can only be added at the end
     fn is_an_upgrade_of(self: @Struct, old: @Struct) -> bool {
         if self.name != old.name
             || self.attrs != old.attrs
             || (*self.children).len() < (*old.children).len() {
             return false;
         }
 
-        let mut i = 0;
-
-        loop {
-            if i >= (*old.children).len() {
-                break true;
-            }
-
-            if *old.children[i] != *self.children[i] {
-                break false;
-            }
-
-            i += 1;
-        }
+        // Verify all existing fields remain unchanged
+        let mut all_fields_match = true;
+        let old_len = (*old.children).len();
+        
+        // Check that existing fields are unchanged
+        let existing_fields_match = old.children.enumerate().all(|(i, old_member)| {
+            let new_member = *self.children[i];
+            old_member.name == new_member.name 
+                && old_member.ty == new_member.ty 
+                && old_member.attrs == new_member.attrs
+        });
+        
+        // Verify no fields were inserted in between (only appended)
+        let new_fields_at_end = (*self.children).len() == old_len 
+            || (*self.children)[..old_len] == *old.children;
+            
+        existing_fields_match && new_fields_at_end
     }
 }

Additionally, we should add a method to verify layout type compatibility:

/// Verifies that the layout types are compatible for upgrade
fn has_compatible_layout_with(self: @Struct, old: @Struct) -> bool {
    // Add layout type comparison logic here
    // This should ensure both structs use the same layout type (Struct or Fixed)
    true // Placeholder - implement actual logic
}

Comment on lines +23 to +25
pub trait IQuantumLeap<T> {
fn plz_more_tps(self: @T) -> felt252;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve type safety and naming in IQuantumLeap trait

Ohayo sensei! The implementation has a few concerns:

  1. The function name plz_more_tps is non-descriptive and doesn't follow standard naming conventions.
  2. The function returns a string literal 'daddy' as felt252 which could lead to type safety issues.

Consider applying these changes:

-    fn plz_more_tps(self: @T) -> felt252;
+    fn get_transactions_per_second(self: @T) -> felt252;

// In the implementation:
-    fn plz_more_tps(self: @ContractState) -> felt252 {
-        'daddy'
+    fn get_transactions_per_second(self: @ContractState) -> felt252 {
+        // Return an actual TPS value
+        1000

Also applies to: 40-42

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (15)
crates/dojo/core/src/lib.cairo (1)

25-30: Essential interfaces for resource management, sensei!

The new resource interfaces (IDeployedResource and IStoredResource) are crucial for implementing the upgradability checks mentioned in the PR objectives. These interfaces will help enforce the conditions for upgrading models and events.

Consider documenting the specific upgrade conditions (same layout type, no field changes/movements) in the interface definitions to make the constraints clear to implementers.

crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (2)

21-64: Consider reducing code duplication in test events.

Ohayo sensei! While each event serves a different test scenario, they share identical fields. Consider using a macro to generate these test events to reduce duplication while maintaining isolation:

macro_rules! define_test_event {
    ($name:ident) => {
        #[derive(Copy, Drop, Serde, Debug)]
        #[dojo::event]
        struct $name {
            #[key]
            pub caller: ContractAddress,
            pub a: felt252,
            pub b: u128,
        }
    };
}

define_test_event!(FooEventBadLayoutType);
define_test_event!(FooEventMemberRemoved);
// ... etc

66-79: Enhance deployment function readability.

Ohayo sensei! Consider these improvements for better maintainability:

+ const DOJO_NAMESPACE: felt252 = 'dojo';

 pub fn deploy_world_for_event_upgrades() -> IWorldDispatcher {
     let namespace_def = NamespaceDef {
-        namespace: "dojo",
+        namespace: DOJO_NAMESPACE,
         resources: [
             TestResource::Event(
                 old_foo_event_bad_layout_type::TEST_CLASS_HASH
                     .try_into()
                     .unwrap()
             ),
             // ... rest of resources
         ].span()
     };
     spawn_test_world([namespace_def].span()).dispatcher
 }
crates/dojo/lang/src/attribute_macros/element.rs (2)

13-14: Documentation could be more detailed, sensei!

While the current documentation is good, it would be more helpful to explicitly mention:

  • How this hash is used in the upgradability checking process
  • What changes to the element would result in a different hash
  • The implications for upgrade compatibility

15-36: Consider adding input validation, sensei!

The implementation looks solid for generating unique hashes! However, consider adding validation for:

  • Empty element_name
  • Empty members array
  • Duplicate member names

This would help prevent potential issues during upgrades.

Here's a suggested improvement:

 pub fn compute_unique_hash(
     db: &dyn SyntaxGroup,
     element_name: &str,
     is_packed: bool,
     members: &[MemberAst],
 ) -> Felt {
+    if element_name.is_empty() {
+        panic!("Element name cannot be empty");
+    }
+    if members.is_empty() {
+        panic!("Members array cannot be empty");
+    }
+    
+    // Check for duplicate member names
+    let mut seen_names = std::collections::HashSet::new();
+    for member in members {
+        let name = member.name(db).text(db).to_string();
+        if !seen_names.insert(name) {
+            panic!("Duplicate member name detected");
+        }
+    }
+
     let mut hashes =
         vec![if is_packed { Felt::ONE } else { Felt::ZERO }, compute_bytearray_hash(element_name)];
     // ... rest of the function
bin/sozo/tests/test_data/policies.json (1)

47-107: Consider grouping related methods in the configuration.

Ohayo! The file structure could be improved by grouping related methods together. For example, all entity-related methods (set_entity, set_entities, delete_entity, delete_entities) could be grouped together, and all event-related methods could be in another group.

Consider reorganizing the JSON structure like this:

[
  {
    "entity_operations": [
      {
        "target": "0x54d0f13bf3fb5f15a8674c5204aad35e3022af96bcc23bdbd16b7e297ffd399",
        "method": "set_entity"
      },
      {
        "target": "0x54d0f13bf3fb5f15a8674c5204aad35e3022af96bcc23bdbd16b7e297ffd399",
        "method": "set_entities"
      },
      // ... other entity methods
    ]
  },
  // ... other method groups
]
crates/dojo/lang/src/attribute_macros/event.rs (1)

114-116: Document the flag parameter's purpose, sensei!

The false flag parameter's purpose in compute_unique_hash is not immediately clear. Consider adding a comment explaining its significance or using a named constant for better clarity.

 let unique_hash =
-    compute_unique_hash(db, &event_name, false, &struct_ast.members(db).elements(db))
+    // false indicates this is an event (not a model) hash computation
+    compute_unique_hash(db, &event_name, IS_EVENT_HASH, &struct_ast.members(db).elements(db))
         .to_string();

Also applies to: 127-127

crates/dojo/lang/src/attribute_macros/model.rs (1)

18-18: Consider documenting the hash computation.

Sensei, while the compute_unique_hash import is clear, it would be helpful to add documentation about how this hash is used for upgradability checks.

Consider adding a doc comment like:

+/// Computes a unique hash for model upgradability validation.
+/// This hash is used to ensure that:
+/// 1. The layout type (Struct/Fixed) remains unchanged
+/// 2. Existing fields are not modified or moved
+/// 3. New fields are only appended at the end
use super::element::{compute_unique_hash, parse_members, serialize_member_ty};
crates/dojo/core-cairo-test/src/tests/world/model.cairo (2)

11-56: Ohayo, sensei! Well-structured model definitions for upgrade testing

The model structs are thoughtfully designed to cover various upgrade scenarios, effectively testing the model upgrade constraints. The progression from FooModelBadLayoutType to FooModelMemberAdded provides comprehensive coverage of different upgrade cases.

Consider documenting each model's purpose with comments to make the test scenarios more explicit for future maintainers. For example:

/// Tests upgrading with an incompatible layout type
#[derive(Introspect, Copy, Drop, Serde)]
#[dojo::model]
pub struct FooModelBadLayoutType {
    // ...
}

58-309: Ohayo, sensei! Comprehensive test coverage with robust error handling

The test suite effectively validates model registration and upgrade functionality with:

  • Permission checks for different roles (owner, writer)
  • Validation of model name constraints
  • Comprehensive upgrade scenarios
  • Clear error messages for failure cases

Consider grouping related tests using nested modules for better organization:

mod registration_tests {
    #[test]
    fn test_register_model_for_namespace_owner() {
        // ...
    }
    // Other registration tests...
}

mod upgrade_tests {
    #[test]
    fn test_upgrade_model_from_model_owner() {
        // ...
    }
    // Other upgrade tests...
}
crates/dojo/core-cairo-test/src/tests/world/contract.cairo (4)

8-20: Add documentation to explain the purpose of this invalid upgrade contract.

Ohayo sensei! Consider adding documentation to explain why this contract is considered invalid and how it's used in testing upgrade failures.

 #[starknet::contract]
+/// Contract used to test upgrade failures.
+/// This contract is considered invalid because it doesn't implement the required
+/// world provider interface.
 pub mod contract_invalid_upgrade {

27-58: Add documentation to explain the purpose of this upgrade contract.

Ohayo sensei! Consider adding documentation to explain how this contract serves as a valid upgrade target in tests.

 #[starknet::contract]
+/// Contract used to test successful upgrades.
+/// This contract implements all required interfaces:
+/// - IQuantumLeap: Test interface
+/// - IWorldProvider: Required for Dojo contracts
+/// - IDeployedResource: Required for Dojo contracts
 pub mod test_contract_upgrade {

111-160: Add documentation to distinguish between different invalid model contracts.

Ohayo sensei! The purpose of each invalid model contract is unclear. Consider adding documentation to explain how each contract tests different invalid scenarios.

 #[starknet::contract]
+/// Tests legacy model upgrade failures.
+/// This contract implements an invalid model that doesn't match
+/// the required legacy model interface.
 mod invalid_legacy_model {

 #[starknet::contract]
+/// Tests legacy model world upgrade failures.
+/// This contract implements an invalid model that doesn't match
+/// the required legacy model world interface.
 mod invalid_legacy_model_world {

 #[starknet::contract]
+/// Tests model upgrade failures.
+/// This contract implements an invalid model that doesn't match
+/// the required model interface.
 mod invalid_model {

 #[starknet::contract]
+/// Tests model world upgrade failures.
+/// This contract implements an invalid model that doesn't match
+/// the required model world interface.
 mod invalid_model_world {

60-379: Improve test organization with test groups.

Ohayo sensei! Consider organizing related tests into groups using mod tests blocks. This would improve readability and make the test structure clearer.

+#[cfg(test)]
+mod deployment_tests {
     #[test]
     fn test_deploy_contract_for_namespace_owner() {
         // ...
     }
     // ... other deployment tests
}

+#[cfg(test)]
+mod upgrade_tests {
     #[test]
     fn test_upgrade_from_world() {
         // ...
     }
     // ... other upgrade tests
}
crates/dojo/core/src/world/world_contract.cairo (1)

1053-1088: Well-implemented upgradability checks with clear documentation.

Ohayo sensei! The implementation effectively enforces the upgrade constraints:

  1. Layout type consistency check
  2. Schema compatibility verification
  3. Clear error messages with context

A suggestion to enhance robustness:

Consider adding debug assertions to validate the schema format before comparison. Here's a suggested addition:

 fn assert_resource_upgradability(
     self: @ContractState,
     namespace: @ByteArray,
     name: @ByteArray,
     prev_address: ContractAddress,
     new_address: ContractAddress
 ) {
+    // Debug assertions for schema validation
+    debug_assert(!old_schema.is_empty(), 'Old schema cannot be empty');
+    debug_assert(!new_schema.is_empty(), 'New schema cannot be empty');
+
     let resource = IStoredResourceDispatcher { contract_address: prev_address };
     let old_layout = resource.layout();
     let old_schema = resource.schema();
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 65b01e8 and 7dd5295.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (46)
  • Cargo.toml (1 hunks)
  • bin/sozo/src/commands/inspect.rs (0 hunks)
  • bin/sozo/tests/test_data/policies.json (2 hunks)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/contract.cairo (2 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo (3 hunks)
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo (0 hunks)
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/contract.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/entities.cairo (32 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/event.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/model.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo (0 hunks)
  • crates/dojo/core/src/contract/interface.cairo (1 hunks)
  • crates/dojo/core/src/event/component.cairo (1 hunks)
  • crates/dojo/core/src/event/event.cairo (1 hunks)
  • crates/dojo/core/src/event/interface.cairo (1 hunks)
  • crates/dojo/core/src/lib.cairo (2 hunks)
  • crates/dojo/core/src/meta/interface.cairo (1 hunks)
  • crates/dojo/core/src/meta/introspect.cairo (1 hunks)
  • crates/dojo/core/src/meta/layout.cairo (1 hunks)
  • crates/dojo/core/src/model/component.cairo (1 hunks)
  • crates/dojo/core/src/model/definition.cairo (2 hunks)
  • crates/dojo/core/src/model/interface.cairo (1 hunks)
  • crates/dojo/core/src/model/model.cairo (3 hunks)
  • crates/dojo/core/src/model/model_value.cairo (0 hunks)
  • crates/dojo/core/src/world/errors.cairo (1 hunks)
  • crates/dojo/core/src/world/world_contract.cairo (14 hunks)
  • crates/dojo/lang/Cargo.toml (1 hunks)
  • crates/dojo/lang/src/attribute_macros/element.rs (1 hunks)
  • crates/dojo/lang/src/attribute_macros/event.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/model.rs (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (2 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo (3 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3 hunks)
  • crates/dojo/world/src/contracts/abigen/model.rs (5 hunks)
  • crates/dojo/world/src/contracts/model.rs (1 hunks)
  • crates/torii/types-test/src/contracts.cairo (1 hunks)
  • examples/simple/src/lib.cairo (1 hunks)
  • examples/spawn-and-move/dojo_dev.toml (1 hunks)
  • xtask/generate-test-db/src/main.rs (1 hunks)
💤 Files with no reviewable changes (4)
  • bin/sozo/src/commands/inspect.rs
  • crates/dojo/core-cairo-test/src/tests/model/model.cairo
  • crates/dojo/core-cairo-test/src/tests/world/resources.cairo
  • crates/dojo/core/src/model/model_value.cairo
🚧 Files skipped from review as they are similar to previous changes (28)
  • Cargo.toml
  • crates/dojo/core-cairo-test/src/lib.cairo
  • crates/dojo/core-cairo-test/src/tests/contract.cairo
  • crates/dojo/core-cairo-test/src/tests/expanded/selector_attack.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo
  • crates/dojo/core-cairo-test/src/tests/helpers/model.cairo
  • crates/dojo/core-cairo-test/src/tests/utils/hash.cairo
  • crates/dojo/core-cairo-test/src/tests/world/entities.cairo
  • crates/dojo/core-cairo-test/src/tests/world/metadata.cairo
  • crates/dojo/core-cairo-test/src/tests/world/namespace.cairo
  • crates/dojo/core/src/contract/interface.cairo
  • crates/dojo/core/src/event/component.cairo
  • crates/dojo/core/src/event/event.cairo
  • crates/dojo/core/src/event/interface.cairo
  • crates/dojo/core/src/meta/interface.cairo
  • crates/dojo/core/src/meta/layout.cairo
  • crates/dojo/core/src/model/component.cairo
  • crates/dojo/core/src/model/definition.cairo
  • crates/dojo/core/src/model/interface.cairo
  • crates/dojo/core/src/world/errors.cairo
  • crates/dojo/lang/Cargo.toml
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
  • crates/dojo/lang/src/attribute_macros/patches/event.patch.cairo
  • crates/dojo/world/src/contracts/model.rs
  • crates/torii/types-test/src/contracts.cairo
  • examples/simple/src/lib.cairo
  • examples/spawn-and-move/dojo_dev.toml
  • xtask/generate-test-db/src/main.rs
🔇 Additional comments (33)
crates/dojo/core/src/lib.cairo (1)

32-32: Smart addition of comparison traits!

The StructCompareTrait and LayoutCompareTrait are excellent additions that will enable validation of upgrade compatibility by comparing structure and layout of resources.

Let's verify these traits implement the required upgrade conditions:

#!/bin/bash
# Description: Check the implementation of comparison traits
echo "Checking StructCompareTrait implementation..."
ast-grep --pattern 'trait StructCompareTrait {
  $$$
}'

echo "Checking LayoutCompareTrait implementation..."
ast-grep --pattern 'trait LayoutCompareTrait {
  $$$
}'

Also applies to: 35-35

crates/dojo/core-cairo-test/src/tests/helpers/event.cairo (3)

1-11: LGTM! Well-documented test helper.

Ohayo sensei! The imports are clean and the documentation clearly explains the purpose of these test helpers and why they avoid the dojo::event attribute.


12-19: LGTM! Well-structured base event.

The base event structure provides a solid foundation for upgrade testing with appropriate field types and introspection support.


81-110: Previous review comments still need to be addressed.

The issues regarding error handling in the schema method and the implementation of the layout method that were mentioned in previous reviews are still valid.

crates/dojo/core/src/model/model.cairo (4)

1-3: Ohayo sensei! Import changes look good!

The transition from Ty to Struct in imports aligns perfectly with our schema representation changes.


39-39: Schema return type change looks solid!

The transition to Struct return type in the schema() method signature enhances type safety and clarity.


91-93: Clean implementation, sensei!

The schema implementation follows the established delegation pattern consistently.


Line range hint 109-117: Verify complete removal of versioning, sensei!

The ModelDef struct correctly excludes versioning. Let's verify we haven't missed any version-related code.

crates/dojo/lang/src/attribute_macros/patches/model.patch.cairo (3)

84-89: Clean implementation of deployed and stored model traits, sensei!

The separation between deployed and stored model implementations provides a clear distinction of responsibilities, which is essential for the new upgradability system.


110-115: Documentation still needed for unique hash computation.

A previous review already highlighted the need for documenting the hash computation process.


33-39: Ohayo! The schema function changes look solid, sensei!

The type checking enhancement ensures models maintain their layout type (Struct), which aligns perfectly with the PR's upgradability requirements. The panic message is clear and helpful for debugging.

Let's verify no models are using non-Struct types:

✅ Verification successful

The previous pattern might have been too specific. Let's try a broader search to catch all schema implementations in Cairo files. This will help us verify if there are any non-Struct return types being used.


Ohayo! The schema function changes are safe and sound, sensei!

The search results show that existing model implementations in the test data (plugin_test_data/model) currently return dojo::meta::introspect::Ty, and the patch updates this to return dojo::meta::introspect::Struct with proper type checking. This change improves type safety while maintaining backward compatibility since Struct is obtained from Ty::Struct(s).

  • The patch ensures all models will return a Struct type
  • The panic message provides clear feedback if a model's schema isn't a Struct
  • The change aligns with the framework's type safety goals
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any model definitions that might return non-Struct types
ast-grep --pattern 'impl $name$DefinitionImpl of dojo::model::ModelDefinition<$_> {
  $$$
  fn schema() -> $ret_type$ {
    $$$
  }
  $$$
}'

Length of output: 142


Script:

#!/bin/bash
# Let's try a different approach to find model implementations and their schema types
rg -U "impl.*ModelDefinition.*\{[\s\S]*?fn schema\(\).*\{[\s\S]*?\}" --type cairo

# Also search for any direct schema function implementations
rg -U "fn schema\(\).*->.*\{" --type cairo

Length of output: 188


Script:

#!/bin/bash
# Let's try without file type restriction since Cairo might not be recognized
rg -U "impl.*ModelDefinition.*\{[\s\S]*?fn schema\(\).*\{[\s\S]*?\}"

# Also search for any files with .cairo extension to understand our codebase better
fd -e cairo

Length of output: 45986

crates/dojo/lang/src/attribute_macros/element.rs (1)

4-4: Ohayo! New imports look good, sensei!

The added imports are well-scoped and necessary for the new hashing functionality.

Also applies to: 8-9

bin/sozo/tests/test_data/policies.json (3)

3-13: Ohayo sensei! Verify the multiple upgrade targets.

I notice we have three different upgrade targets at the beginning of the file. This could pose security risks if not properly managed.

Let's check the upgrade targets usage:


111-127: Review access control method security.

The access control methods (grant_owner, revoke_owner, grant_writer, revoke_writer) are critical system operations. These should be thoroughly tested and secured.

Let's check for related tests and security measures:

✅ Verification successful

Access control methods are thoroughly tested and secured

Ohayo sensei! After reviewing the implementation and tests, I can confirm that the access control methods are well-secured:

  • Comprehensive permission hierarchy (World Owner > Namespace Owner > Resource Owner > Resource Writer)
  • Extensive test coverage including:
    • Permission granting/revocation tests
    • Malicious contract attack tests
    • Namespace ownership tests
    • Non-owner access attempt tests
    • Resource registration validation
  • Security measures implemented:
    • Permission checks before any critical operation
    • Resource existence validation
    • Protection against cross-namespace attacks
    • Contract deployment validation

The implementation in world_contract.cairo and tests in acl.cairo demonstrate robust security practices with proper access control enforcement.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for access control related tests
echo "Checking access control tests..."
rg -l "grant_owner|revoke_owner|grant_writer|revoke_writer" -g "test_*.{cairo,rs}"

# Look for access control implementations
ast-grep --pattern 'fn grant_$_($$$) { $$$ }'
ast-grep --pattern 'fn revoke_$_($$$) { $$$ }'

Length of output: 350


Script:

#!/bin/bash
# Let's try a more comprehensive search for access control related code and tests
echo "Searching for access control related files..."
rg -l "grant_owner|revoke_owner|grant_writer|revoke_writer" --type-add 'cairo:*.cairo' --type cairo

echo -e "\nSearching for access control implementations..."
rg -A 5 "fn (grant|revoke)_(owner|writer)" --type cairo

echo -e "\nChecking test files specifically..."
fd "test_.*\.(cairo|rs)" -x rg -l "grant|revoke"

echo -e "\nLooking for access control related structs or traits..."
rg "(struct|trait).*Access" --type cairo

Length of output: 1155


Script:

#!/bin/bash
# Let's examine the implementation details in the identified files
echo "Checking world contract implementation..."
cat crates/dojo/core/src/world/world_contract.cairo

echo -e "\nChecking ACL test implementation..."
cat crates/dojo/core-cairo-test/src/tests/world/acl.cairo

echo -e "\nChecking world interface..."
cat crates/dojo/core/src/world/iworld.cairo

Length of output: 69960


15-43: Verify the concentration of methods under a single target.

Multiple game mechanics methods (spawn, move, set_player_config, etc.) are all using the same target address: 0x7d32611d1b96df37b041f0a285bf340227cebc144d46c2f34cedd81e2fd5239. While this might be intentional, it's worth verifying that this doesn't create a single point of failure.

Let's analyze the usage of this target:

✅ Verification successful

Let's search for more context about how these targets are used in the codebase. This will help us understand if the concentration of methods under a single target is a security concern or an intentional design pattern.


This will help us understand if this target concentration is part of the game's world contract pattern and whether it's a test configuration or production code.


Ohayo sensei! After analyzing the codebase, I can now provide a definitive response about the target concentration:

The target concentration is intentional and secure by design

The shared target 0x7d32611d1b96df37b041f0a285bf340227cebc144d46c2f34cedd81e2fd5239 appears in a test data policy file (bin/sozo/tests/test_data/policies.json) and represents a game system contract that manages player-related actions. This is a standard pattern in the Dojo framework where:

  • The world contract (world_contract.cairo) implements proper permission controls
  • Each target represents a contract with specific capabilities
  • Methods are grouped by their logical domain (player actions in this case)
  • Access control is enforced through the world contract's permission system

The concentration of methods under a single target is not a security concern as it follows the framework's design patterns for organizing game systems.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check references to the shared target address
echo "Analyzing shared target usage..."
rg -A 2 "0x7d32611d1b96df37b041f0a285bf340227cebc144d46c2f34cedd81e2fd5239"

# Look for any security-related files or tests
fd -t f "security|auth|access" tests/

Length of output: 350


Script:

#!/bin/bash
# Let's try a different approach to find references to this target
echo "Searching for target hash references..."
rg -l "7d32611d1b96df37b041f0a285bf340227cebc144d46c2f34cedd81e2fd5239"

# Look for any system contract addresses or target definitions
echo -e "\nChecking for system contracts or target definitions..."
fd -e cairo . -x grep -l "contract_address\|target"

# Check for any policy or permission related files
echo -e "\nLooking for policy files..."
fd -e json -e toml -e yaml . -x grep -l "policy\|permission\|target"

Length of output: 3024


Script:

#!/bin/bash
# Let's examine the content of the policies.json file to understand the context
echo "Checking policies.json content..."
cat bin/sozo/tests/test_data/policies.json

# Let's also check the spawn-and-move example since it appeared in our results
echo -e "\nChecking spawn-and-move actions..."
cat examples/spawn-and-move/src/actions.cairo

# Check for any world contract implementations that might explain the target usage
echo -e "\nChecking world contract implementation..."
cat crates/dojo/core/src/world/world_contract.cairo

Length of output: 63490

crates/dojo/lang/src/attribute_macros/event.rs (2)

20-20: LGTM! Clean import organization, sensei!

The addition of compute_unique_hash import is well-organized and properly scoped within the element module.


114-116: Verify hash computation reliability, sensei!

The hash computation looks good, but let's ensure it's consistent across different scenarios.

✅ Verification successful

Ohayo! Hash computation is reliable and well-documented, sensei!

The compute_unique_hash implementation is solid and consistent across its usage. The is_packed parameter (set to false in events) is properly documented and used to distinguish between packed and unpacked elements in the hash computation, where:

  • Events use false (ZERO)
  • Models can be either packed or unpacked based on the DOJO_PACKED_DERIVE attribute

The hash computation ensures uniqueness by combining:

  1. A packed/unpacked flag
  2. The element name hash
  3. Hashes of all member names and types
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other usages of compute_unique_hash to verify consistency
# Test: Look for other calls to compute_unique_hash with different flag values
rg "compute_unique_hash\(" --type rust

Length of output: 403


Script:

#!/bin/bash
# Let's check the implementation of compute_unique_hash
ast-grep --pattern 'fn compute_unique_hash($$$)'

# Also check where is_packed is used
rg "is_packed" --type rust -A 2

Length of output: 2624


Script:

#!/bin/bash
# Let's check the implementation details of compute_unique_hash function
cat crates/dojo/lang/src/attribute_macros/element.rs

Length of output: 4123

crates/dojo/core/src/meta/introspect.cairo (2)

38-61: ⚠️ Potential issue

Ohayo sensei! The struct comparison implementation needs enhancement.

The current implementation partially addresses the upgrade rules but requires improvements:

  1. Missing layout type verification (a critical requirement from PR objectives)
  2. Field position validation could be more explicit
  3. Lacks documentation explaining the upgrade rules

Consider this enhanced implementation:

 #[generate_trait]
 pub impl StructCompareImpl of StructCompareTrait {
+    /// Validates if a struct is a valid upgrade of another struct.
+    /// 
+    /// # Upgrade Rules
+    /// * Layout type must remain unchanged (Struct/Fixed)
+    /// * Existing fields must maintain their position and type
+    /// * New fields can only be appended at the end
+    /// 
+    /// # Arguments
+    /// * `self` - The new struct version
+    /// * `old` - The previous struct version
+    /// 
+    /// # Returns
+    /// `true` if upgrade rules are satisfied, `false` otherwise
     fn is_an_upgrade_of(self: @Struct, old: @Struct) -> bool {
+        // Early return if basic properties don't match
         if self.name != old.name
             || self.attrs != old.attrs
             || (*self.children).len() < (*old.children).len() {
             return false;
         }

-        let mut i = 0;
-        loop {
-            if i >= (*old.children).len() {
-                break true;
-            }
-            if *old.children[i] != *self.children[i] {
-                break false;
-            }
-            i += 1;
-        }
+        // Verify all existing fields remain unchanged
+        let old_len = (*old.children).len();
+        
+        // Check field-by-field equality for existing fields
+        let mut is_valid = true;
+        let mut i = 0;
+        while i < old_len {
+            if *old.children[i] != *self.children[i] {
+                is_valid = false;
+                break;
+            }
+            i += 1;
+        }
+        
+        is_valid
     }

+    /// Verifies layout type compatibility between structs
+    fn has_compatible_layout(self: @Struct, old: @Struct) -> bool {
+        // TODO: Implement layout type comparison
+        // This should compare the layout types (Struct/Fixed)
+        // from the struct metadata
+        true
+    }
 }

Note: This comment builds upon the previous review while maintaining focus on the critical aspects of the implementation.


38-61: Ohayo sensei! Consider adding test coverage for upgrade scenarios.

The implementation would benefit from comprehensive test coverage to verify all upgrade rules:

  1. Basic compatibility checks
  2. Field addition scenarios
  3. Invalid upgrade attempts
  4. Layout compatibility

Would you like me to help generate test cases for these scenarios?

Let's verify if there are any existing tests:

crates/dojo/lang/src/attribute_macros/model.rs (2)

155-156: LGTM: Clear flag for packed models.

Ohayo! The is_packed flag clearly indicates whether a model uses packed layout, which is essential for the upgradability checks mentioned in the PR objectives.


180-180: LGTM: Hash integration in model generation.

The unique hash is correctly integrated into the model generation template, enabling upgradability validation.

crates/dojo/core-cairo-test/src/tests/world/event.cairo (4)

10-46: LGTM! Well-structured event definitions.

Ohayo, sensei! The event structs are well-organized and follow a consistent pattern with clear naming that indicates their test purposes. Each struct appropriately uses the #[dojo::event] attribute and has caller as a key field.


48-82: Extract common event verification logic.

Ohayo, sensei! The event verification logic in this test could be extracted into a helper function to improve code reusability and maintainability.


169-218: LGTM! Comprehensive upgrade validation tests.

Ohayo, sensei! The test cases thoroughly cover various upgrade scenarios including bad layout type, member removal, and member movement. The error messages are clear and descriptive.


262-287: LGTM! Well-documented edge case tests.

Ohayo, sensei! The edge case tests effectively cover important security scenarios with clear documentation, especially for the malicious contract test case.

crates/dojo/core-cairo-test/src/tests/world/model.cairo (1)

3-6: Verify helper functions implementation

Let's verify the implementation of critical helper functions used in these tests.

✅ Verification successful

Ohayo sensei! Helper functions are properly implemented and safe to use

The helper functions are well-implemented with clear responsibilities:

  • deploy_world() creates a basic test world with the "dojo" namespace
  • deploy_world_for_model_upgrades() sets up a test world with specific model resources for upgrade testing
  • drop_all_events() properly cleans up events using a safe loop pattern

All helper functions follow good practices and are appropriate for their test setup purposes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check implementation of helper functions

# Test: Search for helper function implementations
echo "Searching for helper functions implementation..."
rg -p "fn deploy_world\(" --type cairo
rg -p "fn deploy_world_for_model_upgrades\(" --type cairo
rg -p "fn drop_all_events\(" --type cairo

# Test: Check if helper functions are tested
echo "Checking for tests of helper functions..."
rg -p "#\[test\].*deploy_world" --type cairo
rg -p "#\[test\].*deploy_world_for_model_upgrades" --type cairo
rg -p "#\[test\].*drop_all_events" --type cairo

Length of output: 687


Script:

#!/bin/bash
# Let's try without file type restriction since cairo is not recognized
echo "Searching for helper functions implementation..."
rg -p "fn deploy_world\("
rg -p "fn deploy_world_for_model_upgrades\("
rg -p "fn drop_all_events\("

# Also search for the module where these helpers are defined
echo "Searching for helpers module..."
fd "helpers.cairo"

Length of output: 806


Script:

#!/bin/bash
# Let's check the implementation of these helper functions
echo "Checking deploy_world implementation in helpers.cairo..."
rg -A 10 "fn deploy_world\(\) -> WorldStorage" crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo

echo "Checking deploy_world_for_model_upgrades implementation..."
rg -A 10 "fn deploy_world_for_model_upgrades\(\) -> IWorldDispatcher" crates/dojo/core-cairo-test/src/tests/helpers/model.cairo

echo "Checking drop_all_events implementation..."
rg -A 5 "fn drop_all_events\(address: ContractAddress\)" crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo

Length of output: 2036

crates/dojo/world/src/contracts/abigen/model.rs (3)

Line range hint 627-637: Schema method update in ModelContract looks clean!

The return type change from Ty to Struct maintains consistency with the ModelDef changes.


Line range hint 732-742: Schema method update in ModelContractReader is consistent!

The return type change mirrors the ModelContract implementation, maintaining symmetry between the contract and its reader.


Line range hint 176-217: Ohayo sensei! The ModelDef changes look good!

The removal of the version field and the schema type change from Ty to Struct align well with the PR objectives. This change enforces better type safety by using a more specific type.

Let's verify there are no remaining references to the version field:

✅ Verification successful

Let me verify the remaining references more thoroughly:


Let me try one more verification approach:


Ohayo sensei! The version field removal is properly implemented!

Based on our thorough verification, there are no remaining references to the version field in the ModelDef struct or its implementation. The only version-related mentions in the codebase are unrelated to this model (they're in different contexts like package versions, protocol versions, etc.).

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining version references in model-related files
# Expect: No occurrences of version in model definitions

rg -i "version.*model" 

Length of output: 453


Script:

#!/bin/bash
# Check for version-related code in model.rs and related files
rg -A 3 -B 3 "version" crates/dojo/world/src/contracts/abigen/model.rs

# Check for any version-related structs or types
ast-grep --pattern 'struct $_ {
  $$$
  version: $_,
  $$$
}'

# Check model-related test files
fd "model.*test" --exec rg -l "version"

Length of output: 174


Script:

#!/bin/bash
# Search for any remaining version-related code in the model implementation
ast-grep --pattern 'impl $_ {
  $$$
  version($$$) {
    $$$
  }
  $$$
}'

# Check for version in function parameters or return types
ast-grep --pattern 'fn $_($$$version$$$) -> $_'

# Look for any version-related constants or type definitions
rg -g '*.rs' '(?i)version.*=|type.*version|const.*version'

Length of output: 7915

crates/dojo/core/src/world/world_contract.cairo (4)

42-45: LGTM! Clean import additions for resource management.

The new imports from dojo::meta provide the necessary types and traits for implementing resource upgradability checks.


429-429: Consistent use of IDeployedResourceDispatcher across resource management.

Ohayo sensei! The change from specific dispatcher types to IDeployedResourceDispatcher improves code consistency and maintainability by using a common interface for all deployed resources.

Also applies to: 475-475, 533-533, 579-579


501-504: Consistent integration of upgradability checks.

The upgradability checks are properly integrated into both model and event upgrade paths, ensuring consistent validation across different resource types.

Also applies to: 605-608


1081-1087: Clear and informative error handling.

The error messages provide specific context about the upgrade failure, making it easier to diagnose issues:

  • Layout type mismatch errors include namespace and name
  • Schema compatibility errors provide clear context

Comment on lines +12 to +13
pub mod component;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Ohayo! The event component module needs attention, sensei!

The module is declared in lib.cairo but appears to be missing its implementation. While we found references to event component traits (IDeployedEventImpl, IStoredEventImpl, IEventImpl) in the macro patches, the actual component module and its interfaces are not present in the codebase yet.

  • The component module under event needs to be created with the referenced traits
  • Implementation of the event component interfaces should be added to support the event upgradability checks
🔗 Analysis chain

Ohayo! New event component module looks promising.

The addition of a component module under events aligns well with the PR's objective of implementing upgradability checks for events.

Let's check what this new module contains:


The previous search might have been too restrictive. Let's broaden our search to find the component module and any references to it in the codebase.


The previous search revealed references to event component implementations and traits (IDeployedEventImpl, IStoredEventImpl, IEventImpl). Let's examine the actual component module to understand what these interfaces provide.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the contents of the new event component module
fd "component.cairo" --exec cat {} \; --glob "crates/dojo/core/src/event/**"

Length of output: 317


Script:

#!/bin/bash
# Let's try a broader search to find the component module
echo "Searching for component module in event directory..."
fd . --full-path "*event*component*" --exec cat {}

echo -e "\nSearching for any references to event components..."
rg -g "!target" -g "!*.lock" "event.*component" -A 3

Length of output: 4328


Script:

#!/bin/bash
# Let's check the actual component interfaces in the event module
echo "Checking event component interfaces..."
fd . --type f --glob "**/event/component.cairo" --exec cat {}

echo -e "\nChecking for IDeployedEventImpl trait..."
ast-grep --pattern 'trait IDeployedEventImpl {
  $$$
}'

echo -e "\nChecking for IStoredEventImpl trait..."
ast-grep --pattern 'trait IStoredEventImpl {
  $$$
}'

Length of output: 568

Comment on lines +160 to +162
let unique_hash =
compute_unique_hash(db, &model_type, is_packed, &struct_ast.members(db).elements(db))
.to_string();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Ohayo sensei! After analyzing the compute_unique_hash implementation, I can now provide a definitive response about the hash computation's behavior.

Hash computation is order-dependent and needs attention

The implementation in element.rs shows that the hash is computed by:

  1. Creating an ordered vector of member hashes
  2. Iterating through members in the order they appear
  3. Computing individual hashes for each member's name and type

This means the hash will change if fields are reordered, which could cause unnecessary upgrade checks to fail.

  • crates/dojo/lang/src/attribute_macros/element.rs: Consider sorting members by name before computing the hash to make it order-independent.
🔗 Analysis chain

Verify hash computation's resilience to field reordering.

The compute_unique_hash function is crucial for model upgradability checks. We should ensure it maintains consistency across field reorderings while detecting actual changes.

Let's verify the hash computation behavior:


Let me check the implementation of compute_unique_hash to understand how it handles field ordering.


Let me try a different approach to find the implementation and tests.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if compute_unique_hash is used consistently across the codebase
# and verify its behavior with field reordering

# Search for other usages of compute_unique_hash
rg "compute_unique_hash" -A 3

# Look for test cases that verify hash behavior
rg -l "test.*compute.*hash|test.*model.*upgrade" 

Length of output: 2242


Script:

#!/bin/bash
# Get the implementation of compute_unique_hash
ast-grep --pattern 'pub fn compute_unique_hash($$$) { $$$ }'

# Also check for any model-related test files
fd test.*model.*rs

Length of output: 85


Script:

#!/bin/bash
# Try to find the compute_unique_hash implementation with ripgrep
rg -A 15 "^pub fn compute_unique_hash" 

# Look for model tests in a different way
rg -l "mod tests.*model|test.*model"

# Check if there are any test files that verify hash consistency
rg "test.*hash.*model|test.*model.*hash" -A 5

Length of output: 3895

Comment on lines +103 to +167
#[test]
fn test_upgrade_event_from_event_owner() {
let bob = starknet::contract_address_const::<0xb0b>();

let world = deploy_world_for_event_upgrades();
world.grant_owner(Event::<FooEventMemberAdded>::selector(DOJO_NSH), bob);

starknet::testing::set_account_contract_address(bob);
starknet::testing::set_contract_address(bob);

drop_all_events(world.contract_address);

world.upgrade_event("dojo", e_FooEventMemberAdded::TEST_CLASS_HASH.try_into().unwrap());

let event = starknet::testing::pop_log::<world::Event>(world.contract_address);
assert(event.is_some(), 'no event)');

if let world::Event::EventUpgraded(event) = event.unwrap() {
assert(
event.selector == Event::<FooEventMemberAdded>::selector(DOJO_NSH), 'bad model selector'
);
assert(
event.class_hash == e_FooEventMemberAdded::TEST_CLASS_HASH.try_into().unwrap(),
'bad model class_hash'
);
assert(
event.address != core::num::traits::Zero::<ContractAddress>::zero(),
'bad model prev address'
);
} else {
core::panic_with_felt252('no EventUpgraded event');
}

assert(
world.is_owner(Event::<FooEventMemberAdded>::selector(DOJO_NSH), bob),
'bob is not the owner'
);
}

#[test]
fn test_upgrade_event() {
let world = deploy_world_for_event_upgrades();

drop_all_events(world.contract_address);

world.upgrade_event("dojo", e_FooEventMemberAdded::TEST_CLASS_HASH.try_into().unwrap());

let event = starknet::testing::pop_log::<world::Event>(world.contract_address);
assert(event.is_some(), 'no event)');

if let world::Event::EventUpgraded(event) = event.unwrap() {
assert(
event.selector == Event::<FooEventMemberAdded>::selector(DOJO_NSH), 'bad model selector'
);
assert(
event.class_hash == e_FooEventMemberAdded::TEST_CLASS_HASH.try_into().unwrap(),
'bad model class_hash'
);
assert(
event.address != core::num::traits::Zero::<ContractAddress>::zero(), 'bad model address'
);
} else {
core::panic_with_felt252('no EventUpgraded event');
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract common upgrade verification logic.

Ohayo, sensei! The upgrade verification logic is duplicated between test_upgrade_event_from_event_owner and test_upgrade_event. Consider extracting it into a helper function.

Copy link

codecov bot commented Nov 5, 2024

Codecov Report

Attention: Patch coverage is 4.65116% with 41 lines in your changes missing coverage. Please review.

Project coverage is 56.91%. Comparing base (cf1d99f) to head (7dd5295).
Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
crates/dojo/lang/src/attribute_macros/element.rs 0.00% 20 Missing ⚠️
crates/dojo/lang/src/attribute_macros/model.rs 0.00% 7 Missing ⚠️
crates/dojo/world/src/contracts/abigen/model.rs 14.28% 6 Missing ⚠️
crates/dojo/lang/src/attribute_macros/event.rs 0.00% 5 Missing ⚠️
xtask/generate-test-db/src/main.rs 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2626      +/-   ##
==========================================
+ Coverage   56.83%   56.91%   +0.08%     
==========================================
  Files         397      397              
  Lines       49535    49451      -84     
==========================================
- Hits        28151    28143       -8     
+ Misses      21384    21308      -76     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Collaborator

@glihm glihm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing, thanks @remybar! 🔥

@glihm glihm merged commit 8b2d976 into dojoengine:main Nov 5, 2024
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants