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(lang): add the ability to get a WorldStorage from a namespace hash #2686

Open
wants to merge 9 commits into
base: feat/poseidon-macro
Choose a base branch
from

Conversation

bengineer42
Copy link
Contributor

@bengineer42 bengineer42 commented Nov 14, 2024

Description

Added the ability to get a WorldStorage from a namespace hash

Related issue

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

Release Notes

  • New Features

    • Introduced poseidon_hash_string module for enhanced testing capabilities related to the Poseidon hash function.
    • Added new methods for creating WorldStorage instances from a hash.
    • Integrated PoseidonHashStringMacro into the Dojo plugin suite for improved code generation.
    • Added a method to retrieve world storage using a hashed namespace.
  • Bug Fixes

    • Added unit tests for various scenarios of the poseidon_hash_string function to ensure correctness.
  • Documentation

    • Updated test suite to include new tests for poseidon_hash_string functionality.
    • Added a test for the world_default_from_hash method to validate its functionality.

Copy link

coderabbitai bot commented Nov 14, 2024

Walkthrough

Ohayo, sensei! This pull request introduces several enhancements to the Dojo codebase, primarily focusing on the Poseidon hash functionality. A new module for testing the Poseidon hash string is added, along with multiple unit tests to validate its behavior. Additionally, new methods are introduced in the WorldStorage and InternalUtils implementations to facilitate object creation from a hash. The changes also include updates to inline macros and the testing framework, expanding the capabilities of the Dojo environment without altering existing functionalities.

Changes

File Path Change Summary
crates/dojo/core-cairo-test/src/lib.cairo Added new module poseidon_hash_string in expanded module under tests.
crates/dojo/core-cairo-test/src/tests/expanded/poseidon_hash_string.cairo Introduced unit tests for poseidon_hash_string function, validating various input scenarios.
crates/dojo/core/src/world/storage.cairo Added method new_from_hash to WorldStorageInternalImpl, allowing creation of WorldStorage from a hash.
crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo Added method world_from_hash to $name$InternalImpl, utilizing new_from_hash for creating WorldStorage.
crates/dojo/lang/src/cairo_plugin.rs Introduced PoseidonHashStringMacro to dojo_plugin_suite, expanding macro capabilities.
crates/dojo/lang/src/inline_macros/mod.rs Added new module poseidon_hash_string and exported PoseidonHashStringMacro.
crates/dojo/lang/src/inline_macros/poseidon_hash_string.rs Introduced PoseidonHashStringMacro struct and its methods for generating code based on inline macro expressions.
crates/dojo/lang/src/semantics/tests.rs Added new entry for poseidon_hash_string in the test_file_test! macro for dojo_semantics.
examples/spawn-and-move/src/actions.cairo Added method world_default_from_hash in InternalImpl for retrieving world storage using a hash.

Possibly related PRs

Suggested reviewers

  • glihm

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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: 4

🧹 Outside diff range and nitpick comments (6)
crates/dojo/core-cairo-test/src/lib.cairo (1)

41-41: Ohayo sensei! The module addition looks good, but could use some documentation.

The placement and naming of the new poseidon_hash_string module is appropriate. Consider adding a brief doc comment explaining its purpose and relationship to the WorldStorage functionality.

Add a doc comment before the module declaration:

+        /// Tests for Poseidon hash string functionality used in WorldStorage namespace operations
         mod poseidon_hash_string;
crates/dojo/lang/src/semantics/tests.rs (1)

25-26: Consider grouping related hash function tests together.

Since this test is related to Poseidon hash functionality, consider organizing similar hash-related tests under a common prefix or in a dedicated test module for better maintainability.

Consider restructuring the test cases like this:

    test_file_test!(
        dojo_semantics,
        "src/plugin/semantics/test_data",
        {
            get: "get",
            set: "set",
            selector_from_tag: "selector_from_tag",
            get_models_test_class_hashes: "get_models_test_class_hashes",
            spawn_test_world: "spawn_test_world",
-           poseidon_hash_string: "poseidon_hash_string",
+           // Hash-related tests
+           hash_poseidon_string: "poseidon_hash_string",
+           // Add other hash-related tests here
        },
        test_semantics
    );
crates/dojo/core-cairo-test/src/tests/expanded/poseidon_hash_string.cairo (1)

