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(dojo-lang): add bytearray_hash macro #2946

Merged
merged 8 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions Cargo.lock

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

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ rpassword = "7.2.0"
rstest = "0.18.2"
rstest_reuse = "0.6.0"
salsa = "0.16.1"
scarb = { git = "https://github.com/dojoengine/scarb", rev = "b5ab351aa9b52dcf27a397021d84a423afd016dc" }
scarb-metadata = { git = "https://github.com/dojoengine/scarb", rev = "b5ab351aa9b52dcf27a397021d84a423afd016dc" }
scarb-ui = { git = "https://github.com/dojoengine/scarb", rev = "b5ab351aa9b52dcf27a397021d84a423afd016dc" }
scarb = { git = "https://github.com/dojoengine/scarb", rev = "a3b3c7fae12aecd3ce1502b1a651fced6be546df" }
scarb-metadata = { git = "https://github.com/dojoengine/scarb", rev = "a3b3c7fae12aecd3ce1502b1a651fced6be546df" }
scarb-ui = { git = "https://github.com/dojoengine/scarb", rev = "a3b3c7fae12aecd3ce1502b1a651fced6be546df" }
semver = "1.0.5"
serde = { version = "1.0", features = [ "derive" ] }
serde_json = { version = "1.0", features = [ "arbitrary_precision" ] }
Expand Down
1 change: 1 addition & 0 deletions crates/dojo/core-cairo-test/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod tests {

mod expanded {
pub(crate) mod selector_attack;
pub(crate) mod bytearray_hash;
}

mod helpers {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use core::poseidon::poseidon_hash_span;

#[test]
fn test_bytearray_hash() {
let bytes: ByteArray = "foo";
let hash = bytearray_hash!("foo");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_eq!(computed, hash);
}

#[test]
fn test_bytearray_hash_empty() {
let bytes: ByteArray = "";
let hash = bytearray_hash!("");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_eq!(computed, hash);
}

#[test]
fn test_bytearray_hash_31() {
let bytes: ByteArray = "0123456789012345678901234567890";
let hash = bytearray_hash!("0123456789012345678901234567890");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_eq!(computed, hash);
}

#[test]
fn test_bytearray_hash_long() {
let bytes: ByteArray = "0123456789012345678901234567890foo";
let hash = bytearray_hash!("0123456789012345678901234567890foo");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_eq!(computed, hash);
}

#[test]
fn test_bytearray_hash_ne() {
let bytes: ByteArray = "foo";
let hash = bytearray_hash!("bar");
let mut array = array![];
bytes.serialize(ref array);
let computed = poseidon_hash_span(array.span());
assert_ne!(computed, hash);
}
4 changes: 3 additions & 1 deletion crates/dojo/core/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ pub mod storage {

pub mod utils {
pub mod hash;
pub use hash::{bytearray_hash, selector_from_names, selector_from_namespace_and_name};
pub use hash::{
bytearray_hash, selector_from_hashes, selector_from_names, selector_from_namespace_and_name,
};

pub mod key;
pub use key::{entity_id_from_serialized_keys, combine_key, entity_id_from_keys};
Expand Down
5 changes: 5 additions & 0 deletions crates/dojo/core/src/utils/hash.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ pub fn selector_from_names(namespace: @ByteArray, name: @ByteArray) -> felt252 {
pub fn selector_from_namespace_and_name(namespace_hash: felt252, name: @ByteArray) -> felt252 {
poseidon_hash_span([namespace_hash, bytearray_hash(name)].span())
}

/// Computes the selector from two hashes.
pub fn selector_from_hashes(namespace_hash: felt252, name_hash: felt252) -> felt252 {
poseidon_hash_span([namespace_hash, name_hash].span())
}
23 changes: 19 additions & 4 deletions crates/dojo/core/src/world/storage.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,30 @@ pub impl WorldStorageInternalImpl of WorldStorageTrait {
WorldStorage { dispatcher: world, namespace_hash }
}

fn new_from_hash(world: IWorldDispatcher, namespace_hash: felt252) -> WorldStorage {
WorldStorage { dispatcher: world, namespace_hash }
}

fn set_namespace(ref self: WorldStorage, namespace: @ByteArray) {
self.namespace_hash = dojo::utils::bytearray_hash(namespace);
}

fn dns(self: @WorldStorage, contract_name: @ByteArray) -> Option<(ContractAddress, ClassHash)> {
match (*self.dispatcher)
.resource(
dojo::utils::selector_from_namespace_and_name(*self.namespace_hash, contract_name),
) {
Self::dns_from_hash(self, dojo::utils::bytearray_hash(contract_name))
}

fn dns_from_hash(
self: @WorldStorage, contract_name_hash: felt252,
) -> Option<(ContractAddress, ClassHash)> {
Self::dns_from_selector(
self, dojo::utils::selector_from_hashes(*self.namespace_hash, contract_name_hash),
)
}

fn dns_from_selector(
self: @WorldStorage, selector: felt252,
) -> Option<(ContractAddress, ClassHash)> {
match (*self.dispatcher).resource(selector) {
Resource::Contract((
contract_address, _,
)) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub mod $name$ {
fn world(self: @ContractState, namespace: @ByteArray) -> dojo::world::storage::WorldStorage {
dojo::world::WorldStorageTrait::new(self.world_provider.world_dispatcher(), namespace)
}

fn world_ns_hash(self: @ContractState, namespace_hash: felt252) -> dojo::world::storage::WorldStorage {
dojo::world::WorldStorageTrait::new_from_hash(self.world_provider.world_dispatcher(), namespace_hash)
}
}

$body$
Expand Down
7 changes: 5 additions & 2 deletions crates/dojo/lang/src/cairo_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::attribute_macros::{
DojoContract, DojoEvent, DojoModel, DOJO_CONTRACT_ATTR, DOJO_EVENT_ATTR, DOJO_MODEL_ATTR,
};
use super::derive_macros::{dojo_derive_all, DOJO_INTROSPECT_DERIVE, DOJO_PACKED_DERIVE};
use super::inline_macros::SelectorFromTagMacro;
use super::inline_macros::{BytearrayHashMacro, SelectorFromTagMacro};

// #[cfg(test)]
// #[path = "plugin_test.rs"]
Expand All @@ -25,7 +25,10 @@ pub struct BuiltinDojoPlugin;
pub fn dojo_plugin_suite() -> PluginSuite {
let mut suite = PluginSuite::default();

suite.add_plugin::<BuiltinDojoPlugin>().add_inline_macro_plugin::<SelectorFromTagMacro>();
suite
.add_plugin::<BuiltinDojoPlugin>()
.add_inline_macro_plugin::<SelectorFromTagMacro>()
.add_inline_macro_plugin::<BytearrayHashMacro>();
Comment on lines +29 to +31
Copy link
Collaborator

Choose a reason for hiding this comment

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

@bengineer42 fyi the issue was that you were trying to add 2 times the BuiltinDojoPlugin. This was causing the weird scarb issue on events, which is not related at all. But this was the reason.


suite
}
Expand Down
63 changes: 63 additions & 0 deletions crates/dojo/lang/src/inline_macros/bytearray_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use cairo_lang_defs::patcher::PatchBuilder;
use cairo_lang_defs::plugin::{
InlineMacroExprPlugin, InlinePluginResult, MacroPluginMetadata, NamedPlugin, PluginDiagnostic,
PluginGeneratedFile,
};
use cairo_lang_defs::plugin_utils::unsupported_bracket_diagnostic;
use cairo_lang_diagnostics::Severity;
use cairo_lang_syntax::node::{ast, TypedStablePtr, TypedSyntaxNode};
use dojo_types::naming;

#[derive(Debug, Default)]
pub struct BytearrayHashMacro;

impl NamedPlugin for BytearrayHashMacro {
const NAME: &'static str = "bytearray_hash";
}

impl InlineMacroExprPlugin for BytearrayHashMacro {
fn generate_code(
&self,
db: &dyn cairo_lang_syntax::node::db::SyntaxGroup,
syntax: &ast::ExprInlineMacro,
_metadata: &MacroPluginMetadata<'_>,
) -> InlinePluginResult {
let ast::WrappedArgList::ParenthesizedArgList(arg_list) = syntax.arguments(db) else {
return unsupported_bracket_diagnostic(db, syntax);
};

let args = arg_list.arguments(db).elements(db);

if args.len() != 1 {
return InlinePluginResult {
code: None,
diagnostics: vec![PluginDiagnostic {
stable_ptr: syntax.stable_ptr().untyped(),
message: "Invalid arguments. Expected \"bytearray_hash!(\"long string\")\""
.to_string(),
severity: Severity::Error,
}],
};
}

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

let bytearray_hash = naming::compute_bytearray_hash(bytearray);

let mut builder = PatchBuilder::new(db, syntax);
builder.add_str(&format!("{:#64x}", bytearray_hash));

let (code, code_mappings) = builder.build();

InlinePluginResult {
code: Some(PluginGeneratedFile {
name: "bytearray_hash_macro".into(),
content: code,
code_mappings,
diagnostics_note: None,
aux_data: None,
}),
diagnostics: vec![],
}
}
}
2 changes: 2 additions & 0 deletions crates/dojo/lang/src/inline_macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use cairo_lang_syntax::node::db::SyntaxGroup;
use cairo_lang_syntax::node::{ast, Terminal, TypedStablePtr, TypedSyntaxNode};
use smol_str::SmolStr;

pub mod bytearray_hash;
pub mod delete;
pub mod emit;
pub mod get;
Expand All @@ -17,6 +18,7 @@ pub mod set;
pub mod spawn_test_world;
pub mod utils;

pub use bytearray_hash::BytearrayHashMacro;
pub use delete::DeleteMacro;
pub use emit::EmitMacro;
pub use get::GetMacro;
Expand Down
Loading
Loading