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

Pass world to constructor if expected #962

Merged
merged 1 commit into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 4 additions & 3 deletions crates/dojo-world/src/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,18 +216,19 @@ pub trait Deployable: Declarable + Sync {
fn prepare_contract_declaration_params(
artifact_path: &PathBuf,
) -> Result<(FlattenedSierraClass, FieldElement)> {
let flattened_class = get_flattened_class(artifact_path)
let flattened_class = read_class(artifact_path)?
.flatten()
.map_err(|e| anyhow!("error flattening the contract class: {e}"))?;
let compiled_class_hash = get_compiled_class_hash(artifact_path).map_err(|e| {
anyhow!("error computing compiled class hash: {} {e}", artifact_path.to_str().unwrap())
})?;
Ok((flattened_class, compiled_class_hash))
}

fn get_flattened_class(artifact_path: &PathBuf) -> Result<FlattenedSierraClass> {
pub fn read_class(artifact_path: &PathBuf) -> Result<SierraClass> {
let file = File::open(artifact_path)?;
let contract_artifact: SierraClass = serde_json::from_reader(&file)?;
Ok(contract_artifact.flatten()?)
Ok(contract_artifact)
}

fn get_compiled_class_hash(artifact_path: &PathBuf) -> Result<FieldElement> {
Expand Down
4 changes: 2 additions & 2 deletions crates/sozo/src/commands/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ where
name.clone(),
world_address,
account,
config,
config.ui(),
None,
)
.await
Expand Down Expand Up @@ -213,7 +213,7 @@ impl DevArgs {
self.starknet,
self.world,
env_metadata.as_ref(),
config,
config.ui(),
name.as_ref(),
))
.ok()
Expand Down
2 changes: 1 addition & 1 deletion crates/sozo/src/commands/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl MigrateArgs {
self,
env_metadata,
target_dir,
ws.config(),
ws.config().ui(),
))?;

Ok(())
Expand Down
68 changes: 42 additions & 26 deletions crates/sozo/src/ops/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use dojo_world::migration::contract::ContractMigration;
use dojo_world::migration::strategy::{prepare_for_migration, MigrationStrategy};
use dojo_world::migration::world::WorldDiff;
use dojo_world::migration::{
Declarable, DeployOutput, Deployable, MigrationError, RegisterOutput, StateDiff,
read_class, Declarable, DeployOutput, Deployable, MigrationError, RegisterOutput, StateDiff,
};
use dojo_world::utils::TransactionWaiter;
use scarb::core::Config;
use scarb_ui::Ui;
use starknet::accounts::{Account, ConnectedAccount, SingleOwnerAccount};
use starknet::core::types::contract::AbiEntry;
use starknet::core::types::{
BlockId, BlockTag, FieldElement, InvokeTransactionResult, StarknetError,
};
Expand Down Expand Up @@ -42,7 +42,7 @@ pub async fn execute<U>(
args: MigrateArgs,
env_metadata: Option<Environment>,
target_dir: U,
config: &Config,
ui: &Ui,
) -> Result<()>
where
U: AsRef<Path>,
Expand All @@ -52,25 +52,25 @@ where
// Setup account for migration and fetch world address if it exists.

let (world_address, account) =
setup_env(account, starknet, world, env_metadata.as_ref(), config, name.as_ref()).await?;
setup_env(account, starknet, world, env_metadata.as_ref(), ui, name.as_ref()).await?;

// Load local and remote World manifests.

let (local_manifest, remote_manifest) =
load_world_manifests(&target_dir, world_address, &account, config).await?;
load_world_manifests(&target_dir, world_address, &account, ui).await?;

// Calculate diff between local and remote World manifests.

config.ui().print_step(2, "🧰", "Evaluating Worlds diff...");
ui.print_step(2, "🧰", "Evaluating Worlds diff...");
let diff = WorldDiff::compute(local_manifest, remote_manifest);
let total_diffs = diff.count_diffs();
config.ui().print_sub(format!("Total diffs found: {total_diffs}"));
ui.print_sub(format!("Total diffs found: {total_diffs}"));

if total_diffs == 0 {
config.ui().print("\n✨ No changes to be made. Remote World is already up to date!")
ui.print("\n✨ No changes to be made. Remote World is already up to date!")
} else {
// Mirate according to the diff.
apply_diff(target_dir, diff, name, world_address, &account, config, Some(args.transaction))
apply_diff(target_dir, diff, name, world_address, &account, ui, Some(args.transaction))
.await?;
}

