1+ #[ cfg( feature = "os_input" ) ]
2+ use std:: collections:: HashMap ;
3+
4+ #[ cfg( feature = "os_input" ) ]
5+ use blake2:: Blake2s256 ;
6+ #[ cfg( feature = "os_input" ) ]
7+ use digest:: Digest ;
18use serde:: { Deserialize , Serialize } ;
29use starknet_api:: block:: BlockNumber ;
10+ #[ cfg( feature = "os_input" ) ]
11+ use starknet_api:: core:: { ClassHash , ContractAddress } ;
12+ #[ cfg( feature = "os_input" ) ]
13+ use starknet_api:: state:: StorageKey ;
314use starknet_patricia_storage:: storage_trait:: DbValue ;
415use starknet_types_core:: felt:: Felt ;
516
17+ #[ cfg( feature = "os_input" ) ]
18+ use crate :: block_committer:: input:: StarknetStorageKey ;
19+
620#[ derive( Clone , Debug , Default , Deserialize , Eq , PartialEq , Hash , Serialize ) ]
721pub struct DbBlockNumber ( pub BlockNumber ) ;
822
@@ -23,3 +37,44 @@ pub fn serialize_felt_no_packing(felt: Felt) -> DbValue {
2337pub fn deserialize_felt_no_packing ( value : & DbValue ) -> Felt {
2438 Felt :: from_bytes_be_slice ( & value. 0 )
2539}
40+
41+ /// Wire layout for [`accessed_keys_digest`]. Field order and sorting are part of the digest.
42+ #[ cfg( feature = "os_input" ) ]
43+ #[ derive( Serialize , Deserialize ) ]
44+ struct AccessedKeysCanonical {
45+ class_hashes : Vec < ClassHash > ,
46+ /// Contract trie reads (e.g. class / nonce), sorted.
47+ contract_addresses : Vec < ContractAddress > ,
48+ /// Storage-slot reads: sorted by contract address; each key list sorted by underlying felt.
49+ contract_storage : Vec < ( ContractAddress , Vec < StorageKey > ) > ,
50+ }
51+
52+ /// BLAKE2s-256 digest of canonical serialized accessed read keys (replay fingerprint).
53+ #[ cfg( feature = "os_input" ) ]
54+ pub fn accessed_keys_digest (
55+ class_hashes : & [ ClassHash ] ,
56+ contract_addresses : & [ ContractAddress ] ,
57+ contract_storage_keys : & HashMap < ContractAddress , Vec < StarknetStorageKey > > ,
58+ ) -> [ u8 ; 32 ] {
59+ let mut class_hashes: Vec < ClassHash > = class_hashes. iter ( ) . copied ( ) . collect ( ) ;
60+ class_hashes. sort ( ) ;
61+
62+ let mut contract_addresses: Vec < ContractAddress > = contract_addresses. iter ( ) . copied ( ) . collect ( ) ;
63+ contract_addresses. sort ( ) ;
64+
65+ let mut contract_storage: Vec < ( ContractAddress , Vec < StorageKey > ) > = contract_storage_keys
66+ . iter ( )
67+ . map ( |( addr, keys) | {
68+ let mut keys: Vec < StorageKey > = keys. iter ( ) . map ( |k| k. 0 ) . collect ( ) ;
69+ keys. sort_by_key ( |k| Felt :: from ( * k) ) ;
70+ ( * addr, keys)
71+ } )
72+ . collect ( ) ;
73+ contract_storage. sort_by_key ( |( addr, _) | * addr) ;
74+
75+ let canonical = AccessedKeysCanonical { class_hashes, contract_addresses, contract_storage } ;
76+ let bytes = bincode:: serialize ( & canonical) . expect ( "accessed keys bincode serialization" ) ;
77+
78+ let hash = Blake2s256 :: digest ( & bytes) ;
79+ hash. into ( )
80+ }
0 commit comments