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

[sozo] generate JSON manifest #1694

Merged
merged 9 commits into from
Mar 25, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ output.txt
**/katana-logs
crates/benches/bench_results.txt
**/generated
.vscode
4 changes: 2 additions & 2 deletions crates/dojo-lang/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use cairo_lang_utils::UpcastMut;
use camino::Utf8PathBuf;
use convert_case::{Case, Casing};
use dojo_world::manifest::{
Class, ComputedValueEntrypoint, DojoContract, DojoModel, Manifest, ManifestMethods,
AbiFormat, Class, ComputedValueEntrypoint, DojoContract, DojoModel, Manifest, ManifestMethods,
BASE_CONTRACT_NAME, WORLD_CONTRACT_NAME,
};
use itertools::Itertools;
Expand Down Expand Up @@ -451,7 +451,7 @@ where
let relative_abi_path = relative_abis_dir.join(name.clone()).with_extension("json");

if abi.is_some() {
manifest.inner.set_abi(Some(relative_abi_path.clone()));
manifest.inner.set_abi(Some(AbiFormat::Path(relative_abi_path.clone())));
}

let manifest_toml = toml::to_string_pretty(&manifest)?;
Expand Down
124 changes: 96 additions & 28 deletions crates/dojo-world/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use serde_with::serde_as;
use smol_str::SmolStr;
use starknet::core::serde::unsigned_field_element::UfeHex;
use starknet::core::types::contract::AbiEntry;
use starknet::core::types::{
BlockId, BlockTag, EmittedEvent, EventFilter, FieldElement, FunctionCall, StarknetError,
};
Expand Down Expand Up @@ -75,13 +76,14 @@

/// Represents a declaration of a model.
#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]
#[serde(tag = "kind")]
pub struct DojoModel {
pub members: Vec<Member>,
#[serde_as(as = "UfeHex")]
pub class_hash: FieldElement,
pub abi: Option<Utf8PathBuf>,
pub abi: Option<AbiFormat>,
}

/// System input ABI.
Expand Down Expand Up @@ -110,57 +112,100 @@
pub model: Option<String>,
}

/// Format of the ABI into the manifest.
#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum AbiFormat {
/// Only a relative path to the ABI file is stored.
Path(Utf8PathBuf),
/// The full ABI is embedded.
Embed(Vec<AbiEntry>),
}

#[cfg(test)]
impl PartialEq for AbiFormat {
fn eq(&self, other: &Self) -> bool {
glihm marked this conversation as resolved.
Show resolved Hide resolved
match (self, other) {
(AbiFormat::Path(p1), AbiFormat::Path(p2)) => p1 == p2,
(AbiFormat::Embed(e1), AbiFormat::Embed(e2)) => {
// Currently, [`AbiEntry`] does not implement [`PartialEq`] so we cannot compare
// them directly.
let e1_json = serde_json::to_string(e1).expect("valid JSON from ABI");
let e2_json = serde_json::to_string(e2).expect("valid JSON from ABI");
e1_json == e2_json

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L129-L136

Added lines #L129 - L136 were not covered by tests
}
_ => false,

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L138

Added line #L138 was not covered by tests
}
}

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L140

Added line #L140 was not covered by tests
}

impl AbiFormat {
pub fn to_path(&self) -> Option<&Utf8PathBuf> {
match self {
AbiFormat::Path(p) => Some(p),
AbiFormat::Embed(_) => None,

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L144-L147

Added lines #L144 - L147 were not covered by tests
}
}

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L149

Added line #L149 was not covered by tests
}

#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]
#[serde(tag = "kind")]
pub struct DojoContract {
#[serde_as(as = "Option<UfeHex>")]
pub address: Option<FieldElement>,
#[serde_as(as = "UfeHex")]
pub class_hash: FieldElement,
pub abi: Option<Utf8PathBuf>,
pub abi: Option<AbiFormat>,
pub reads: Vec<String>,
pub writes: Vec<String>,
pub computed: Vec<ComputedValueEntrypoint>,
}

