Skip to content

Commit

Permalink
feat(compiler): store abi inside manifest.json file (#807)
Browse files Browse the repository at this point in the history
* feat(compiler): store abi inside manifest.json file

* fix tests
  • Loading branch information
lambda-0x authored Aug 20, 2023
1 parent ee924b3 commit 9483a9e
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 28 deletions.
10 changes: 6 additions & 4 deletions crates/dojo-lang/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use cairo_lang_compiler::db::RootDatabase;
use cairo_lang_filesystem::db::FilesGroup;
use cairo_lang_filesystem::ids::{CrateId, CrateLongId};
use cairo_lang_semantic::db::SemanticGroup;
use cairo_lang_starknet::abi;
use cairo_lang_starknet::contract::{find_contracts, ContractDeclaration};
use cairo_lang_starknet::contract_class::{compile_prepared_db, ContractClass};
use cairo_lang_utils::UpcastMut;
Expand Down Expand Up @@ -85,7 +86,8 @@ impl Compiler for DojoCompiler {
};

// (contract name, class hash)
let mut compiled_classes: HashMap<SmolStr, FieldElement> = HashMap::new();
let mut compiled_classes: HashMap<SmolStr, (FieldElement, Option<abi::Contract>)> =
HashMap::new();

for (decl, class) in zip(contracts, classes) {
let target_name = &unit.target().name;
Expand All @@ -96,10 +98,10 @@ impl Compiler for DojoCompiler {
serde_json::to_writer_pretty(file.deref_mut(), &class)
.with_context(|| format!("failed to serialize contract: {contract_name}"))?;

let class_hash = compute_class_hash_of_contract_class(class).with_context(|| {
let class_hash = compute_class_hash_of_contract_class(&class).with_context(|| {
format!("problem computing class hash for contract `{contract_name}`")
})?;
compiled_classes.insert(contract_name, class_hash);
compiled_classes.insert(contract_name, (class_hash, class.abi));
}

let mut file = target_dir.open_rw("manifest.json", "output file", ws.config())?;
Expand All @@ -111,7 +113,7 @@ impl Compiler for DojoCompiler {
}
}

fn compute_class_hash_of_contract_class(class: ContractClass) -> Result<FieldElement> {
fn compute_class_hash_of_contract_class(class: &ContractClass) -> Result<FieldElement> {
let class_str = serde_json::to_string(&class)?;
let sierra_class = serde_json::from_str::<SierraClass>(&class_str)
.map_err(|e| anyhow!("error parsing Sierra class: {e}"))?;
Expand Down
52 changes: 32 additions & 20 deletions crates/dojo-lang/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use cairo_lang_defs::ids::{ModuleId, ModuleItemId};
use cairo_lang_filesystem::ids::CrateId;
use cairo_lang_semantic::db::SemanticGroup;
use cairo_lang_semantic::plugin::DynPluginAuxData;
use cairo_lang_starknet::abi;
use convert_case::{Case, Casing};
use dojo_world::manifest::{
Contract, Input, Output, System, EXECUTOR_CONTRACT_NAME, WORLD_CONTRACT_NAME,
Expand All @@ -23,11 +24,11 @@ impl Manifest {
pub fn new(
db: &dyn SemanticGroup,
crate_ids: &[CrateId],
compiled_classes: HashMap<SmolStr, FieldElement>,
compiled_classes: HashMap<SmolStr, (FieldElement, Option<abi::Contract>)>,
) -> Self {
let mut manifest = Manifest(dojo_world::manifest::Manifest::default());

let world = compiled_classes.get(WORLD_CONTRACT_NAME).unwrap_or_else(|| {
let (world, world_abi) = compiled_classes.get(WORLD_CONTRACT_NAME).unwrap_or_else(|| {
panic!(
"{}",
format!(
Expand All @@ -36,20 +37,29 @@ impl Manifest {
)
);
});
let executor = compiled_classes.get(EXECUTOR_CONTRACT_NAME).unwrap_or_else(|| {
panic!(
"{}",
format!(
"Contract `{}` not found. Did you include `dojo` as a dependency?",
EXECUTOR_CONTRACT_NAME
)
);
});

manifest.0.world =
Contract { name: WORLD_CONTRACT_NAME.into(), address: None, class_hash: *world };
manifest.0.executor =
Contract { name: EXECUTOR_CONTRACT_NAME.into(), address: None, class_hash: *executor };
let (executor, executor_abi) =
compiled_classes.get(EXECUTOR_CONTRACT_NAME).unwrap_or_else(|| {
panic!(
"{}",
format!(
"Contract `{}` not found. Did you include `dojo` as a dependency?",
EXECUTOR_CONTRACT_NAME
)
);
});

manifest.0.world = Contract {
name: WORLD_CONTRACT_NAME.into(),
address: None,
class_hash: *world,
abi: world_abi.clone(),
};
manifest.0.executor = Contract {
name: EXECUTOR_CONTRACT_NAME.into(),
address: None,
class_hash: *executor,
abi: executor_abi.clone(),
};

for crate_id in crate_ids {
let modules = db.crate_modules(*crate_id);
Expand Down Expand Up @@ -86,7 +96,7 @@ impl Manifest {
db: &dyn SemanticGroup,
aux_data: &DojoAuxData,
module_id: ModuleId,
compiled_classes: &HashMap<SmolStr, FieldElement>,
compiled_classes: &HashMap<SmolStr, (FieldElement, Option<abi::Contract>)>,
) {
for component in &aux_data.components {
let component = component.clone();
Expand All @@ -96,7 +106,7 @@ impl Manifest {
{
// It needs the `Component` suffix because we are
// searching from the compiled contracts.
let class_hash = compiled_classes
let (class_hash, class_abi) = compiled_classes
.get(name.to_case(Case::Snake).as_str())
.with_context(|| format!("Component {name} not found in target."))
.unwrap();
Expand All @@ -105,6 +115,7 @@ impl Manifest {
name: component.name,
members: component.members,
class_hash: *class_hash,
abi: class_abi.clone(),
});
}
}
Expand All @@ -115,7 +126,7 @@ impl Manifest {
db: &dyn SemanticGroup,
aux_data: &DojoAuxData,
module_id: ModuleId,
compiled_classes: &HashMap<SmolStr, FieldElement>,
compiled_classes: &HashMap<SmolStr, (FieldElement, Option<abi::Contract>)>,
) -> Result<()> {
for SystemAuxData { name, dependencies } in &aux_data.systems {
if let Ok(Some(ModuleItemId::Submodule(submodule_id))) =
Expand Down Expand Up @@ -150,7 +161,7 @@ impl Manifest {
vec![Output { ty: signature.return_type.format(db) }]
};

let class_hash = compiled_classes
let (class_hash, class_abi) = compiled_classes
.get(name.as_str())
.with_context(|| format!("System {name} not found in target."))
.unwrap();
Expand All @@ -165,6 +176,7 @@ impl Manifest {
.sorted_by(|a, b| a.name.cmp(&b.name))
.cloned()
.collect::<Vec<_>>(),
abi: class_abi.clone(),
});
}
} else {
Expand Down
6 changes: 6 additions & 0 deletions crates/dojo-world/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::path::Path;

use ::serde::{Deserialize, Serialize};
use anyhow::{anyhow, Result};
use cairo_lang_starknet::abi;
use dojo_types::component::Member;
use dojo_types::system::Dependency;
use serde_with::serde_as;
Expand Down Expand Up @@ -46,6 +47,7 @@ pub struct Component {
pub members: Vec<Member>,
#[serde_as(as = "UfeHex")]
pub class_hash: FieldElement,
pub abi: Option<abi::Contract>,
}

/// System input ABI.
Expand Down Expand Up @@ -73,6 +75,7 @@ pub struct System {
#[serde_as(as = "UfeHex")]
pub class_hash: FieldElement,
pub dependencies: Vec<Dependency>,
pub abi: Option<abi::Contract>,
}

#[serde_as]
Expand All @@ -83,6 +86,7 @@ pub struct Contract {
pub address: Option<FieldElement>,
#[serde_as(as = "UfeHex")]
pub class_hash: FieldElement,
pub abi: Option<abi::Contract>,
}

#[serde_as]
Expand Down Expand Up @@ -209,11 +213,13 @@ impl Manifest {
name: WORLD_CONTRACT_NAME.into(),
class_hash: world_class_hash,
address: Some(world_address),
..Default::default()
},
executor: Contract {
name: EXECUTOR_CONTRACT_NAME.into(),
address: Some(executor_address),
class_hash: executor_class_hash,
..Default::default()
},
})
}
Expand Down
18 changes: 14 additions & 4 deletions crates/dojo-world/src/migration/world_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ fn no_diff_when_local_and_remote_are_equal() {
address: Some(77_u32.into()),
class_hash: 66_u32.into(),
name: WORLD_CONTRACT_NAME.into(),
..Default::default()
};

let executor_contract = Contract {
address: Some(88_u32.into()),
class_hash: 99_u32.into(),
name: EXECUTOR_CONTRACT_NAME.into(),
..Default::default()
};

let components =
vec![Component { members: vec![], name: "Component".into(), class_hash: 11_u32.into() }];
let components = vec![Component {
members: vec![],
name: "Component".into(),
class_hash: 11_u32.into(),
..Default::default()
}];

let systems =
vec![System { name: "System".into(), class_hash: 22_u32.into(), ..Default::default() }];
Expand Down Expand Up @@ -49,8 +55,12 @@ fn diff_when_local_and_remote_are_different() {
..Default::default()
};

let components =
vec![Component { members: vec![], name: "Component".into(), class_hash: 11_u32.into() }];
let components = vec![Component {
members: vec![],
name: "Component".into(),
class_hash: 11_u32.into(),
..Default::default()
}];

let systems =
vec![System { name: "System".into(), class_hash: 22_u32.into(), ..Default::default() }];
Expand Down
2 changes: 2 additions & 0 deletions crates/torii/core/src/sql_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ async fn test_load_from_manifest(pool: SqlitePool) {
name: "Test".into(),
members: vec![Member { name: "test".into(), ty: "u32".into(), key: false }],
class_hash: FieldElement::TWO,
..Default::default()
})
.await
.unwrap();
Expand All @@ -82,6 +83,7 @@ async fn test_load_from_manifest(pool: SqlitePool) {
outputs: vec![],
class_hash: FieldElement::THREE,
dependencies: vec![],
..Default::default()
})
.await
.unwrap();
Expand Down

0 comments on commit 9483a9e

Please sign in to comment.