diff --git a/.github/workflows/prove_blocks.yml b/.github/workflows/prove_blocks.yml index 5b423885..55401a2a 100644 --- a/.github/workflows/prove_blocks.yml +++ b/.github/workflows/prove_blocks.yml @@ -51,3 +51,9 @@ jobs: PATHFINDER_RPC_URL: ${{ secrets.PATHFINDER_RPC_URL }} run: | cargo test --release --package prove_block --test prove_block -- test_prove_selected_blocks --show-output --ignored + + - name: Class hashes + env: + PATHFINDER_RPC_URL: ${{ secrets.PATHFINDER_RPC_URL }} + run: | + cargo test --release --package prove_block --test hash_tests -- test_recompute_class_hash --show-output --ignored diff --git a/Cargo.toml b/Cargo.toml index eec0b155..5ab27df0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ cairo-lang-starknet-classes = { version = "=2.7.1" } cairo-lang-utils = { version = "=2.7.1" } cairo-lang-casm = { version = "=2.7.1" } cairo-type-derive = { version = "0.1.0", path = "crates/cairo-type-derive" } -cairo-vm = { git = "https://github.com/Moonsong-Labs/cairo-vm", branch = "notlesh/segment-arena-relocation-fix", features = ["cairo-1-hints", "extensive_hints", "mod_builtin"] } +cairo-vm = { git = "https://github.com/Moonsong-Labs/cairo-vm", rev = "56b68b50944ecb3123a168218ea7b8b8e23f9be8", features = ["cairo-1-hints", "extensive_hints", "mod_builtin"] } clap = { version = "4.5.4", features = ["derive"] } c-kzg = { version = "1.0.3" } env_logger = "0.11.3" diff --git a/crates/bin/prove_block/tests/hash_tests.rs b/crates/bin/prove_block/tests/hash_tests.rs new file mode 100644 index 00000000..faab40f4 --- /dev/null +++ b/crates/bin/prove_block/tests/hash_tests.rs @@ -0,0 +1,37 @@ +use rpc_client::RpcClient; +use rstest::rstest; +use starknet::core::types::BlockId; +use starknet::providers::Provider; +use starknet_os_types::compiled_class::GenericCompiledClass; +use starknet_os_types::deprecated_compiled_class::GenericDeprecatedCompiledClass; +use starknet_types_core::felt::Felt; + +#[rstest] +// Contract address 0x41a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf +#[case::correct_hash_computation_0("0x07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69", 78720)] +// Contract address 0x7a3c142b1ef242f093642604c2ac2259da0efa3a0517715c34a722ba2ecd048 +#[case::correct_hash_computation_1("0x5c478ee27f2112411f86f207605b2e2c58cdb647bac0df27f660ef2252359c6", 30000)] +#[ignore = "Requires a running Pathfinder node"] +#[tokio::test(flavor = "multi_thread")] +async fn test_recompute_class_hash(#[case] class_hash_str: String, #[case] block_number: u64) { + let endpoint = std::env::var("PATHFINDER_RPC_URL").expect("Missing PATHFINDER_RPC_URL in env"); + let class_hash = Felt::from_hex(&class_hash_str).unwrap(); + let block_id = BlockId::Number(block_number); + + let rpc_client = RpcClient::new(&endpoint); + let contract_class = rpc_client.starknet_rpc().get_class(block_id, class_hash).await.unwrap(); + + let compiled_class = if let starknet::core::types::ContractClass::Legacy(legacy_cc) = contract_class { + let compiled_class = GenericDeprecatedCompiledClass::try_from(legacy_cc).unwrap(); + GenericCompiledClass::Cairo0(compiled_class) + } else { + panic!("Test intended to test Legacy contracts"); + }; + + let recomputed_class_hash = Felt::from(compiled_class.class_hash().unwrap()); + + println!("Class hash: {:#x}", class_hash); + println!("Recomputed class hash: {:#x}", recomputed_class_hash); + + assert_eq!(class_hash, recomputed_class_hash); +} diff --git a/crates/bin/prove_block/tests/prove_block.rs b/crates/bin/prove_block/tests/prove_block.rs index 0e3e483b..db2b3a16 100644 --- a/crates/bin/prove_block/tests/prove_block.rs +++ b/crates/bin/prove_block/tests/prove_block.rs @@ -43,12 +43,16 @@ use rstest::rstest; #[case::declare_and_deploy_in_same_block(169206)] #[case::dest_ptr_not_a_relocatable(155140)] #[case::dest_ptr_not_a_relocatable_2(155830)] +#[case::inconsistent_cairo0_class_hash_0(30000)] +#[case::inconsistent_cairo0_class_hash_1(204936)] #[ignore = "Requires a running Pathfinder node"] #[tokio::test(flavor = "multi_thread")] async fn test_prove_selected_blocks(#[case] block_number: u64) { let endpoint = std::env::var("PATHFINDER_RPC_URL").expect("Missing PATHFINDER_RPC_URL in env"); - prove_block(block_number, &endpoint, LayoutName::all_cairo) + let (pie, _output) = prove_block(block_number, &endpoint, LayoutName::all_cairo) .await .map_err(debug_prove_error) - .expect("Block could not be proven"); + .expect("OS failed to generate Cairo Pie"); + + pie.run_validity_checks().expect("Cairo Pie run validity checks failed"); } diff --git a/crates/starknet-os-types/src/starknet_core_addons.rs b/crates/starknet-os-types/src/starknet_core_addons.rs index 20e2b1ac..1029f3d3 100644 --- a/crates/starknet-os-types/src/starknet_core_addons.rs +++ b/crates/starknet-os-types/src/starknet_core_addons.rs @@ -3,8 +3,8 @@ use std::io::Read; use flate2::read::GzDecoder; use starknet_core::types::contract::legacy::{ - LegacyContractClass, LegacyEntrypointOffset, RawLegacyAbiEntry, RawLegacyEntryPoint, RawLegacyEntryPoints, - RawLegacyEvent, RawLegacyFunction, RawLegacyL1Handler, RawLegacyMember, RawLegacyStruct, + LegacyContractClass, LegacyEntrypointOffset, RawLegacyAbiEntry, RawLegacyConstructor, RawLegacyEntryPoint, + RawLegacyEntryPoints, RawLegacyEvent, RawLegacyFunction, RawLegacyL1Handler, RawLegacyMember, RawLegacyStruct, }; use starknet_core::types::{ CompressedLegacyContractClass, LegacyContractAbiEntry, LegacyContractEntryPoint, LegacyEntryPointsByType, @@ -13,14 +13,17 @@ use starknet_core::types::{ fn raw_abi_entry_from_legacy_function_abi_entry(entry: LegacyFunctionAbiEntry) -> RawLegacyAbiEntry { match entry.r#type { - LegacyFunctionAbiType::Function | LegacyFunctionAbiType::Constructor => { - RawLegacyAbiEntry::Function(RawLegacyFunction { - inputs: entry.inputs, - name: entry.name, - outputs: entry.outputs, - state_mutability: entry.state_mutability, - }) - } + LegacyFunctionAbiType::Function => RawLegacyAbiEntry::Function(RawLegacyFunction { + inputs: entry.inputs, + name: entry.name, + outputs: entry.outputs, + state_mutability: entry.state_mutability, + }), + LegacyFunctionAbiType::Constructor => RawLegacyAbiEntry::Constructor(RawLegacyConstructor { + inputs: entry.inputs, + name: entry.name, + outputs: entry.outputs, + }), LegacyFunctionAbiType::L1Handler => RawLegacyAbiEntry::L1Handler(RawLegacyL1Handler { inputs: entry.inputs, name: entry.name, @@ -53,7 +56,7 @@ fn raw_legacy_abi_entry_from_legacy_contract_abi_entry( fn raw_legacy_entrypoint_from_legacy_entrypoint(legacy_entry_point: LegacyContractEntryPoint) -> RawLegacyEntryPoint { RawLegacyEntryPoint { - offset: LegacyEntrypointOffset::U64AsHex(legacy_entry_point.offset), + offset: LegacyEntrypointOffset::U64AsInt(legacy_entry_point.offset), selector: legacy_entry_point.selector, } } diff --git a/pyproject.toml b/pyproject.toml index 22f0774e..b297a586 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ readme = "README.md" python = "^3.9" ecdsa = "^0.18.0" fastecdsa = "^2.3.0" -sympy = "^1.12" +sympy = "~1.12" cairo-lang = "0.13.1" [build-system] diff --git a/tests/integration/common/transaction_utils.rs b/tests/integration/common/transaction_utils.rs index c3bf1766..f4ad6de7 100644 --- a/tests/integration/common/transaction_utils.rs +++ b/tests/integration/common/transaction_utils.rs @@ -920,7 +920,9 @@ where Err(_) => { println!("exception:\n{:#?}", result); } - _ => {} + Ok((pie, _output)) => { + pie.run_validity_checks().expect("Validity check failed"); + } } result