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

refactor(sozo): fetch writes from events and calculate diff for that + some refactor #2203

Merged
merged 18 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 17 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
16 changes: 11 additions & 5 deletions bin/sozo/src/commands/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,15 @@
contracts=?models_contracts,
"Granting Writer permissions."
);
auth::grant_writer(ui, &world, models_contracts, transaction.into(), default_namespace)
auth::grant_writer(ui, &world, &models_contracts, transaction.into(), default_namespace)

Check warning on line 159 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L159

Added line #L159 was not covered by tests
.await
}
AuthKind::Owner { owners_resources } => {
trace!(
resources=?owners_resources,
"Granting Owner permissions."
);
auth::grant_owner(ui, &world, owners_resources, transaction.into(), default_namespace)
auth::grant_owner(ui, &world, &owners_resources, transaction.into(), default_namespace)

Check warning on line 167 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L167

Added line #L167 was not covered by tests
.await
}
}
Expand Down Expand Up @@ -192,15 +192,21 @@
contracts=?models_contracts,
"Revoking Writer permissions."
);
auth::revoke_writer(ui, &world, models_contracts, transaction.into(), default_namespace)
.await
auth::revoke_writer(
ui,
&world,
&models_contracts,
transaction.into(),
default_namespace,
)
.await

Check warning on line 202 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L195-L202

Added lines #L195 - L202 were not covered by tests
}
AuthKind::Owner { owners_resources } => {
trace!(
resources=?owners_resources,
"Revoking Owner permissions."
);
auth::revoke_owner(ui, &world, owners_resources, transaction.into(), default_namespace)
auth::revoke_owner(ui, &world, &owners_resources, transaction.into(), default_namespace)

Check warning on line 209 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L209

Added line #L209 was not covered by tests
.await
}
}
Expand Down
2 changes: 1 addition & 1 deletion bin/sozo/tests/register_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async fn reregister_models() {
account.set_block_id(BlockId::Tag(BlockTag::Pending));

execute_strategy(&ws, &migration, &account, TxnConfig::init_wait()).await.unwrap();
let world_address = &format!("0x{:x}", &migration.world_address().unwrap());
let world_address = &format!("0x{:x}", &migration.world_address);
let account_address = &format!("0x{:x}", account.address());
let private_key =
&format!("0x{:x}", sequencer.account_data(0).private_key.as_ref().unwrap().secret_scalar());
Expand Down
14 changes: 6 additions & 8 deletions crates/dojo-test-utils/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@ pub fn prepare_migration(
manifest.merge(overlay_manifest);
}

let mut world = WorldDiff::compute(manifest, None);
world.update_order(default_namespace).unwrap();
let world = WorldDiff::compute(manifest, None, default_namespace)?;

let mut strat = prepare_for_migration(None, felt!("0x12345"), &target_dir, world).unwrap();
strat.resolve_variable(strat.world_address().unwrap()).unwrap();
let strat = prepare_for_migration(None, felt!("0x12345"), &target_dir, world).unwrap();

Ok(strat)
}
Expand All @@ -47,7 +45,7 @@ pub fn prepare_migration_with_world_and_seed(
world_address: Option<Felt>,
seed: &str,
default_namespace: &str,
) -> Result<MigrationStrategy> {
) -> Result<(MigrationStrategy, WorldDiff)> {
// In testing, profile name is always dev.
let profile_name = "dev";

Expand All @@ -62,9 +60,9 @@ pub fn prepare_migration_with_world_and_seed(
manifest.merge(overlay_manifest);
}

let mut world = WorldDiff::compute(manifest, None);
world.update_order(default_namespace).unwrap();
let world = WorldDiff::compute(manifest, None, default_namespace)?;

let seed = cairo_short_string_to_felt(seed).unwrap();
prepare_for_migration(world_address, seed, &target_dir, world)
let strat = prepare_for_migration(world_address, seed, &target_dir, world.clone())?;
Ok((strat, world))
}
12 changes: 12 additions & 0 deletions crates/dojo-world/src/contracts/naming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@
format!("{tag}{TAG_SEPARATOR}{selector}")
}