23-41: Good boundary testing, but consider additional cases!

The tests for 31 characters and longer strings are valuable. Consider adding tests for:

  • Maximum allowed string length
  • UTF-8 characters
  • Special characters
crates/dojo/lang/src/cairo_plugin.rs (1)

28-29: Consider consolidating the plugin registrations, sensei!

The current implementation has two separate chain calls for adding inline macro plugins. We can make this more elegant by chaining them together.

Here's a suggested improvement:

-    suite.add_plugin::<BuiltinDojoPlugin>().add_inline_macro_plugin::<SelectorFromTagMacro>();
-    suite.add_plugin::<BuiltinDojoPlugin>().add_inline_macro_plugin::<PoseidonHashStringMacro>();
+    suite
+        .add_plugin::<BuiltinDojoPlugin>()
+        .add_inline_macro_plugin::<SelectorFromTagMacro>()
+        .add_inline_macro_plugin::<PoseidonHashStringMacro>();
examples/spawn-and-move/src/actions.cairo (1)

314-324: The test coverage looks good, sensei! Consider expanding it.

While the current test effectively verifies the basic functionality, consider adding test cases for:

  • Invalid namespace hashes
  • Empty namespace
  • Special characters in namespace

Here's a suggested expansion of the test cases:

#[test]
#[available_gas(30000000)]
#[should_panic(expected: ('invalid namespace hash',))]
fn test_world_from_hash_invalid() {
    let ndef = namespace_def();
    let mut world = spawn_test_world([ndef].span());
    world.sync_perms_and_inits(contract_defs());
    let invalid_hash: felt252 = 0;
    world.dispatcher.new_from_hash(invalid_hash);
}
crates/dojo/core/src/world/storage.cairo (1)

35-37: Ohayo! The implementation looks clean, but needs documentation, sensei!

The new method provides a direct way to create WorldStorage from a hash, which is good! However, we should add documentation to explain its purpose and usage.

Consider adding documentation like this:

+    /// Creates a new WorldStorage instance from an existing namespace hash.
+    /// This is useful when you already have the hash and want to avoid recomputing it.
+    /// @param self - The IWorldDispatcher reference
+    /// @param namespace_hash - The precomputed namespace hash
+    /// @return WorldStorage instance initialized with the provided dispatcher and hash
     fn new_from_hash(self: @IWorldDispatcher, namespace_hash: felt252) -> WorldStorage {
         WorldStorage { dispatcher: *self, namespace_hash }
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4671d9c and a897f4c.

⛔ Files ignored due to path filters (3)
  • crates/dojo/core-cairo-test/Scarb.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 (9)
  • crates/dojo/core-cairo-test/src/lib.cairo (1 hunks)
  • crates/dojo/core-cairo-test/src/tests/expanded/poseidon_hash_string.cairo (1 hunks)
  • crates/dojo/core/src/world/storage.cairo (1 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (1 hunks)
  • crates/dojo/lang/src/cairo_plugin.rs (2 hunks)
  • crates/dojo/lang/src/inline_macros/mod.rs (2 hunks)
  • crates/dojo/lang/src/inline_macros/poseidon_hash_string.rs (1 hunks)
  • crates/dojo/lang/src/semantics/tests.rs (1 hunks)
  • examples/spawn-and-move/src/actions.cairo (2 hunks)
🔇 Additional comments (14)
crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (1)

33-35: Ohayo! Implementation looks clean, but needs documentation.

The new method follows good patterns and integrates well with the existing world provider functionality.

Consider adding documentation to explain:

  • When to use world_from_hash vs world
  • Expected format/constraints of the namespace_hash parameter
+       /// Gets a WorldStorage instance from a namespace hash
+       /// @param namespace_hash The felt252 hash of the namespace
+       /// @return WorldStorage instance for the given namespace
        fn world_from_hash(self: @ContractState, namespace_hash: felt252) -> dojo::world::storage::WorldStorage {

Let's verify the WorldStorageTrait::new_from_hash implementation exists:

✅ Verification successful

The previous ast-grep pattern might have been too specific. Let's try these broader searches to find the implementation and trait definition.


Ohayo! The implementation is verified and correct, sensei!

The search results confirm that new_from_hash is properly implemented in WorldStorageTrait at crates/dojo/core/src/world/storage.cairo. The implementation matches exactly what's being used in the contract:

fn new_from_hash(self: @IWorldDispatcher, namespace_hash: felt252) -> WorldStorage {
    WorldStorage { dispatcher: *self, namespace_hash }
}

The method is a simple constructor that takes a namespace hash directly instead of computing it from a ByteArray, which aligns perfectly with the contract's usage.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for new_from_hash implementation in WorldStorageTrait
ast-grep --pattern 'impl $_ of WorldStorageTrait {
  $$$
  fn new_from_hash($_) {
    $$$
  }
  $$$
}'

Length of output: 104


Script:

#!/bin/bash
# Let's try a broader search for WorldStorageTrait and new_from_hash
rg "WorldStorageTrait" -A 5 -B 5

# Also search specifically for new_from_hash function
rg "fn new_from_hash" -A 5 -B 5

# And let's check trait definition
rg "trait WorldStorageTrait" -A 10

Length of output: 7877

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

41-41: Verify the implementation of the new test module.

Let's ensure the test module is properly implemented with comprehensive test cases.

✅ Verification successful

Let me gather more information about the test module implementation.


Test module implementation is well-covered, sensei! ✨

The poseidon_hash_string test module has comprehensive test coverage with 6 test cases:

  • Basic string hashing test
  • Empty string test
  • 31-character string test
  • Long string test (>31 chars)
  • Variable input test
  • Inequality test

Each test properly verifies the hash computation by comparing against the expected result using the poseidon_hash_span function.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of the poseidon_hash_string test module

# Check the test module implementation
rg -A 10 "mod poseidon_hash_string" 

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

Length of output: 1864


Script:

#!/bin/bash
# Check for the actual implementation of poseidon_hash_string test module
fd poseidon_hash_string.cairo --exec cat {}

# Look for any test functions in files containing poseidon_hash_string
rg -l "poseidon_hash_string" | xargs rg "fn test_" -A 5

Length of output: 8070

crates/dojo/core-cairo-test/src/tests/expanded/poseidon_hash_string.cairo (3)

1-3: Ohayo sensei! The imports look good!

The necessary poseidon hash functionality is properly imported.


4-12: Clean and focused test implementation!

The test effectively validates the basic hash functionality for a simple string.


13-21: Excellent edge case coverage, sensei!

Testing empty string input is crucial for robust hash functionality.

crates/dojo/lang/src/inline_macros/mod.rs (2)

15-15: Ohayo sensei! The module declaration looks good!

The new poseidon_hash_string module declaration follows the established pattern and maintains proper alphabetical ordering.


25-25: The export declaration is well-structured, sensei!

The PoseidonHashStringMacro export follows the established pattern and maintains proper alphabetical ordering.

Let's verify the macro implementation:

✅ Verification successful

The macro implementation is complete and well-structured, sensei!

The PoseidonHashStringMacro correctly:

  • Implements the required InlineMacroExprPlugin trait
  • Has a proper generate_code method with expected signature
  • Includes input validation and error handling
  • Generates appropriate code using PatchBuilder
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the PoseidonHashStringMacro implementation

# Check if the macro implements required traits
ast-grep --pattern 'impl InlineMacroExprPlugin for PoseidonHashStringMacro'

# Check if the macro has the generate_code method
ast-grep --pattern 'fn generate_code(&self, $_, $_, $_) -> InlinePluginResult'

Length of output: 4479

crates/dojo/lang/src/cairo_plugin.rs (1)

15-15: Ohayo! Clean import addition, sensei!

The import follows the existing pattern and maintains consistency with the codebase.

examples/spawn-and-move/src/actions.cairo (2)

216-216: Import looks good, sensei!

The WorldStorageTrait import is appropriately placed and necessary for the new hash-based world storage functionality.


207-209: Ohayo sensei! The implementation looks solid!

The new world_default_from_hash method provides a clean way to access world storage using a hashed namespace, maintaining consistency with the existing pattern while adding new functionality.

Let's verify that the hash is used consistently across the codebase:

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

35-37: Consider validating the namespace_hash parameter

The method accepts any felt252 value as namespace_hash without validation.

Let's check if there are any validation patterns in existing code:

✅ Verification successful

Let me check if there's any validation being done for namespace_hash in the world contract:


Let me check one more thing about namespace registration:


Ohayo sensei! After reviewing the codebase, I can now provide a clear response about the namespace_hash validation:

The namespace_hash validation is already handled at registration time

The WorldStorage's new_from_hash method is safe to use as-is because:

  • Namespaces must be registered first via register_namespace
  • Registration validates the namespace name format using is_name_valid
  • Registration prevents duplicate registrations
  • The World contract maintains the mapping of valid namespace_hashes

The hash parameter in new_from_hash is meant to be used with pre-validated namespace hashes that were obtained through the proper registration flow.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Look for namespace_hash validation patterns
# Expected: Find examples of hash validation

rg -B 3 -A 3 "namespace_hash.*felt252" "crates/dojo"

Length of output: 31859


Script:

#!/bin/bash
# Look for namespace validation in world contract implementation
ast-grep --pattern 'fn is_namespace_registered(self: @ContractState, namespace_hash: felt252) -> bool {
  $$$
}'

# Also check for any other validation patterns
rg -B 3 -A 3 "namespace.*valid" "crates/dojo"

Length of output: 2479


Script:

#!/bin/bash
# Look for namespace registration implementation
rg -B 5 -A 5 "register_namespace" "crates/dojo"

Length of output: 16364


35-37: Verify test coverage for the new method

While the implementation is straightforward, we should ensure it's properly tested.

Let's check for test coverage:

✅ Verification successful

The previous search failed because we were looking in a specific directory that didn't exist. Let's broaden our search to find where tests might be located and any usage of the method.


Let's check the test directory that seems most relevant to core functionality and also look for inline tests in the implementation file itself, sensei!


Ohayo sensei! Let's take a look at the actual file content and check for any test files in the world module directory that might have been missed by our previous searches!


Test coverage exists in test configuration

Ohayo sensei! Looking at the code, I can see that the new_from_hash method is actually covered by the test configuration. The file includes a #[cfg(target: "test")] section with comprehensive test implementations for EventStorageTest, ModelStorageTest, and ModelValueStorageTest traits that all rely on the WorldStorage struct and its initialization methods.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Look for test cases covering new_from_hash
# Expected: Find test files containing new_from_hash usage

rg -l "new_from_hash" "crates/dojo/core/src/world/tests"

Length of output: 127


Script:

#!/bin/bash
# Let's first find where the tests might be located
fd "test" --type d

# Then search for any test files that might reference new_from_hash
rg -l "new_from_hash" --type rust

Length of output: 921


Script:

#!/bin/bash
# Let's look in the core-cairo-test directory since it seems most relevant
rg "new_from_hash" crates/dojo/core-cairo-test/ -A 5 -B 5

# Also check the actual implementation file for any existing test modules
rg "mod test" crates/dojo/core/src/world/storage.cairo

Length of output: 114


Script:

#!/bin/bash
# Let's check the content of the storage.cairo file to see its structure
cat crates/dojo/core/src/world/storage.cairo

# Also look for any test files in the world module directory
fd "test" crates/dojo/core/src/world/

Length of output: 18121

crates/dojo/lang/src/inline_macros/poseidon_hash_string.rs (2)

36-36: ⚠️ Potential issue

Ohayo, sensei! Escape double quotes in the error message.

In line 36, the double quotes inside the string need to be escaped to prevent a compile-time error.

Apply this diff to fix the issue:

- message: "Invalid arguments. Expected \"poseidon_hash_string!(\"tag\")\"".to_string(),
+ message: "Invalid arguments. Expected \"poseidon_hash_string!(\\\"tag\\\")\"".to_string(),

Likely invalid or redundant comment.


48-48: Ohayo, sensei! Verify the format specifier in {:#64x}.

The format specifier {:#64x} might not produce a fixed-width hexadecimal representation as intended.

Run the following script to test the formatting:

Ensure the output aligns with the expected format of a 64-character hexadecimal string.

✅ Verification successful

Ohayo, sensei! The format specifier {:#64x} is correct and consistent with codebase usage.

Looking at the codebase, there are numerous examples of using similar format specifiers for hexadecimal formatting of selectors and other values. The # flag ensures the 0x prefix, and 64 width ensures consistent padding. This is particularly evident in:

  • crates/dojo/lang/src/inline_macros/poseidon_hash_string.rs: Uses {:#64x} for selector formatting
  • crates/dojo/lang/src/inline_macros/selector_from_tag.rs: Uses the same format specifier
  • Other parts of the codebase use similar patterns like {:#066x} for consistent hex formatting
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the output of the format specifier.

# Test: Check how the selector is formatted.
echo "Testing format specifier output:"
rustc -e 'let selector: u128 = 0x123456789ABCDEF; println!("{:#64x}", selector);'

Length of output: 231


Script:

#!/bin/bash
# Let's examine the actual code usage and context
rg -A 5 -B 5 "format!\(.*#.*x.*selector" --type rust

# Also check other similar format usages in the codebase
rg -A 2 -B 2 "format!\(.*#.*x" --type rust

# Look for tests or examples that might show the expected format
rg -A 5 -B 5 "selector.*format.*x" --type rust

Length of output: 118736

Comment on lines +25 to +26

poseidon_hash_string: "poseidon_hash_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! Missing test file for poseidon_hash_string

The test case poseidon_hash_string is added to the test macro but the corresponding test file is missing in crates/dojo/lang/src/semantics/test_data/. All other test files listed in the macro have their corresponding files present in the test directory.

  • Missing test file: crates/dojo/lang/src/semantics/test_data/poseidon_hash_string
  • Other test files like get, set, selector_from_tag etc. are properly present
🔗 Analysis chain

Ohayo sensei! Verify the test file existence and structure.

The new test case poseidon_hash_string has been added to the test suite, but we should verify that the corresponding test file exists at the expected location.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and structure of the poseidon_hash_string test file

# Check if the test file exists
fd "poseidon_hash_string" "src/plugin/semantics/test_data"

# If found, examine its content for proper test structure
if [ $? -eq 0 ]; then
  rg -A 10 "test|assert" "src/plugin/semantics/test_data/poseidon_hash_string.cairo"
fi

Length of output: 192


Script:

#!/bin/bash
# Let's first find the correct test data directory structure
fd -t d "test_data"

# Then search for the poseidon test file in the correct location
fd "poseidon_hash_string" .

# Let's also check the test file structure in semantics/tests.rs to understand the pattern
rg -A 5 "test_file_test!" "crates/dojo/lang/src/semantics/tests.rs"

Length of output: 586


Script:

#!/bin/bash
# Let's check if the test file exists in the correct location
fd "poseidon_hash_string" "crates/dojo/lang/src/semantics/test_data"

# Let's also check the content of the test macro to understand the full context
cat "crates/dojo/lang/src/semantics/tests.rs"

# And examine the actual test files that exist
ls -la "crates/dojo/lang/src/semantics/test_data" 2>/dev/null || echo "Directory not found"

Length of output: 2474

Comment on lines +53 to +60
fn test_poseidon_hash_string_ne() {
let bytes: ByteArray = "foo";
let hash = poseidon_hash_string!("bar");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_ne!(computed, 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

Critical: Missing #[test] attribute and consider additional negative cases!

  1. The test won't be executed without the test attribute.
  2. Consider adding more negative tests:
    • Similar strings (e.g., "foo" vs "fooo")
    • Case variations (e.g., "foo" vs "FOO")
    • Different string lengths with same content

Apply this diff to fix the attribute:

+#[test]
 fn test_poseidon_hash_string_ne() {
📝 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 test_poseidon_hash_string_ne() {
let bytes: ByteArray = "foo";
let hash = poseidon_hash_string!("bar");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_ne!(computed, hash);
}
#[test]
fn test_poseidon_hash_string_ne() {
let bytes: ByteArray = "foo";
let hash = poseidon_hash_string!("bar");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_ne!(computed, hash);
}

Comment on lines 43 to 51
fn test_poseidon_hash_string_var() {
let bytes: ByteArray = "foo";
let bytes2: ByteArray = "foo";
let hash = poseidon_hash_string!(bytes);
let mut array = array![];
bytes2.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_eq!(computed, 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

Critical: Missing #[test] attribute!

The test won't be executed without the test attribute.

Apply this diff to fix:

+#[test]
 fn test_poseidon_hash_string_var() {
📝 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 test_poseidon_hash_string_var() {
let bytes: ByteArray = "foo";
let bytes2: ByteArray = "foo";
let hash = poseidon_hash_string!(bytes);
let mut array = array![];
bytes2.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_eq!(computed, hash);
}
#[test]
fn test_poseidon_hash_string_var() {
let bytes: ByteArray = "foo";
let bytes2: ByteArray = "foo";
let hash = poseidon_hash_string!(bytes);
let mut array = array![];
bytes2.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_eq!(computed, hash);
}

};
}

let tag = &args[0].as_syntax_node().get_text(db).replace('\"', "");
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ohayo, sensei! Properly handle string literals for the tag.

Using replace('\"', "") may not correctly handle all cases, especially if the tag contains escaped quotes or special characters.

Consider parsing the string literal to accurately extract the tag value, handling any escaped characters appropriately.

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 (4)
crates/dojo/core-cairo-test/src/tests/expanded/poseidon_hash_string.cairo (2)

4-12: Add documentation and use const for test data

The test logic is solid, but consider these improvements for better maintainability:

+/// Tests that poseidon_hash_string! macro produces the same result as manual serialization
+/// and hashing for a basic string.
+const TEST_STRING: &str = "foo";
 #[test]
 fn test_poseidon_hash_string() {
-    let bytes: ByteArray = "foo";
-    let hash = poseidon_hash_string!("foo");
+    let bytes: ByteArray = TEST_STRING;
+    let hash = poseidon_hash_string!(TEST_STRING);
     let mut array = array![];
     bytes.serialize(ref array);
     let computed = poseidon_hash_span(array.span());
     assert_eq!(computed, hash);
 }

13-21: Add documentation for edge case test

Good edge case testing! Consider adding explicit documentation:

+/// Tests the hash computation for an empty string, which is an important edge case
+/// that could potentially cause issues in string handling.
 #[test]
 fn test_poseidon_hash_string_empty() {
examples/spawn-and-move/src/actions.cairo (2)

207-209: Ohayo sensei! Consider documenting the relationship with world_default

The implementation looks correct, but it would be helpful to document how this method relates to world_default and when to use each approach.

Add a doc comment explaining the purpose:

+        /// Alternative to `world_default` that uses the hashed namespace directly.
+        /// This is equivalent to `world_default` but skips the string-to-hash conversion.
         fn world_default_from_hash(self: @ContractState) -> dojo::world::WorldStorage {

314-324: Ohayo sensei! The test coverage looks solid

The test effectively verifies that the world storage created from a hash matches the expected properties. However, we could enhance it by testing the equivalence with world_default.

Consider adding this assertion to verify equivalence:

         assert_eq!(storage.namespace_hash, world.namespace_hash);
         assert_eq!(storage.dispatcher.contract_address, world.dispatcher.contract_address);
+        // Verify equivalence with world_default
+        let (actions_system_addr, _) = world.dns(@"actions").unwrap();
+        let actions_system = IActionsDispatcher { contract_address: actions_system_addr };
+        let default_storage = actions_system.world_default();
+        assert_eq!(storage.namespace_hash, default_storage.namespace_hash);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a897f4c and 21a19b7.

📒 Files selected for processing (4)
  • crates/dojo/core-cairo-test/src/tests/expanded/poseidon_hash_string.cairo (1 hunks)
  • crates/dojo/core/src/world/storage.cairo (1 hunks)
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo (1 hunks)
  • examples/spawn-and-move/src/actions.cairo (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/dojo/core/src/world/storage.cairo
  • crates/dojo/lang/src/attribute_macros/patches/contract.patch.cairo
🔇 Additional comments (2)
crates/dojo/core-cairo-test/src/tests/expanded/poseidon_hash_string.cairo (2)

44-51: ⚠️ Potential issue

Critical: Fix incorrect test data in inequality check

Ohayo sensei! There's a critical issue in this test. The ByteArray is created with "foo" but compared against the hash of "bar". This makes the test meaningless as it's comparing different things.

Fix the test data consistency:

 #[test]
 fn test_poseidon_hash_string_ne() {
-    let bytes: ByteArray = "foo";
+    let bytes: ByteArray = "bar";
     let hash = poseidon_hash_string!("bar");
     let mut array = array![];
     bytes.serialize(ref array);
     let computed = poseidon_hash_span(array.span());
     assert_ne!(computed, hash);
 }

Additionally, consider adding more inequality test cases:

  • Similar strings (e.g., "foo" vs "fooo")
  • Case variations (e.g., "foo" vs "FOO")

Likely invalid or redundant comment.


23-41: Clarify the significance of 31 characters and add boundary tests

The test cases for 31 characters and longer strings are good, but:

  1. Why is 31 characters significant? Consider adding a comment explaining this.
  2. Consider adding more boundary tests:
    • 30 characters (just below 31)
    • 32 characters (just above 31)
    • Maximum allowed length

Let's check if there are any length constraints in the implementation:

Comment on lines +35 to +38
fn new_from_hash(world: IWorldDispatcher, namespace_hash: felt252) -> WorldStorage {
WorldStorage { dispatcher: world, namespace_hash }
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

If we add this to save the Poseidon hashes on the serialized byte array, we should also add one for the dns. Cairo doesn't support function overloading.

Since computing the dojo selector requires three steps:

  1. Hashing the namespace (saved by the new_from_hash).
  2. Hashing the name.
  3. Hashing them together.
    Having something like:
let (ca, ch) = world.dns_from_hash/selector(selector_from_tag!("eternum-map_system")).unwrap();

Will be the most efficient way to query a resource, with no Poseidon hash at all.

pub struct PoseidonHashStringMacro;

impl NamedPlugin for PoseidonHashStringMacro {
const NAME: &'static str = "poseidon_hash_string";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const NAME: &'static str = "poseidon_hash_string";
const NAME: &'static str = "poseidon_hash_string";

Wondering if poseidon_hash_bytearray would not be more consistent with the dojo utils functions already using bytearray instead of string.

fn test_world_from_hash() {
let ndef = namespace_def();
let mut world = spawn_test_world([ndef].span());
world.sync_perms_and_inits(contract_defs());
Copy link
Collaborator

Choose a reason for hiding this comment

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

May be removed as not used.

Suggested change
world.sync_perms_and_inits(contract_defs());

@glihm glihm changed the title Added the ability to get a WorldStorage from a namespace hash feat(lang): add the ability to get a WorldStorage from a namespace hash Nov 14, 2024
@glihm
Copy link
Collaborator

glihm commented Nov 21, 2024

@bengineer42 let me know if you don't have bandwidth I'll wrap it up. 🫡

@bengineer42
Copy link
Contributor Author

Sorry didn't see you had reviewed will look into it today

@bengineer42 bengineer42 changed the base branch from main to feat/poseidon-macro November 21, 2024 16:30
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 (2)
crates/dojo/core/src/world/storage.cairo (2)

36-39: Consider adding hash validation.

The new constructor looks clean, sensei! However, consider adding validation for the namespace_hash parameter to ensure it's a valid Poseidon hash value.

 fn new_from_hash(world: IWorldDispatcher, namespace_hash: felt252) -> WorldStorage {
+    // Validate that namespace_hash is a valid Poseidon hash
+    assert(namespace_hash != 0, 'Invalid namespace hash');
     WorldStorage { dispatcher: world, namespace_hash }
 }

49-55: Consider caching the selector computation.

The selector computation in dns_from_hash could be cached to optimize repeated lookups for the same namespace and contract name combination.

 fn dns_from_hash(
     self: @WorldStorage, contract_name_hash: felt252
 ) -> Option<(ContractAddress, ClassHash)> {
+    // Consider adding a cached_selector field to WorldStorage
+    // and checking/updating it here
     Self::dns_from_selector(
         self, poseidon_hash_span([*self.namespace_hash, contract_name_hash].span())
     )
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3b772ce and 8a1f9d9.

📒 Files selected for processing (1)
  • crates/dojo/core/src/world/storage.cairo (2 hunks)
🔇 Additional comments (3)
crates/dojo/core/src/world/storage.cairo (3)

4-4: LGTM! Import addition is well-placed.

Ohayo! The addition of poseidon_hash_span import aligns perfectly with the new hash-based functionality.


44-47: LGTM! Clean refactor of DNS lookup.

The modification to use dns_from_hash improves code reusability while maintaining functionality.


57-65: LGTM! Error handling is consistent.

The implementation of dns_from_selector follows the codebase's error handling patterns with proper use of Option type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants