Skip to content

Commit 19be0db

Browse files
committed
starknet_committer: compute and store accessed keys digest
1 parent b0885bd commit 19be0db

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

crates/starknet_committer/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ license.workspace = true
77
description = "Computes and manages Starknet state."
88

99
[features]
10+
os_input = ["dep:bincode", "dep:blake2", "dep:digest"]
1011
testing = ["starknet_patricia/testing"]
1112

1213
[dependencies]
14+
bincode = { workspace = true, optional = true }
15+
blake2 = { workspace = true, optional = true }
16+
digest = { workspace = true, optional = true }
1317
apollo_config.workspace = true
1418
async-trait.workspace = true
1519
derive_more = { workspace = true, features = ["as_ref", "from", "into"] }

crates/starknet_committer/src/db/serde_db_utils.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
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;
18
use serde::{Deserialize, Serialize};
29
use 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;
314
use starknet_patricia_storage::storage_trait::DbValue;
415
use 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)]
721
pub struct DbBlockNumber(pub BlockNumber);
822

@@ -23,3 +37,44 @@ pub fn serialize_felt_no_packing(felt: Felt) -> DbValue {
2337
pub 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

Comments
 (0)