pub fn get_tag_from_filename(filename: &str) -> Result<String> {
let parts: Vec<&str> = filename.split(TAG_SEPARATOR).collect();
if parts.len() != 3 {
return Err(anyhow!(
"Unexpected filename. Expected format: \
<NAMESPACE>{TAG_SEPARATOR}<NAME>{TAG_SEPARATOR}<SELECTOR>"
));
}

Ok(format!("{}{TAG_SEPARATOR}{}", parts[0], parts[1]))
}

Check warning on line 81 in crates/dojo-world/src/contracts/naming.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/contracts/naming.rs#L71-L81

Added lines #L71 - L81 were not covered by tests

pub fn compute_bytearray_hash(value: &str) -> Felt {
let ba = ByteArray::from_string(value).unwrap();
poseidon_hash_many(&ByteArray::cairo_serialize(&ba))
Expand Down
6 changes: 2 additions & 4 deletions crates/dojo-world/src/contracts/world_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,12 @@ pub async fn deploy_world(
manifest.merge(overlay_manifest);
}

let mut world = WorldDiff::compute(manifest.clone(), None);
world.update_order(default_namespace).unwrap();
let world = WorldDiff::compute(manifest.clone(), None, default_namespace).unwrap();

let account = sequencer.account(0);

let mut strategy =
let strategy =
prepare_for_migration(None, Felt::from_hex("0x12345").unwrap(), target_dir, world).unwrap();
strategy.resolve_variable(strategy.world_address().unwrap()).unwrap();

let base_class_hash =
strategy.base.unwrap().declare(&account, &TxnConfig::init_wait()).await.unwrap().class_hash;
Expand Down
8 changes: 4 additions & 4 deletions crates/dojo-world/src/manifest/manifest_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ fn parse_deployed_contracts_events_without_upgrade() {
build_deploy_event(vec![felt!("0x0"), felt!("0x3"), felt!("0x789")], "ns3", "c3"),
];

let actual_contracts = parse_contracts_events(events, vec![]);
let actual_contracts = parse_contracts_events(events, vec![], vec![]);
assert_eq!(actual_contracts, expected_contracts);
}

Expand Down Expand Up @@ -213,7 +213,7 @@ fn parse_deployed_contracts_events_with_upgrade() {
},
];

let actual_contracts = parse_contracts_events(deployed_events, upgrade_events);
let actual_contracts = parse_contracts_events(deployed_events, upgrade_events, vec![]);
similar_asserts::assert_eq!(actual_contracts, expected_contracts);
}

Expand Down Expand Up @@ -293,7 +293,7 @@ fn events_without_block_number_arent_parsed() {
},
];

let actual_contracts = parse_contracts_events(deployed_events, upgrade_events);
let actual_contracts = parse_contracts_events(deployed_events, upgrade_events, vec![]);
similar_asserts::assert_eq!(actual_contracts, expected_contracts);
}

Expand Down Expand Up @@ -357,7 +357,7 @@ fn fetch_remote_manifest() {

// compute diff from local and remote manifest

let diff = WorldDiff::compute(local_manifest, Some(remote_manifest));
let diff = WorldDiff::compute(local_manifest, Some(remote_manifest), "dojo-test").unwrap();

assert_eq!(diff.count_diffs(), 0, "there should not be any diff");
}
Expand Down
123 changes: 102 additions & 21 deletions crates/dojo-world/src/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::{fs, io};

use anyhow::Result;
use cainome::cairo_serde::{ByteArray, CairoSerde, Error as CainomeError};
use cainome::cairo_serde::{ByteArray, CairoSerde, Error as CainomeError, Zeroable};
use camino::Utf8PathBuf;
use serde::de::DeserializeOwned;
use serde::Serialize;
Expand Down Expand Up @@ -132,6 +132,24 @@
self.models.retain(|model| !tags.contains(&model.inner.tag));
}

