Skip to content

Commit 660a732

Browse files
authored
fix: wrong type for bytecode_segment_lengths (#651)
1 parent 95fb1b6 commit 660a732

File tree

7 files changed

+110
-37
lines changed

7 files changed

+110
-37
lines changed

starknet-core/src/types/contract/mod.rs

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ pub struct CompiledClass {
8383
/// Represents the structure of the bytecode segments, using a nested list of segment lengths.
8484
/// For example, [2, [3, 4]] represents a bytecode with 2 segments, the first is a leaf of
8585
/// length 2 and the second is a node with 2 children of lengths 3 and 4.
86-
#[serde(default, skip_serializing_if = "Vec::is_empty")]
87-
pub bytecode_segment_lengths: Vec<IntOrList>,
86+
#[serde(default, skip_serializing_if = "Option::is_none")]
87+
pub bytecode_segment_lengths: Option<IntOrList>,
8888
/// Hints for non-determinism.
8989
pub hints: Vec<Hint>,
9090
/// Same as `hints` but represented in Python code, which can be generated by the compiler but
@@ -658,42 +658,45 @@ impl CompiledClass {
658658
);
659659

660660
// Hashes bytecode
661-
hasher.update(if self.bytecode_segment_lengths.is_empty() {
662-
// Pre-Sierra-1.5.0 compiled classes
663-
poseidon_hash_many(&self.bytecode)
664-
} else {
665-
// `bytecode_segment_lengths` was added since Sierra 1.5.0 and changed hash calculation.
666-
// This implementation here is basically a direct translation of the Python code from
667-
// `cairo-lang` v0.13.1. The goal was simply to have a working implementation as quickly
668-
// as possible. There should be some optimizations to be made here.
669-
// TODO: review how this can be optimized
670-
671-
// NOTE: this looks extremely inefficient. Maybe just use a number for tracking instead?
672-
let mut rev_visited_pcs: Vec<u64> = (0..(self.bytecode.len() as u64)).rev().collect();
673-
674-
let (res, total_len) = Self::create_bytecode_segment_structure_inner(
675-
&self.bytecode,
676-
&IntOrList::List(self.bytecode_segment_lengths.clone()),
677-
&mut rev_visited_pcs,
678-
&mut 0,
679-
)?;
680-
681-
if total_len != self.bytecode.len() as u64 {
682-
return Err(ComputeClassHashError::BytecodeSegmentLengthMismatch(
683-
BytecodeSegmentLengthMismatchError {
684-
segment_length: total_len as usize,
685-
bytecode_length: self.bytecode.len(),
686-
},
687-
));
688-
}
689-
if !rev_visited_pcs.is_empty() {
690-
return Err(ComputeClassHashError::PcOutOfRange(PcOutOfRangeError {
691-
pc: rev_visited_pcs[rev_visited_pcs.len() - 1],
692-
}));
693-
}
661+
hasher.update(
662+
if let Some(bytecode_segment_lengths) = self.bytecode_segment_lengths.clone() {
663+
// `bytecode_segment_lengths` was added since Sierra 1.5.0 and changed hash calculation.
664+
// This implementation here is basically a direct translation of the Python code from
665+
// `cairo-lang` v0.13.1. The goal was simply to have a working implementation as quickly
666+
// as possible. There should be some optimizations to be made here.
667+
// TODO: review how this can be optimized
668+
669+
// NOTE: this looks extremely inefficient. Maybe just use a number for tracking instead?
670+
let mut rev_visited_pcs: Vec<u64> =
671+
(0..(self.bytecode.len() as u64)).rev().collect();
672+
673+
let (res, total_len) = Self::create_bytecode_segment_structure_inner(
674+
&self.bytecode,
675+
&bytecode_segment_lengths,
676+
&mut rev_visited_pcs,
677+
&mut 0,
678+
)?;
679+
680+
if total_len != self.bytecode.len() as u64 {
681+
return Err(ComputeClassHashError::BytecodeSegmentLengthMismatch(
682+
BytecodeSegmentLengthMismatchError {
683+
segment_length: total_len as usize,
684+
bytecode_length: self.bytecode.len(),
685+
},
686+
));
687+
}
688+
if !rev_visited_pcs.is_empty() {
689+
return Err(ComputeClassHashError::PcOutOfRange(PcOutOfRangeError {
690+
pc: rev_visited_pcs[rev_visited_pcs.len() - 1],
691+
}));
692+
}
694693

695-
res.hash()
696-
});
694+
res.hash()
695+
} else {
696+
// Pre-Sierra-1.5.0 compiled classes
697+
poseidon_hash_many(&self.bytecode)
698+
},
699+
);
697700

698701
Ok(hasher.finalize())
699702
}
@@ -1022,6 +1025,7 @@ mod tests {
10221025
include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_sierra.txt"),
10231026
include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_sierra.txt"),
10241027
include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_sierra.txt"),
1028+
include_str!("../../../test-data/contracts/cairo2.6/artifacts/trivial_sierra.txt"),
10251029
] {
10261030
let direct_deser = serde_json::from_str::<SierraClass>(raw_artifact).unwrap();
10271031
let via_contract_artifact = match serde_json::from_str::<ContractArtifact>(raw_artifact)
@@ -1047,6 +1051,7 @@ mod tests {
10471051
include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_compiled.txt"),
10481052
include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_compiled.txt"),
10491053
include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"),
1054+
include_str!("../../../test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt"),
10501055
] {
10511056
let direct_deser = serde_json::from_str::<CompiledClass>(raw_artifact).unwrap();
10521057
let via_contract_artifact = match serde_json::from_str::<ContractArtifact>(raw_artifact)
@@ -1133,6 +1138,12 @@ mod tests {
11331138
include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"),
11341139
include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20.hashes.json"),
11351140
),
1141+
(
1142+
include_str!(
1143+
"../../../test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt"
1144+
),
1145+
include_str!("../../../test-data/contracts/cairo2.6/artifacts/trivial.hashes.json"),
1146+
),
11361147
] {
11371148
let compiled_class = serde_json::from_str::<CompiledClass>(raw_artifact).unwrap();
11381149
let computed_hash = compiled_class.class_hash().unwrap();
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"sierra_class_hash": "0x7585639b4e793743860f2761d81e070157ae8d0fc8e518a8cd9069eb2a40010",
3+
"compiled_class_hash": "0x317d3ac2cf840e487b6d0014a75f0cf507dff0bc143c710388e323487089bfa"
4+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"prime": "0x800000000000011000000000000000000000000000000000000000000000001",
3+
"compiler_version": "2.6.2",
4+
"bytecode": [],
5+
"bytecode_segment_lengths": 0,
6+
"hints": [],
7+
"entry_points_by_type": {
8+
"EXTERNAL": [],
9+
"L1_HANDLER": [],
10+
"CONSTRUCTOR": []
11+
}
12+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"sierra_program": [
3+
"0x1",
4+
"0x5",
5+
"0x0",
6+
"0x2",
7+
"0x6",
8+
"0x2",
9+
"0x1",
10+
"0xff",
11+
"0x0",
12+
"0x4",
13+
"0x0"
14+
],
15+
"sierra_program_debug_info": {
16+
"type_names": [],
17+
"libfunc_names": [],
18+
"user_func_names": []
19+
},
20+
"contract_class_version": "0.1.0",
21+
"entry_points_by_type": {
22+
"EXTERNAL": [],
23+
"L1_HANDLER": [],
24+
"CONSTRUCTOR": []
25+
},
26+
"abi": [
27+
{
28+
"type": "event",
29+
"name": "trivial::trivial::Trivial::Event",
30+
"kind": "enum",
31+
"variants": []
32+
}
33+
]
34+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#[starknet::contract]
2+
mod Trivial {
3+
#[storage]
4+
struct Storage {}
5+
6+
#[abi(embed_v0)]
7+
fn something(ref self: ContractState) -> felt252 {
8+
1
9+
}
10+
}

starknet-core/test-data/contracts/cairo2.6/docker_entry_compile.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ compile () {
1111
}
1212

1313
compile "/contracts/erc20.cairo" "/artifacts/erc20"
14+
compile "/contracts/trivial.cairo" "/artifacts/trivial"

starknet-core/test-data/contracts/cairo2.6/docker_entry_hashes.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ hash () {
99
}
1010

1111
hash "/artifacts/erc20"
12+
hash "/artifacts/trivial"

0 commit comments

Comments
 (0)