#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]

#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L168-L169

Added lines #L168 - L169 were not covered by tests
pub struct OverlayDojoContract {
pub name: SmolStr,
pub reads: Option<Vec<String>>,
pub writes: Option<Vec<String>>,
}

#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L177-L178

Added lines #L177 - L178 were not covered by tests
pub struct OverlayDojoModel {}

#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L182-L183

Added lines #L182 - L183 were not covered by tests
pub struct OverlayContract {}

#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L187-L188

Added lines #L187 - L188 were not covered by tests
pub struct OverlayClass {}

#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L193

Added line #L193 was not covered by tests
#[serde(tag = "kind")]
pub struct Class {
#[serde_as(as = "UfeHex")]
pub class_hash: FieldElement,
pub abi: Option<Utf8PathBuf>,
pub abi: Option<AbiFormat>,
}

#[serde_as]
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L203

Added line #L203 was not covered by tests
#[serde(tag = "kind")]
pub struct Contract {
#[serde_as(as = "UfeHex")]
pub class_hash: FieldElement,
pub abi: Option<Utf8PathBuf>,
pub abi: Option<AbiFormat>,
#[serde_as(as = "Option<UfeHex>")]
pub address: Option<FieldElement>,
#[serde_as(as = "Option<UfeHex>")]
Expand All @@ -170,7 +215,8 @@
pub seed: Option<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L219

Added line #L219 was not covered by tests
pub struct BaseManifest {
pub world: Manifest<Class>,
pub base: Manifest<Class>,
Expand Down Expand Up @@ -202,20 +248,23 @@
}
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L251-L252

Added lines #L251 - L252 were not covered by tests
pub struct DeploymentManifest {
pub world: Manifest<Contract>,
pub base: Manifest<Class>,
pub contracts: Vec<Manifest<DojoContract>>,
pub models: Vec<Manifest<DojoModel>>,
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L260-L261

Added lines #L260 - L261 were not covered by tests
pub struct OverlayManifest {
pub contracts: Vec<OverlayDojoContract>,
}

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct Manifest<T>
where
T: ManifestMethods,
Expand All @@ -236,8 +285,8 @@

pub trait ManifestMethods {
type OverlayType;
fn abi(&self) -> Option<&Utf8PathBuf>;
fn set_abi(&mut self, abi: Option<Utf8PathBuf>);
fn abi(&self) -> Option<&AbiFormat>;
fn set_abi(&mut self, abi: Option<AbiFormat>);
fn class_hash(&self) -> &FieldElement;
fn set_class_hash(&mut self, class_hash: FieldElement);

Expand Down Expand Up @@ -300,7 +349,7 @@
self.world.inner.seed = previous.world.inner.seed;
}

pub fn write_to_path(&self, path: &Utf8PathBuf) -> Result<()> {
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)?;
Expand All @@ -309,6 +358,25 @@
Ok(())
}

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

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L362

Added line #L362 was not covered by tests

// Embedding ABIs into the manifest.
let mut manifest_with_abis = self.clone();
for contract in &mut manifest_with_abis.contracts {
if let Some(AbiFormat::Path(abi_path)) = &contract.inner.abi {
let mut abi_file = std::fs::File::open(manifest_dir.join(abi_path))?;
let abi_entries: Vec<AbiEntry> = serde_json::from_reader(&mut abi_file)?;
contract.inner.abi = Some(AbiFormat::Embed(abi_entries));
}

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L365-L371

Added lines #L365 - L371 were not covered by tests
}

let deployed_manifest = serde_json::to_string_pretty(&manifest_with_abis)?;
fs::write(path, deployed_manifest)?;

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L374-L375

Added lines #L374 - L375 were not covered by tests

Ok(())
}

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L377-L378

Added lines #L377 - L378 were not covered by tests