/// Generates a map of `tag -> ManifestKind`
pub fn build_kind_from_tags(&self) -> HashMap<String, ManifestKind> {
let mut kind_from_tags = HashMap::<String, ManifestKind>::new();

kind_from_tags.insert(WORLD_CONTRACT_TAG.to_string(), ManifestKind::WorldClass);
kind_from_tags.insert(BASE_CONTRACT_TAG.to_string(), ManifestKind::BaseClass);

for model in self.models.as_slice() {
kind_from_tags.insert(model.inner.tag.clone(), ManifestKind::Model);
}

for contract in self.contracts.as_slice() {
kind_from_tags.insert(contract.inner.tag.clone(), ManifestKind::Contract);
}

kind_from_tags
}

pub fn merge(&mut self, overlay: OverlayManifest) {
let mut base_map = HashMap::new();

Expand Down Expand Up @@ -161,31 +179,14 @@
}

#[derive(Clone, Debug, Copy)]
enum ManifestKind {
pub enum ManifestKind {
BaseClass,
WorldClass,
Contract,
Model,
}

impl OverlayManifest {
fn build_kind_from_tags(base_manifest: &BaseManifest) -> HashMap<String, ManifestKind> {
let mut kind_from_tags = HashMap::<String, ManifestKind>::new();

kind_from_tags.insert(WORLD_CONTRACT_TAG.to_string(), ManifestKind::WorldClass);
kind_from_tags.insert(BASE_CONTRACT_TAG.to_string(), ManifestKind::BaseClass);

for model in base_manifest.models.as_slice() {
kind_from_tags.insert(model.inner.tag.clone(), ManifestKind::Model);
}

for contract in base_manifest.contracts.as_slice() {
kind_from_tags.insert(contract.inner.tag.clone(), ManifestKind::Contract);
}

kind_from_tags
}

fn load_overlay(
path: &PathBuf,
kind: ManifestKind,
Expand Down Expand Up @@ -219,7 +220,7 @@
) -> Result<Self, AbstractManifestError> {
fs::create_dir_all(path)?;

let kind_from_tags = Self::build_kind_from_tags(base_manifest);
let kind_from_tags = base_manifest.build_kind_from_tags();
let mut loaded_tags = HashMap::<String, bool>::new();
let mut overlays = OverlayManifest::default();

Expand Down Expand Up @@ -360,6 +361,7 @@
Ok(())
}

// Writes the Deployment manifest in JSON format, with ABIs embedded.
pub fn write_to_path_json(&self, path: &Utf8PathBuf, root_dir: &Utf8PathBuf) -> Result<()> {
fs::create_dir_all(path.parent().unwrap())?;

Expand Down Expand Up @@ -442,6 +444,23 @@
}
}

// impl DeploymentMetadata {
// pub fn load_from_path(path: &Utf8PathBuf) -> Result<Self, AbstractManifestError> {
// let manifest: Self = toml::from_str(&fs::read_to_string(path)?).unwrap();

// Ok(manifest)
// }

// pub fn write_to_path_toml(&self, path: &Utf8PathBuf) -> Result<()> {
// fs::create_dir_all(path.parent().unwrap())?;

// let deployed_manifest = toml::to_string_pretty(&self)?;
// fs::write(path, deployed_manifest)?;

// Ok(())
// }
// }
lambda-0x marked this conversation as resolved.
Show resolved Hide resolved

// TODO: currently implementing this method using trait is causing lifetime issue due to
// `async_trait` macro which is hard to debug. So moved it as a async method on type itself.
// #[async_trait]
Expand All @@ -465,6 +484,7 @@
let registered_models_event_name = starknet_keccak("ModelRegistered".as_bytes());
let contract_deployed_event_name = starknet_keccak("ContractDeployed".as_bytes());
let contract_upgraded_event_name = starknet_keccak("ContractUpgraded".as_bytes());
let writer_updated_event_name = starknet_keccak("WriterUpdated".as_bytes());

let events = get_events(
&provider,
Expand All @@ -473,13 +493,15 @@
registered_models_event_name,
contract_deployed_event_name,
contract_upgraded_event_name,
writer_updated_event_name,
]],
)
.await?;

