Skip to content
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ apollo_reverts.path = "crates/apollo_reverts"
apollo_rpc.path = "crates/apollo_rpc"
apollo_rpc_execution.path = "crates/apollo_rpc_execution"
apollo_starknet_client.path = "crates/apollo_starknet_client"
apollo_starknet_os_program.path = "crates/apollo_starknet_os_program"
apollo_starknet_os_program = { path = "crates/apollo_starknet_os_program", version = "0.15.0-rc.0" }
apollo_state_reader.path = "crates/apollo_state_reader"
apollo_state_sync.path = "crates/apollo_state_sync"
apollo_state_sync_metrics.path = "crates/apollo_state_sync_metrics"
Expand Down
21 changes: 15 additions & 6 deletions crates/apollo_starknet_os_program/build/compile_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ use std::path::PathBuf;
use apollo_infra_utils::cairo0_compiler::{compile_cairo0_program, Cairo0CompilerError};
use apollo_infra_utils::compile_time_cargo_manifest_dir;

/// Compile the StarkNet OS program.
pub fn compile_starknet_os() -> Vec<u8> {
let cairo_root_path = PathBuf::from(compile_time_cargo_manifest_dir!()).join("src/cairo");
let os_main_path = cairo_root_path.join("starkware/starknet/core/os/os.cairo");
match compile_cairo0_program(os_main_path, cairo_root_path) {
fn compile_program(path_to_main_file: PathBuf) -> Vec<u8> {
match compile_cairo0_program(path_to_main_file, cairo_root_path()) {
Ok(bytes) => bytes,
Err(Cairo0CompilerError::Cairo0CompilerVersion(error)) => {
panic!(
Expand All @@ -18,7 +15,19 @@ pub fn compile_starknet_os() -> Vec<u8> {
)
}
Err(other_error) => {
panic!("Failed to compile the StarkNet OS program. Error:\n{other_error}.")
panic!("Failed to compile the program. Error:\n{other_error}.")
}
}
}

fn cairo_root_path() -> PathBuf {
PathBuf::from(compile_time_cargo_manifest_dir!()).join("src/cairo")
}

pub fn compile_starknet_os() -> Vec<u8> {
compile_program(cairo_root_path().join("starkware/starknet/core/os/os.cairo"))
}

pub fn compile_starknet_aggregator() -> Vec<u8> {
compile_program(cairo_root_path().join("starkware/starknet/core/aggregator/main.cairo"))
}
7 changes: 7 additions & 0 deletions crates/apollo_starknet_os_program/build/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ fn main() {
let starknet_os_bytes_path = out_dir.join("starknet_os_bytes");
std::fs::write(&starknet_os_bytes_path, &starknet_os_bytes)
.expect("Failed to write the compiled OS bytes to the output directory.");

println!("cargo::warning=Compiling Starknet aggregator program...");
let starknet_aggregator_bytes = compile_program::compile_starknet_aggregator();
println!("cargo::warning=Done. Writing compiled bytes to output directory.");
let starknet_aggregator_bytes_path = out_dir.join("starknet_aggregator_bytes");
std::fs::write(&starknet_aggregator_bytes_path, &starknet_aggregator_bytes)
.expect("Failed to write the compiled aggregator bytes to the output directory.");
}
10 changes: 8 additions & 2 deletions crates/apollo_starknet_os_program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::sync::LazyLock;

use cairo_vm::types::program::Program;

use crate::program_hash::ProgramHash;
use crate::program_hash::ProgramHashes;

pub mod program_hash;

Expand All @@ -15,12 +15,18 @@ pub static CAIRO_FILES_MAP: LazyLock<HashMap<String, String>> = LazyLock::new(||
});

pub const OS_PROGRAM_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/starknet_os_bytes"));
pub const AGGREGATOR_PROGRAM_BYTES: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/starknet_aggregator_bytes"));

pub static OS_PROGRAM: LazyLock<Program> = LazyLock::new(|| {
Program::from_bytes(OS_PROGRAM_BYTES, Some("main")).expect("Failed to load the OS bytes.")
});
pub static AGGREGATOR_PROGRAM: LazyLock<Program> = LazyLock::new(|| {
Program::from_bytes(AGGREGATOR_PROGRAM_BYTES, Some("main"))
.expect("Failed to load the aggregator bytes.")
});

pub static PROGRAM_HASH: LazyLock<ProgramHash> = LazyLock::new(|| {
pub static PROGRAM_HASHES: LazyLock<ProgramHashes> = LazyLock::new(|| {
// As the program hash file may not exist at runtime, it's contents must be included at compile
// time.
serde_json::from_str(include_str!("program_hash.json"))
Expand Down
6 changes: 4 additions & 2 deletions crates/apollo_starknet_os_program/src/program_hash.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"os": "0x1a07803807a087714c365cc2babcf19cf5ebc4d939cccc5df1e0019554c560d"
}
"os": "0x1a07803807a087714c365cc2babcf19cf5ebc4d939cccc5df1e0019554c560d",
"aggregator": "0x181986bfe23bbfdac56c40522bd5c2b1b64c824c74bd6722a3ccacc8cc888e2",
"aggregator_with_prefix": "0x1ae51bd7157e0754f1e1729806ad5579a7ac6926cd0c8dd342ad1e7a3758c2e"
}
51 changes: 37 additions & 14 deletions crates/apollo_starknet_os_program/src/program_hash.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use cairo_vm::types::builtin_name::BuiltinName;
use cairo_vm::types::errors::program_errors::ProgramError;
use cairo_vm::types::program::Program;
use serde::{Deserialize, Serialize};
use starknet_types_core::felt::Felt;
use starknet_types_core::hash::{Pedersen, StarkHash};

use crate::OS_PROGRAM;
use crate::{AGGREGATOR_PROGRAM, OS_PROGRAM};

#[cfg(test)]
#[path = "program_hash_test.rs"]
Expand All @@ -21,12 +22,29 @@ pub enum ProgramHashError {
}

#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct ProgramHash {
pub struct ProgramHashes {
pub os: Felt,
pub aggregator: Felt,
pub aggregator_with_prefix: Felt,
}

pub struct AggregatorHash {
pub with_prefix: Felt,
pub without_prefix: Felt,
}

const BOOTLOADER_VERSION: u8 = 0;

fn pad_to_32_bytes(data: &[u8]) -> [u8; 32] {
let mut padded = [0; 32];
let len = data.len();
if len > 32 {
panic!("Data length exceeds 32 bytes.");
}
padded[32 - len..].copy_from_slice(data);
padded
}

fn pedersen_hash_chain(data: Vec<Felt>) -> Felt {
let length = Felt::from(data.len());
vec![length]
Expand All @@ -37,8 +55,8 @@ fn pedersen_hash_chain(data: Vec<Felt>) -> Felt {
.expect("Hash data chain is not empty.")
}

pub fn compute_os_program_hash() -> Result<Felt, ProgramHashError> {
let builtins = OS_PROGRAM
fn compute_program_hash(program: &Program) -> Result<Felt, ProgramHashError> {
let builtins = program
.iter_builtins()
.map(|builtin| {
let builtin_bytes = builtin.to_str().to_string().into_bytes();
Expand All @@ -48,29 +66,34 @@ pub fn compute_os_program_hash() -> Result<Felt, ProgramHashError> {
name: builtin.to_str().to_string(),
})
} else {
let mut padded_builtin_bytes = [0].repeat(32 - builtin_bytes.len());
padded_builtin_bytes.extend(builtin_bytes);
Ok(Felt::from_bytes_be(
padded_builtin_bytes
.as_slice()
.try_into()
.expect("Padded bytes are 32 bytes long."),
))
Ok(Felt::from_bytes_be(&pad_to_32_bytes(&builtin_bytes)))
}
})
.collect::<Result<Vec<Felt>, _>>()?;
let program_header = vec![
Felt::from(BOOTLOADER_VERSION),
// TODO(Dori): When [available](https://github.com/lambdaclass/cairo-vm/pull/2101), use the
// Program::get_main() getter instead of the get_stripped_program() method.
Felt::from(OS_PROGRAM.get_stripped_program()?.main),
Felt::from(program.get_stripped_program()?.main),
Felt::from(builtins.len()),
];
let data = OS_PROGRAM
let data = program
.iter_data()
.map(|data| data.get_int().ok_or(ProgramHashError::UnexpectedRelocatable))
.collect::<Result<Vec<Felt>, _>>()?;

let data_chain: Vec<Felt> = program_header.into_iter().chain(builtins).chain(data).collect();
Ok(pedersen_hash_chain(data_chain))
}

pub fn compute_os_program_hash() -> Result<Felt, ProgramHashError> {
compute_program_hash(&OS_PROGRAM)
}

pub fn compute_aggregator_program_hash() -> Result<AggregatorHash, ProgramHashError> {
let hash = compute_program_hash(&AGGREGATOR_PROGRAM)?;
Ok(AggregatorHash {
with_prefix: Pedersen::hash(&Felt::from_bytes_be(&pad_to_32_bytes(b"AGGREGATOR")), &hash),
without_prefix: hash,
})
}
24 changes: 17 additions & 7 deletions crates/apollo_starknet_os_program/src/program_hash_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ use std::sync::LazyLock;

use apollo_infra_utils::compile_time_cargo_manifest_dir;

use crate::program_hash::{compute_os_program_hash, ProgramHash};
use crate::PROGRAM_HASH;
use crate::program_hash::{
compute_aggregator_program_hash,
compute_os_program_hash,
AggregatorHash,
ProgramHashes,
};
use crate::PROGRAM_HASHES;

static PROGRAM_HASH_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
PathBuf::from(compile_time_cargo_manifest_dir!()).join("src/program_hash.json")
Expand All @@ -14,18 +19,23 @@ static PROGRAM_HASH_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
/// JSON.
/// To fix this test, run the following command:
/// ```bash
/// FIX_PROGRAM_HASH=1 cargo test -p apollo_starknet_os_program test_program_hash
/// FIX_PROGRAM_HASH=1 cargo test -p apollo_starknet_os_program test_program_hashes
/// ```
#[test]
fn test_program_hash() {
let computed_hash = ProgramHash { os: compute_os_program_hash().unwrap() };
fn test_program_hashes() {
let AggregatorHash { with_prefix, without_prefix } = compute_aggregator_program_hash().unwrap();
let computed_hashes = ProgramHashes {
os: compute_os_program_hash().unwrap(),
aggregator: without_prefix,
aggregator_with_prefix: with_prefix,
};
if std::env::var("FIX_PROGRAM_HASH").is_ok() {
std::fs::write(
PROGRAM_HASH_PATH.as_path(),
serde_json::to_string_pretty(&computed_hash).unwrap(),
serde_json::to_string_pretty(&computed_hashes).unwrap(),
)
.unwrap_or_else(|error| panic!("Failed to write the program hash file: {error:?}."));
} else {
assert_eq!(computed_hash, *PROGRAM_HASH);
assert_eq!(computed_hashes, *PROGRAM_HASHES);
}
}
4 changes: 2 additions & 2 deletions crates/starknet_committer_and_os_cli/src/os_cli/commands.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fs;
use std::path::Path;

use apollo_starknet_os_program::{CAIRO_FILES_MAP, OS_PROGRAM_BYTES, PROGRAM_HASH};
use apollo_starknet_os_program::{CAIRO_FILES_MAP, OS_PROGRAM_BYTES, PROGRAM_HASHES};
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use cairo_vm::types::layout_name::LayoutName;
use cairo_vm::vm::runners::cairo_pie::CairoPie;
Expand Down Expand Up @@ -119,5 +119,5 @@ pub(crate) fn dump_program(output_path: String, program: ProgramToDump) {
}

pub(crate) fn dump_program_hashes(output_path: String) {
write_to_file(&output_path, &*PROGRAM_HASH);
write_to_file(&output_path, &*PROGRAM_HASHES);
}
8 changes: 4 additions & 4 deletions workspace_tests/version_integrity_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use toml_test_utils::{
};

const PARENT_BRANCH: &str = include_str!("../scripts/parent_branch.txt");
const MAIN_PARENT_BRANCH: &str = "main";
const MAIN_BRANCH: &str = "main";
const EXPECTED_MAIN_VERSION: &str = "0.0.0";

static ROOT_CRATES_FOR_PUBLISH: LazyLock<HashSet<&str>> =
LazyLock::new(|| HashSet::from(["blockifier"]));
LazyLock::new(|| HashSet::from(["blockifier", "apollo_starknet_os_program"]));
static CRATES_FOR_PUBLISH: LazyLock<HashSet<String>> = LazyLock::new(|| {
let publish_deps: HashSet<String> = ROOT_CRATES_FOR_PUBLISH
.iter()
Expand Down Expand Up @@ -224,12 +224,12 @@ fn test_no_features_in_workspace() {

#[test]
fn test_main_branch_is_versionless() {
if PARENT_BRANCH.trim() == MAIN_PARENT_BRANCH {
if PARENT_BRANCH.trim() == MAIN_BRANCH {
let workspace_version = ROOT_TOML.workspace_version();
assert_eq!(
workspace_version, EXPECTED_MAIN_VERSION,
"The workspace version should be '{EXPECTED_MAIN_VERSION}' when the parent branch is \
'{MAIN_PARENT_BRANCH}'; found {workspace_version}.",
'{MAIN_BRANCH}'; found {workspace_version}.",
);
}
}
Loading