Skip to content

Commit

Permalink
feat: store contract abi and source in contract metadata (starkware-l…
Browse files Browse the repository at this point in the history
…ibs#1682)

sozo: store ABI and source in metadata registry

This PR updates the `sozo build` command to save ABI and expanded source files,
into the `target` directory, for the world contract and every user contracts.

These ABI and source files are then uploaded as IPFS artifacts in the `ResourceMetadata`
registry, for the world, models and contracts.
  • Loading branch information
remybar authored Apr 12, 2024
1 parent 9a814ad commit e9fab2c
Show file tree
Hide file tree
Showing 19 changed files with 1,271 additions and 174 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bin/sozo/src/commands/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ impl DevArgs {
let env_metadata = if config.manifest_path().exists() {
let ws = scarb::ops::read_workspace(config.manifest_path(), config)?;

dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned())
dojo_metadata_from_workspace(&ws).env().cloned()
} else {
None
};
Expand Down
2 changes: 1 addition & 1 deletion bin/sozo/src/commands/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl MigrateArgs {
let ws = scarb::ops::read_workspace(config.manifest_path(), config)?;

let env_metadata = if config.manifest_path().exists() {
dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned())
dojo_metadata_from_workspace(&ws).env().cloned()
} else {
None
};
Expand Down
2 changes: 1 addition & 1 deletion bin/sozo/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn load_metadata_from_config(config: &Config) -> Result<Option<Environment>,
let env_metadata = if config.manifest_path().exists() {
let ws = scarb::ops::read_workspace(config.manifest_path(), config)?;

dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned())
dojo_metadata_from_workspace(&ws).env().cloned()
} else {
None
};
Expand Down
2 changes: 1 addition & 1 deletion crates/dojo-lang/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ cairo-lang-debug.workspace = true
cairo-lang-defs.workspace = true
cairo-lang-diagnostics.workspace = true
cairo-lang-filesystem.workspace = true
cairo-lang-formatter.workspace = true
cairo-lang-lowering.workspace = true
cairo-lang-parser.workspace = true
cairo-lang-plugins.workspace = true
Expand Down Expand Up @@ -50,7 +51,6 @@ tracing.workspace = true
url = "2.2.2"

[dev-dependencies]
cairo-lang-formatter.workspace = true
cairo-lang-semantic.workspace = true
cairo-lang-test-utils.workspace = true
dojo-test-utils = { path = "../dojo-test-utils" }
Expand Down
36 changes: 31 additions & 5 deletions crates/dojo-lang/src/compiler.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::io::Write;
use std::iter::zip;
use std::ops::DerefMut;