let mut registered_models_events = vec![];
let mut contract_deployed_events = vec![];
let mut contract_upgraded_events = vec![];
let mut writer_updated_events = vec![];

for event in events {
match event.keys.first() {
Expand All @@ -492,12 +514,19 @@
Some(event_name) if *event_name == contract_upgraded_event_name => {
contract_upgraded_events.push(event)
}
Some(event_name) if *event_name == writer_updated_event_name => {
writer_updated_events.push(event)
}
_ => {}
}
}

let models = parse_models_events(registered_models_events);
let mut contracts = parse_contracts_events(contract_deployed_events, contract_upgraded_events);
let mut contracts = parse_contracts_events(
contract_deployed_events,
contract_upgraded_events,
writer_updated_events,
);

for contract in &mut contracts {
contract.manifest_name = naming::get_filename_from_tag(&contract.inner.tag);
Expand Down Expand Up @@ -537,7 +566,52 @@
fn parse_contracts_events(
deployed: Vec<EmittedEvent>,
upgraded: Vec<EmittedEvent>,
granted: Vec<EmittedEvent>,
) -> Vec<Manifest<DojoContract>> {
fn retain_only_latest_grant_events(events: Vec<EmittedEvent>) -> HashMap<Felt, Vec<Felt>> {
// create a map with some extra data which will be flattened later
// system -> (block_num, (resource -> perm))
let mut grants: HashMap<Felt, (u64, HashMap<Felt, bool>)> = HashMap::new();
events.into_iter().for_each(|event| {
let mut data = event.data.into_iter();
let block_num = event.block_number;
let resource = data.next().expect("resource is missing from event");
let contract = data.next().expect("contract is missing from event");
let value = data.next().expect("value is missing from event");

let value = !value.is_zero();

// Events that do not have a block number are ignored because we are unable to evaluate
// whether the events happened before or after the latest event that has been processed.
if let Some(num) = block_num {
grants
.entry(contract)
.and_modify(|(current_block, current_resource)| {
if *current_block < num {
*current_block = num;
current_resource.insert(resource, value);

Check warning on line 592 in crates/dojo-world/src/manifest/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest/mod.rs#L591-L592

Added lines #L591 - L592 were not covered by tests
}
})
.or_insert((num, HashMap::from([(resource, value)])));
}
});

// flatten out the map to remove block_number information and only include resources that
// are true i.e. system -> [resources]
grants
.into_iter()
.map(|(contract, (_, resources))| {
(
contract,
resources
.into_iter()
.filter_map(|(resource, bool)| if bool { Some(resource) } else { None })
.collect(),
)
})
.collect()
}

fn retain_only_latest_upgrade_events(events: Vec<EmittedEvent>) -> HashMap<Felt, Felt> {
// addr -> (block_num, class_hash)
let mut upgrades: HashMap<Felt, (u64, Felt)> = HashMap::new();
Expand Down Expand Up @@ -568,6 +642,7 @@
}

let upgradeds = retain_only_latest_upgrade_events(upgraded);
let grants = retain_only_latest_grant_events(granted);

deployed
.into_iter()
Expand All @@ -594,12 +669,18 @@
class_hash = *upgrade;
}

let mut writes = vec![];
if let Some(contract) = grants.get(&address) {
writes.extend(contract.iter().map(|f| f.to_hex_string()));
}

Manifest::new(
DojoContract {
address: Some(address),
class_hash,
abi: None,
tag: tag.clone(),
writes,
..Default::default()
},
naming::get_filename_from_tag(&tag),
Expand Down
Loading
Loading