1+ #[ cfg( feature = "os_input" ) ]
2+ use blake2:: Blake2s256 ;
3+ #[ cfg( feature = "os_input" ) ]
4+ use digest:: Digest ;
15use serde:: { Deserialize , Serialize } ;
26use starknet_api:: block:: BlockNumber ;
7+ #[ cfg( feature = "os_input" ) ]
8+ use starknet_patricia:: patricia_merkle_tree:: types:: NodeIndex ;
39use starknet_patricia_storage:: storage_trait:: DbValue ;
410use starknet_types_core:: felt:: Felt ;
511
12+ #[ cfg( feature = "os_input" ) ]
13+ use crate :: patricia_merkle_tree:: tree:: SortedLeavesRequest ;
14+
615#[ derive( Clone , Debug , Default , Deserialize , Eq , PartialEq , Hash , Serialize ) ]
716pub struct DbBlockNumber ( pub BlockNumber ) ;
817
@@ -23,3 +32,51 @@ pub fn serialize_felt_no_packing(felt: Felt) -> DbValue {
2332pub fn deserialize_felt_no_packing ( value : & DbValue ) -> Felt {
2433 Felt :: from_bytes_be_slice ( & value. 0 )
2534}
35+
36+ /// BLAKE2s-256 digest over a deterministic encoding of [`SortedLeavesRequest`].
37+ ///
38+ /// The hashed payload is a concatenation length-prefixed big-endian 32-byte
39+ /// [`NodeIndex`] values (`idx.0.to_be_bytes()`), in this order:
40+ ///
41+ /// 1. Classes trie — `len(classes_sorted)` then each class leaf index (already sorted).
42+ /// 2. Contracts trie — `len(contracts_sorted)` then each contract leaf index (already sorted).
43+ /// 3. Storage tries — `len(storage_sorted)` then, for each contract index in ascending order: the
44+ /// contract index, `len(storage slot indices)` for that contract, then each storage slot index
45+ /// (already sorted within the contract).
46+ #[ cfg( feature = "os_input" ) ]
47+ pub fn accessed_keys_digest ( sorted : & SortedLeavesRequest < ' _ > ) -> [ u8 ; 32 ] {
48+ let mut payload = Vec :: new ( ) ;
49+
50+ let class = sorted. class_sorted . get_indices ( ) ;
51+ payload. extend_from_slice ( & encode_usize ( class. len ( ) ) ) ;
52+ for idx in class {
53+ payload. extend_from_slice ( & idx. 0 . to_be_bytes ( ) ) ;
54+ }
55+
56+ let contract = sorted. contract_sorted . get_indices ( ) ;
57+ payload. extend_from_slice ( & encode_usize ( contract. len ( ) ) ) ;
58+ for idx in contract {
59+ payload. extend_from_slice ( & idx. 0 . to_be_bytes ( ) ) ;
60+ }
61+
62+ let mut contract_indices: Vec < NodeIndex > = sorted. storage_sorted . keys ( ) . copied ( ) . collect ( ) ;
63+ contract_indices. sort_unstable ( ) ;
64+
65+ payload. extend_from_slice ( & encode_usize ( contract_indices. len ( ) ) ) ;
66+ for contract_idx in contract_indices {
67+ let sorted_slots = sorted. storage_sorted . get ( & contract_idx) . unwrap ( ) ;
68+ payload. extend_from_slice ( & contract_idx. 0 . to_be_bytes ( ) ) ;
69+ let slot_indices = sorted_slots. get_indices ( ) ;
70+ payload. extend_from_slice ( & encode_usize ( slot_indices. len ( ) ) ) ;
71+ for slot in slot_indices {
72+ payload. extend_from_slice ( & slot. 0 . to_be_bytes ( ) ) ;
73+ }
74+ }
75+
76+ Blake2s256 :: digest ( & payload) . into ( )
77+ }
78+
79+ #[ cfg( feature = "os_input" ) ]
80+ fn encode_usize ( n : usize ) -> [ u8 ; 8 ] {
81+ u64:: try_from ( n) . expect ( "accessed leaf count exceeds u64::MAX" ) . to_be_bytes ( )
82+ }
0 commit comments