Expand All @@ -8,13 +9,14 @@ use cairo_lang_defs::db::DefsGroup;
use cairo_lang_defs::ids::{ModuleId, ModuleItemId};
use cairo_lang_filesystem::db::FilesGroup;
use cairo_lang_filesystem::ids::{CrateId, CrateLongId};
use cairo_lang_formatter::format_string;
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_starknet::plugin::aux_data::StarkNetContractAuxData;
use cairo_lang_utils::UpcastMut;
use camino::Utf8PathBuf;
use camino::{Utf8Path, Utf8PathBuf};
use convert_case::{Case, Casing};
use dojo_world::manifest::{
AbiFormat, Class, ComputedValueEntrypoint, DojoContract, DojoModel, Manifest, ManifestMethods,
Expand Down Expand Up @@ -46,6 +48,8 @@ pub const ABIS_DIR: &str = "abis";
pub const CONTRACTS_DIR: &str = "contracts";
pub const MODELS_DIR: &str = "models";

pub const SOURCES_DIR: &str = "src";

pub(crate) const LOG_TARGET: &str = "dojo_lang::compiler";

#[cfg(test)]
Expand Down Expand Up @@ -87,6 +91,8 @@ impl Compiler for DojoCompiler {
) -> Result<()> {
let props: Props = unit.target().props()?;
let target_dir = unit.target_dir(ws);
let sources_dir = target_dir.child(Utf8Path::new(SOURCES_DIR));

let compiler_config = build_compiler_config(&unit, ws);

let mut main_crate_ids = collect_main_crate_ids(&unit, db);
Expand Down Expand Up @@ -118,11 +124,31 @@ impl Compiler for DojoCompiler {

for (decl, class) in zip(contracts, classes) {
let contract_full_path = decl.module_id().full_path(db.upcast_mut());
let file_name = format!("{contract_full_path}.json");

let mut file = target_dir.open_rw(file_name.clone(), "output file", ws.config())?;
serde_json::to_writer_pretty(file.deref_mut(), &class)
.with_context(|| format!("failed to serialize contract: {contract_full_path}"))?;
// save expanded contract source file
if let Ok(file_id) = db.module_main_file(decl.module_id()) {
if let Some(file_content) = db.file_content(file_id) {
let src_file_name = format!("{contract_full_path}.cairo").replace("::", "_");

let mut file =
sources_dir.open_rw(src_file_name.clone(), "source file", ws.config())?;
file.write(format_string(db, file_content.to_string()).as_bytes())
.with_context(|| {
format!("failed to serialize contract source: {contract_full_path}")
})?;
} else {
return Err(anyhow!("failed to get source file content: {contract_full_path}"));
}
} else {
return Err(anyhow!("failed to get source file: {contract_full_path}"));
}

// save JSON artifact file
let file_name = format!("{contract_full_path}.json");
let mut file = target_dir.open_rw(file_name.clone(), "class file", ws.config())?;
serde_json::to_writer_pretty(file.deref_mut(), &class).with_context(|| {
format!("failed to serialize contract artifact: {contract_full_path}")
})?;

let class_hash = compute_class_hash_of_contract_class(&class).with_context(|| {
format!("problem computing class hash for contract `{contract_full_path}`")
Expand Down
41 changes: 28 additions & 13 deletions crates/dojo-test-utils/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,40 @@ use scarb::ops;
use scarb_ui::Verbosity;

pub fn build_test_config(path: &str) -> anyhow::Result<Config> {
build_full_test_config(path, true)
}

pub fn build_full_test_config(path: &str, override_dirs: bool) -> anyhow::Result<Config> {
let mut compilers = CompilerRepository::empty();
compilers.add(Box::new(DojoCompiler)).unwrap();

let cairo_plugins = CairoPluginRepository::default();
let path = Utf8PathBuf::from_path_buf(path.into()).unwrap();

let cache_dir = TempDir::new().unwrap();
let config_dir = TempDir::new().unwrap();
let target_dir = TempDir::new().unwrap();
if override_dirs {
let cache_dir = TempDir::new().unwrap();
let config_dir = TempDir::new().unwrap();
let target_dir = TempDir::new().unwrap();

let path = Utf8PathBuf::from_path_buf(path.into()).unwrap();
Config::builder(path.canonicalize_utf8().unwrap())
.global_cache_dir_override(Some(Utf8Path::from_path(cache_dir.path()).unwrap()))
.global_config_dir_override(Some(Utf8Path::from_path(config_dir.path()).unwrap()))
.target_dir_override(Some(Utf8Path::from_path(target_dir.path()).unwrap().to_path_buf()))
.ui_verbosity(Verbosity::Verbose)
.log_filter_directive(env::var_os("SCARB_LOG"))
.compilers(compilers)
.cairo_plugins(cairo_plugins.into())
.build()
Config::builder(path.canonicalize_utf8().unwrap())
.global_cache_dir_override(Some(Utf8Path::from_path(cache_dir.path()).unwrap()))
.global_config_dir_override(Some(Utf8Path::from_path(config_dir.path()).unwrap()))
.target_dir_override(Some(
Utf8Path::from_path(target_dir.path()).unwrap().to_path_buf(),
))
.ui_verbosity(Verbosity::Verbose)
.log_filter_directive(env::var_os("SCARB_LOG"))
.compilers(compilers)
.cairo_plugins(cairo_plugins.into())
.build()
} else {
Config::builder(path.canonicalize_utf8().unwrap())
.ui_verbosity(Verbosity::Verbose)
.log_filter_directive(env::var_os("SCARB_LOG"))
.compilers(compilers)
.cairo_plugins(cairo_plugins.into())
.build()
}
}

pub fn corelib() -> PathBuf {
Expand Down
Loading

0 comments on commit e9fab2c

Please sign in to comment.