/// Construct a manifest of a remote World.
///
/// # Arguments
Expand Down Expand Up @@ -628,11 +696,11 @@
impl ManifestMethods for DojoContract {
type OverlayType = OverlayDojoContract;

fn abi(&self) -> Option<&Utf8PathBuf> {
fn abi(&self) -> Option<&AbiFormat> {
self.abi.as_ref()
}

fn set_abi(&mut self, abi: Option<Utf8PathBuf>) {
fn set_abi(&mut self, abi: Option<AbiFormat>) {
self.abi = abi;
}

Expand All @@ -657,11 +725,11 @@
impl ManifestMethods for DojoModel {
type OverlayType = OverlayDojoModel;

fn abi(&self) -> Option<&Utf8PathBuf> {
fn abi(&self) -> Option<&AbiFormat> {

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L728

Added line #L728 was not covered by tests
self.abi.as_ref()
}

fn set_abi(&mut self, abi: Option<Utf8PathBuf>) {
fn set_abi(&mut self, abi: Option<AbiFormat>) {

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L732

Added line #L732 was not covered by tests
self.abi = abi;
}

Expand All @@ -679,11 +747,11 @@
impl ManifestMethods for Contract {
type OverlayType = OverlayContract;

fn abi(&self) -> Option<&Utf8PathBuf> {
fn abi(&self) -> Option<&AbiFormat> {

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L750

Added line #L750 was not covered by tests
self.abi.as_ref()
}

fn set_abi(&mut self, abi: Option<Utf8PathBuf>) {
fn set_abi(&mut self, abi: Option<AbiFormat>) {

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L754

Added line #L754 was not covered by tests
self.abi = abi;
}

Expand All @@ -701,11 +769,11 @@
impl ManifestMethods for Class {
type OverlayType = OverlayClass;

fn abi(&self) -> Option<&Utf8PathBuf> {
fn abi(&self) -> Option<&AbiFormat> {

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L772

Added line #L772 was not covered by tests
self.abi.as_ref()
}

fn set_abi(&mut self, abi: Option<Utf8PathBuf>) {
fn set_abi(&mut self, abi: Option<AbiFormat>) {

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

View check run for this annotation

Codecov / codecov/patch

crates/dojo-world/src/manifest.rs#L776

Added line #L776 was not covered by tests
self.abi = abi;
}

Expand Down
6 changes: 3 additions & 3 deletions crates/sozo/ops/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use cainome::parser::tokens::{CompositeInner, CompositeInnerKind, CoreBasic, Tok
use cainome::parser::AbiParser;
use camino::Utf8PathBuf;
use dojo_lang::compiler::{DEPLOYMENTS_DIR, MANIFESTS_DIR};
use dojo_world::manifest::{DeploymentManifest, ManifestMethods};
use dojo_world::manifest::{AbiFormat, DeploymentManifest, ManifestMethods};
use starknet::core::types::{BlockId, EventFilter, FieldElement};
use starknet::core::utils::{parse_cairo_short_string, starknet_keccak};
use starknet::providers::jsonrpc::HttpTransport;
Expand Down Expand Up @@ -104,14 +104,14 @@ fn extract_events(
let mut events_map = HashMap::new();

for contract in &manifest.contracts {
if let Some(abi_path) = contract.inner.abi() {
if let Some(AbiFormat::Path(abi_path)) = contract.inner.abi() {
let full_abi_path = manifest_dir.join(abi_path);
process_abi(&mut events_map, &full_abi_path)?;
}
}

for model in &manifest.contracts {
if let Some(abi_path) = model.inner.abi() {
if let Some(AbiFormat::Path(abi_path)) = model.inner.abi() {
let full_abi_path = manifest_dir.join(abi_path);
process_abi(&mut events_map, &full_abi_path)?;
}
Expand Down
23 changes: 13 additions & 10 deletions crates/sozo/ops/src/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use dojo_world::contracts::cairo_utils;
use dojo_world::contracts::world::WorldContract;
use dojo_world::manifest::{
AbstractManifestError, BaseManifest, DeploymentManifest, DojoContract, Manifest,
AbiFormat, AbstractManifestError, BaseManifest, DeploymentManifest, DojoContract, Manifest,
ManifestMethods, OverlayManifest,
};
use dojo_world::metadata::dojo_metadata_from_workspace;
Expand Down Expand Up @@ -133,6 +133,10 @@
Ok(())
}

fn build_deployed_path(manifest_dir: &Utf8PathBuf, chain_id: &str, extension: &str) -> Utf8PathBuf {
manifest_dir.join(MANIFESTS_DIR).join(DEPLOYMENTS_DIR).join(chain_id).with_extension(extension)
}

Check warning on line 138 in crates/sozo/ops/src/migration/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/sozo/ops/src/migration/mod.rs#L136-L138

Added lines #L136 - L138 were not covered by tests

async fn update_manifests_and_abis(
ws: &Workspace<'_>,
local_manifest: BaseManifest,
Expand All @@ -145,11 +149,8 @@
let ui = ws.config().ui();
ui.print("\n✨ Updating manifests...");

let deployed_path = manifest_dir
.join(MANIFESTS_DIR)
.join(DEPLOYMENTS_DIR)
.join(chain_id)
.with_extension("toml");
let deployed_path = build_deployed_path(manifest_dir, chain_id, "toml");
let deployed_path_json = build_deployed_path(manifest_dir, chain_id, "json");

Check warning on line 153 in crates/sozo/ops/src/migration/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/sozo/ops/src/migration/mod.rs#L152-L153

Added lines #L152 - L153 were not covered by tests
glihm marked this conversation as resolved.
Show resolved Hide resolved

let mut local_manifest: DeploymentManifest = local_manifest.into();

Expand Down Expand Up @@ -185,7 +186,8 @@
// local_manifest
update_manifest_abis(&mut local_manifest, manifest_dir, chain_id).await;

local_manifest.write_to_path(&deployed_path)?;
local_manifest.write_to_path_toml(&deployed_path)?;
local_manifest.write_to_path_json(&deployed_path_json, manifest_dir)?;

Check warning on line 190 in crates/sozo/ops/src/migration/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/sozo/ops/src/migration/mod.rs#L189-L190

Added lines #L189 - L190 were not covered by tests
ui.print("\n✨ Done.");

Ok(())
Expand All @@ -204,8 +206,9 @@
where
T: ManifestMethods,
{
// unwraps in call to abi is safe because we always write abis for DojoContracts
let base_relative_path = manifest.inner.abi().unwrap();
// unwraps in call to abi is safe because we always write abis for DojoContracts as relative
// path.
let base_relative_path = manifest.inner.abi().unwrap().to_path().unwrap();

Check warning on line 211 in crates/sozo/ops/src/migration/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/sozo/ops/src/migration/mod.rs#L209-L211

Added lines #L209 - L211 were not covered by tests
let deployed_relative_path =
Utf8PathBuf::new().join(ABIS_DIR).join(DEPLOYMENTS_DIR).join(chain_id).join(
base_relative_path
Expand All @@ -220,7 +223,7 @@
.await
.expect("Failed to create folder");
fs::copy(full_base_path, full_deployed_path).await.expect("Failed to copy abi file");
manifest.inner.set_abi(Some(deployed_relative_path));
manifest.inner.set_abi(Some(AbiFormat::Path(deployed_relative_path)));

Check warning on line 226 in crates/sozo/ops/src/migration/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/sozo/ops/src/migration/mod.rs#L226

Added line #L226 was not covered by tests
}

for contract in local_manifest.contracts.iter_mut() {
Expand Down
2 changes: 1 addition & 1 deletion examples/spawn-and-move/abis/base/contracts/actions.json
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@
{
"name": "player",
"type": "core::starknet::contract_address::ContractAddress",
"kind": "data"
"kind": "key"
glihm marked this conversation as resolved.
Show resolved Hide resolved
},
{
"name": "direction",
Expand Down
Loading
Loading