Skip to content

Commit

Permalink
Add contract size limits warnings (#1855)
Browse files Browse the repository at this point in the history
Closes #1774
  • Loading branch information
DelevoXDG authored Jan 15, 2025
1 parent 152926a commit 67d6e75
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 4 deletions.
56 changes: 52 additions & 4 deletions scarb/src/compiler/compilers/starknet_contract/artifacts_writer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::compiler::compilers::starknet_contract::{ContractFileStemCalculator, ContractSelector};
use crate::compiler::compilers::Props;
use crate::compiler::helpers::write_json;
use crate::compiler::helpers::write_json_with_byte_count;
use crate::core::{PackageName, Workspace};
use crate::flock::Filesystem;
use cairo_lang_compiler::db::RootDatabase;
Expand All @@ -9,11 +9,17 @@ use cairo_lang_starknet::contract::ContractDeclaration;
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use cairo_lang_starknet_classes::contract_class::ContractClass;
use cairo_lang_utils::UpcastMut;
use indoc::formatdoc;
use itertools::{izip, Itertools};
use scarb_stable_hash::short_hash;
use serde::Serialize;
use smol_str::SmolStr;

const MAX_SIERRA_PROGRAM_FELTS: usize = 81290;
const MAX_CASM_PROGRAM_FELTS: usize = 81290;
const MAX_CONTRACT_CLASS_BYTES: usize = 4089446;
const MAX_COMPILED_CONTRACT_CLASS_BYTES: usize = 4089446;

#[derive(Debug, Serialize)]
struct StarknetArtifacts {
version: usize,
Expand Down Expand Up @@ -132,16 +138,58 @@ impl ArtifactsWriter {
);

if self.sierra {
let sierra_felts = class.sierra_program.len();
if sierra_felts > MAX_SIERRA_PROGRAM_FELTS {
ws.config().ui().warn(formatdoc! {r#"
Sierra program exceeds maximum byte-code size on Starknet:
{MAX_SIERRA_PROGRAM_FELTS} felts allowed. Actual size: {sierra_felts} felts.
"#});
}

let file_name = format!("{file_stem}{extension_prefix}.contract_class.json");
write_json(&file_name, "output file", &self.target_dir, ws, class)?;

let class_size = write_json_with_byte_count(
&file_name,
"output file",
&self.target_dir,
ws,
class,
)?;
if class_size > MAX_CONTRACT_CLASS_BYTES {
ws.config().ui().warn(formatdoc! {r#"
Contract class size exceeds maximum allowed size on Starknet:
{MAX_CONTRACT_CLASS_BYTES} bytes allowed. Actual size: {class_size} bytes.
"#});
}
artifact.artifacts.sierra = Some(file_name);
}

if self.casm {
if let Some(casm_class) = casm_class {
let casm_felts = casm_class.bytecode.len();
if casm_felts > MAX_CASM_PROGRAM_FELTS {
ws.config().ui().warn(formatdoc! {r#"
CASM program exceeds maximum byte-code size on Starknet:
{MAX_CASM_PROGRAM_FELTS} felts allowed. Actual size: {casm_felts} felts.
"#});
}

let file_name =
format!("{file_stem}{extension_prefix}.compiled_contract_class.json");
write_json(&file_name, "output file", &self.target_dir, ws, casm_class)?;

let compiled_class_size = write_json_with_byte_count(
&file_name,
"output file",
&self.target_dir,
ws,
casm_class,
)?;
if compiled_class_size > MAX_COMPILED_CONTRACT_CLASS_BYTES {
ws.config().ui().warn(formatdoc! {r#"
Compiled contract class size exceeds maximum allowed size on Starknet:
{MAX_COMPILED_CONTRACT_CLASS_BYTES} bytes allowed. Actual size: {compiled_class_size} bytes.
"#});
}
artifact.artifacts.casm = Some(file_name);
}
}
Expand All @@ -151,7 +199,7 @@ impl ArtifactsWriter {

artifacts.finish();

write_json(
write_json_with_byte_count(
&format!(
"{}{extension_prefix}.starknet_artifacts.json",
self.target_name
Expand Down
41 changes: 41 additions & 0 deletions scarb/src/compiler/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,32 @@ use itertools::Itertools;
use serde::Serialize;
use std::io::{BufWriter, Write};

pub struct CountingWriter<W> {
inner: W,
pub byte_count: usize,
}

impl<W: Write> CountingWriter<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
byte_count: 0,
}
}
}

impl<W: Write> Write for CountingWriter<W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let n = self.inner.write(buf)?;
self.byte_count += n;
Ok(n)
}

fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}

pub fn build_compiler_config<'c>(
db: &RootDatabase,
unit: &CairoCompilationUnit,
Expand Down Expand Up @@ -112,6 +138,21 @@ pub fn write_json(
Ok(())
}

pub fn write_json_with_byte_count(
file_name: &str,
description: &str,
target_dir: &Filesystem,
ws: &Workspace<'_>,
value: impl Serialize,
) -> Result<usize> {
let file = target_dir.create_rw(file_name, description, ws.config())?;
let file = BufWriter::new(&*file);
let mut writer = CountingWriter::new(file);
serde_json::to_writer(&mut writer, &value)
.with_context(|| format!("failed to serialize {file_name}"))?;
Ok(writer.byte_count)
}

pub fn write_string(
file_name: &str,
description: &str,
Expand Down

0 comments on commit 67d6e75

Please sign in to comment.