diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a7fe0ad7e6..d5da9be0c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,8 +36,8 @@ Inside `bin` and `crates` you will find source code related to Dojo stack compon - `katana`: The Starknet sequencer tailored for gaming. - `sozo`: The contract manager and Dojo compiler. - `torii`: The indexer that store the state of your World. -- `dojo-core`: The core contract of Dojo written in Cairo. -- `dojo-lang`: The Dojo plugin for the Cairo compiler. +- `dojo/core`: The core contract of Dojo written in Cairo. +- `dojo/lang`: The Dojo plugin for the Cairo compiler. It is important to note that `bin` should only contain applications that gathers user inputs and delegates the work to the libraries present into the crates. @@ -51,6 +51,37 @@ Please use meaningful names for your branches. For example, if you're working on As you're making changes, make sure you follow the coding conventions used throughout the Dojo project. Consistent code style makes it easier for others to read and understand your code. +## Testing the changes + +To speed the test suite and avoid migrating dojo projects again, `katana` databases are compressed and stored in the repo. + +If you don't have any change in the `dojo/core` crate or any cairo example, you only have to extract the databases: + +```bash +bash scripts/extract_test_db.sh +``` + +To test your changes, if you have modified the `dojo/core` crate or any cairo example, you will need to regenerate the databases: + +```bash +# Prints the policies to then be copied into the `sozo/tests/test_data/policies.json` test file to ensure entrypoints and addresses are up to date. +POLICIES_FIX=1 cargo nextest run --all-features --build-jobs 20 --workspace --nocapture policies + +# Ensures the test databases are up to date. +bash scripts/rebuild_test_artifacts.sh +``` + +Then you can run the tests: + +```bash +# If you don't have any change in Katana: +cargo nextest run --all-features --build-jobs 20 --workspace + +# If you have changes in Katana, you must use local Katana to test. +cargo build -r --bin katana +KATANA_RUNNER_BIN=./target/release/katana cargo nextest run --all-features --build-jobs 20 --workspace +``` + ## Submitting a Pull Request Once your changes are ready, commit them and push the branch to your forked repo on GitHub. Then you can open a pull request from your branch to the `main` branch of the Dojo repo. diff --git a/bin/sozo/src/utils.rs b/bin/sozo/src/utils.rs index bbd071edb5..bb3d7b4403 100644 --- a/bin/sozo/src/utils.rs +++ b/bin/sozo/src/utils.rs @@ -40,7 +40,8 @@ pub fn get_world_address( "The world address computed from the seed is different from the address \ provided in config:\n\ndeterministic address: {:#x}\nconfig address: \ {:#x}\n\nThe address in the config file is preferred, consider commenting it \ - out if you attempt to migrate the world with a new seed.", + out from the config file if you attempt to migrate the world with a new \ + seed.\n\nIf you are upgrading the world, you can ignore this message.", deterministic_world_address, wa ) .yellow() diff --git a/bin/sozo/tests/test_data/policies.json b/bin/sozo/tests/test_data/policies.json index 95e4dd9f94..c48574cf3b 100644 --- a/bin/sozo/tests/test_data/policies.json +++ b/bin/sozo/tests/test_data/policies.json @@ -1,118 +1,118 @@ [ { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", + "target": "0x197ece4113fa10c435129f63ffe00877c93446f36a8e3f803b846f76d496ed8", + "method": "upgrade" + }, + { + "target": "0x5e6ead52b5ea1146be22fdc3cffbc28d9eca3452f790f991a010ceeb12e339b", + "method": "upgrade" + }, + { + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "spawn" }, { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "move" }, { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "set_player_config" }, { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "reset_player_config" }, { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "set_player_server_profile" }, { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "set_models" }, { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "enter_dungeon" }, { - "target": "0x7bc340927668bc87eea10d95cb2dfe0fa10be12075fe8189f363643205c34d4", - "method": "upgrade" - }, - { - "target": "0x200cd8070a7dbe0894c74426d2f4c9d778b13042ce955203cb189d85cfb43d1", - "method": "upgrade" - }, - { - "target": "0x2e7d504b81c2f1b60986c95de64b650feb8ae625f04c6cd924150fab3cad4a8", + "target": "0x48c075712ddb98febd836b09049e3d36c7b061fc7027ba5021f8cf00778b7bf", "method": "upgrade" }, { - "target": "0x41ceb76687e3653610fffc3c830607d90079e9c5d96cfb6f270c8231e9ee9db", + "target": "0x317a11a6cb0c66389ad53e1a9c282a64e8b94a7811b139da94138284ce019a4", "method": "upgrade" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "uuid" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "set_metadata" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "register_namespace" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "register_event" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "register_model" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "register_contract" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "init_contract" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "upgrade_event" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "upgrade_model" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "upgrade_contract" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "emit_event" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "set_entity" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "delete_entity" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "grant_owner" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "revoke_owner" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "grant_writer" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "revoke_writer" }, { - "target": "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32", + "target": "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115", "method": "upgrade" }, { diff --git a/crates/dojo/core/src/world/world_contract.cairo b/crates/dojo/core/src/world/world_contract.cairo index 25b9c59346..c37fd2967f 100644 --- a/crates/dojo/core/src/world/world_contract.cairo +++ b/crates/dojo/core/src/world/world_contract.cairo @@ -694,9 +694,18 @@ pub mod world { fn upgrade_contract( ref self: ContractState, namespace: ByteArray, class_hash: ClassHash ) -> ClassHash { - let (new_contract_address, _) = deploy_syscall( - class_hash, starknet::get_tx_info().unbox().transaction_hash, [].span(), false - ) + // Only contracts use an external salt during registration. To ensure the + // upgrade can also be done into a multicall, we combine the transaction hash + // and the namespace hash since we can't have the same class hash registered more than + // once in the same namespace. + let salt = core::poseidon::poseidon_hash_span( + [ + starknet::get_tx_info().unbox().transaction_hash, + dojo::utils::bytearray_hash(@namespace), + ].span() + ); + + let (new_contract_address, _) = deploy_syscall(class_hash, salt, [].span(), false) .unwrap_syscall(); let namespace_hash = bytearray_hash(@namespace); diff --git a/crates/sozo/ops/src/migrate/mod.rs b/crates/sozo/ops/src/migrate/mod.rs index 401db9e7cd..9de60e7e6b 100644 --- a/crates/sozo/ops/src/migrate/mod.rs +++ b/crates/sozo/ops/src/migrate/mod.rs @@ -85,8 +85,7 @@ where &self, ui: &mut MigrationUi, ) -> Result> { - ui.update_text("Deploying world..."); - let world_has_changed = self.ensure_world().await?; + let world_has_changed = self.ensure_world(ui).await?; let resources_have_changed = if !self.diff.is_synced() { self.sync_resources(ui).await? } else { false }; @@ -320,21 +319,33 @@ where ResourceType::Contract => { let (contract_calls, contract_classes) = self.contracts_calls_classes(resource).await?; + + if !contract_calls.is_empty() { + n_resources += 1; + } + invoker.extend_calls(contract_calls); classes.extend(contract_classes); - n_resources += 1; } ResourceType::Model => { let (model_calls, model_classes) = self.models_calls_classes(resource).await?; + + if !model_calls.is_empty() { + n_resources += 1; + } + invoker.extend_calls(model_calls); classes.extend(model_classes); - n_resources += 1; } ResourceType::Event => { let (event_calls, event_classes) = self.events_calls_classes(resource).await?; + + if !event_calls.is_empty() { + n_resources += 1; + } + invoker.extend_calls(event_calls); classes.extend(event_classes); - n_resources += 1; } _ => continue, } @@ -614,10 +625,14 @@ where /// Ensures the world is declared and deployed if necessary. /// /// Returns true if the world has to be deployed/updated, false otherwise. - async fn ensure_world(&self) -> Result> { + async fn ensure_world( + &self, + ui: &mut MigrationUi, + ) -> Result> { match &self.diff.world_info.status { WorldStatus::Synced => return Ok(false), WorldStatus::NotDeployed => { + ui.update_text("Deploying the world..."); trace!("Deploying the first world."); Declarer::declare( @@ -641,6 +656,7 @@ where } WorldStatus::NewVersion => { trace!("Upgrading the world."); + ui.update_text("Upgrading the world..."); Declarer::declare( self.diff.world_info.casm_class_hash, diff --git a/examples/spawn-and-move/dojo_dev.toml b/examples/spawn-and-move/dojo_dev.toml index 9b757c62a5..9a1aea6910 100644 --- a/examples/spawn-and-move/dojo_dev.toml +++ b/examples/spawn-and-move/dojo_dev.toml @@ -11,7 +11,7 @@ rpc_url = "http://localhost:5050/" # Default account for katana with seed = 0 account_address = "0x2af9427c5a277474c079a1283c880ee8a6f0f8fbf73ce969c08d88befec1bba" private_key = "0x1800000000300000180000000000030000000000003006001800006600" -world_address = "0x234d358c2ec21c98a229966bd2bae6dbf2c517969c361bc649361f9055afc32" +world_address = "0xecd610a15ce418719008d506c662ec3e420cf17b4b6d086e53281f30425115" [init_call_args] "ns-others" = ["0xff"] diff --git a/scripts/extract_test_db.sh b/scripts/extract_test_db.sh new file mode 100644 index 0000000000..f4c3b6ee32 --- /dev/null +++ b/scripts/extract_test_db.sh @@ -0,0 +1,6 @@ +# Ensures that the user has locally the db dir in /tmp. + +rm -rf /tmp/spawn-and-move-db +rm -rf /tmp/types-test-db +tar xzf spawn-and-move-db.tar.gz -C /tmp/ +tar xzf types-test-db.tar.gz -C /tmp/ diff --git a/scripts/rebuild_test_artifacts.sh b/scripts/rebuild_test_artifacts.sh index ccfa7b5e82..bd2e42a4a0 100755 --- a/scripts/rebuild_test_artifacts.sh +++ b/scripts/rebuild_test_artifacts.sh @@ -5,8 +5,9 @@ # This script gives an easy way to remove those artifacts. cargo build -r --bin katana +cargo build -r --bin sozo -# some formatting: +# Some formatting. cargo +nightly-2024-08-28 fmt --all -- "$@" scarb --manifest-path examples/spawn-and-move/Scarb.toml fmt @@ -14,9 +15,7 @@ scarb --manifest-path examples/simple/Scarb.toml fmt scarb --manifest-path crates/dojo/core/Scarb.toml fmt scarb --manifest-path crates/dojo/core-cairo-test/Scarb.toml fmt -cargo build -r --bin sozo - -# Cleanup +# Manual forced cleanup. rm -rf examples/spawn-and-move/target rm -rf crates/torii/types-test/target rm -rf crates/dojo/lang/src/manifest_test_data/compiler_cairo/target @@ -37,8 +36,7 @@ cargo +nightly-2024-08-28 fmt --all -- "$@" # Generates the database for testing by migrating the spawn and move example. KATANA_RUNNER_BIN=./target/release/katana cargo generate-test-db -# Ensure the user has locally the db dir in /tmp. -rm -rf /tmp/spawn-and-move-db -rm -rf /tmp/types-test-db -tar xzf spawn-and-move-db.tar.gz -C /tmp/ -tar xzf types-test-db.tar.gz -C /tmp/ + +# Extracts the database for testing. +bash ./scripts/extract_test_db.sh + diff --git a/spawn-and-move-db.tar.gz b/spawn-and-move-db.tar.gz index 7d0a793ad4..5fa4eaf327 100644 Binary files a/spawn-and-move-db.tar.gz and b/spawn-and-move-db.tar.gz differ diff --git a/types-test-db.tar.gz b/types-test-db.tar.gz index f6abaaa511..f23aa96f44 100644 Binary files a/types-test-db.tar.gz and b/types-test-db.tar.gz differ diff --git a/xtask/generate-test-db/src/main.rs b/xtask/generate-test-db/src/main.rs index 9a6783eb4b..fa97957716 100644 --- a/xtask/generate-test-db/src/main.rs +++ b/xtask/generate-test-db/src/main.rs @@ -36,15 +36,29 @@ async fn migrate_spawn_and_move(db_path: &Path) -> Result { let profile_config = ws.load_profile_config()?; let world_local = ws.load_world_local()?; - let world_address = if let Some(env) = &profile_config.env { - env.world_address().map_or_else( - || world_local.deterministic_world_address(), - |wa| Ok(Felt::from_str(wa).unwrap()), - ) + + // In the case of testing, if the addresses are different it means that the example hasn't been + // migrated correctly. + let deterministic_world_address = world_local.deterministic_world_address().unwrap(); + let config_world_address = if let Some(env) = &profile_config.env { + env.world_address() + .map_or_else( + || world_local.deterministic_world_address(), + |wa| Ok(Felt::from_str(wa).unwrap()), + ) + .unwrap() } else { - world_local.deterministic_world_address() + deterministic_world_address + }; + + if deterministic_world_address != config_world_address { + panic!( + "The deterministic world address is different from the config world address. Please \ + review the `dojo_dev.toml` file of spawn-and-move example." + ); } - .unwrap(); + + let world_address = deterministic_world_address; let world_diff = WorldDiff::new_from_chain(world_address, world_local, &runner.provider()).await?; @@ -82,6 +96,7 @@ async fn migrate_types_test(db_path: &Path) -> Result { let profile_config = ws.load_profile_config()?; + // No world address in config, so it should always pick the deterministic one. let world_local = ws.load_world_local()?; let world_address = if let Some(env) = &profile_config.env { env.world_address().map_or_else(