Expand All @@ -83,25 +83,25 @@ pub(crate) async fn apply_diff<U, P, S>(
name: Option<String>,
world_address: Option<FieldElement>,
account: &SingleOwnerAccount<P, S>,
config: &Config,
ui: &Ui,
txn_config: Option<TransactionOptions>,
) -> Result<FieldElement>
where
U: AsRef<Path>,
P: Provider + Sync + Send + 'static,
S: Signer + Sync + Send + 'static,
{
let strategy = prepare_migration(target_dir, diff, name, world_address, config)?;
let strategy = prepare_migration(target_dir, diff, name, world_address, ui)?;

println!(" ");

let block_height = execute_strategy(&strategy, account, config.ui(), txn_config)
let block_height = execute_strategy(&strategy, account, ui, txn_config)
.await
.map_err(|e| anyhow!(e))
.with_context(|| "Problem trying to migrate.")?;

if let Some(block_height) = block_height {
config.ui().print(format!(
ui.print(format!(
"\n🎉 Successfully migrated World on block #{} at address {}",
block_height,
bold_message(format!(
Expand All @@ -110,7 +110,7 @@ where
))
));
} else {
config.ui().print(format!(
ui.print(format!(
"\n🎉 Successfully migrated World at address {}",
bold_message(format!(
"{:#x}",
Expand All @@ -127,7 +127,7 @@ pub(crate) async fn setup_env(
starknet: StarknetOptions,
world: WorldOptions,
env_metadata: Option<&Environment>,
config: &Config,
ui: &Ui,
name: Option<&String>,
) -> Result<(Option<FieldElement>, SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>)> {
let world_address = world.address(env_metadata).ok();
Expand All @@ -139,9 +139,9 @@ pub(crate) async fn setup_env(

let address = account.address();

config.ui().print(format!("\nMigration account: {address:#x}"));
ui.print(format!("\nMigration account: {address:#x}"));
if let Some(name) = name {
config.ui().print(format!("\nWorld name: {name}\n"));
ui.print(format!("\nWorld name: {name}\n"));
}

match account.provider().get_class_hash_at(BlockId::Tag(BlockTag::Pending), address).await {
Expand All @@ -162,20 +162,20 @@ async fn load_world_manifests<U, P, S>(
target_dir: U,
world_address: Option<FieldElement>,
account: &SingleOwnerAccount<P, S>,
config: &Config,
ui: &Ui,
) -> Result<(Manifest, Option<Manifest>)>
where
U: AsRef<Path>,
P: Provider + Sync + Send + 'static,
S: Signer + Sync + Send + 'static,
{
config.ui().print_step(1, "🌎", "Building World state...");
ui.print_step(1, "🌎", "Building World state...");

let local_manifest = Manifest::load_from_path(target_dir.as_ref().join("manifest.json"))?;

let remote_manifest = if let Some(world_address) = world_address {
config.ui().print_sub(format!("Found remote World: {world_address:#x}"));
config.ui().print_sub("Fetching remote state");
ui.print_sub(format!("Found remote World: {world_address:#x}"));
ui.print_sub("Fetching remote state");

Manifest::from_remote(account.provider(), world_address, Some(local_manifest.clone()))
.await
Expand All @@ -191,7 +191,7 @@ where
})
.with_context(|| "Failed to build remote World state.")?
} else {
config.ui().print_sub("No remote World found");
ui.print_sub("No remote World found");
None
};

Expand All @@ -203,12 +203,12 @@ fn prepare_migration<U>(
diff: WorldDiff,
name: Option<String>,
world_address: Option<FieldElement>,
config: &Config,
ui: &Ui,
) -> Result<MigrationStrategy>
where
U: AsRef<Path>,
{
config.ui().print_step(3, "📦", "Preparing for migration...");
ui.print_step(3, "📦", "Preparing for migration...");

if name.is_none() && !diff.world.is_same() {
bail!(
Expand All @@ -228,7 +228,7 @@ where

let info = migration.info();

config.ui().print_sub(format!(
ui.print_sub(format!(
"Total items to be migrated ({}): New {} Update {}",
info.new + info.update,
info.new,
Expand Down Expand Up @@ -415,9 +415,25 @@ where
let mut deploy_output = vec![];

for contract in strategy.contracts.iter() {
let mut constructor_calldata = vec![];
let class = read_class(contract.artifact_path())?;
for entry in class.abi {
if let AbiEntry::Constructor(constructor) = entry {
if !constructor.inputs.is_empty()
&& constructor.inputs[0].r#type == "dojo::world::IWorldDispatcher"
{
let world_address = strategy.world_address()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this not empty for a newly deployed world ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assume it is populated since we use it for registering models too

constructor_calldata.push(world_address);
break;
}
}
}

let name = &contract.diff.name;
ui.print(italic_message(name).to_string());
match deploy_contract(contract, name, vec![], migrator, ui, &txn_config).await? {
match deploy_contract(contract, name, constructor_calldata, migrator, ui, &txn_config)
.await?
{
ContractDeploymentOutput::Output(output) => {
ui.print_sub(format!("Contract address: {:#x}", output.contract_address));
ui.print_hidden_sub(format!("deploy transaction: {:#x}", output.transaction_hash));
Expand Down
Loading