neo_devpack_solidity/storage_key.rs
1//! Storage Key Computation Module
2//!
3//! Computes deterministic storage keys for Neo N3 smart contract state
4//! variables, matching the layout actually emitted by the compiler's
5//! bytecode (see `src/cli/bytecode/bytecode_helpers/storage/mapping.rs`).
6//!
7//! # Key Derivation (production scheme)
8//!
9//! - Base slot of a state variable: `SHA256(variable_name)` —
10//! [`compute_state_slot`]. Struct fields use the same hash over the
11//! qualified `"Struct::field"` name (see `src/ir/build/inference.rs`).
12//! - Mapping entry / dynamic-array element: derived ITERATIVELY per nesting
13//! level on-chain as `slot = keccak256(StdLib.serialize(key) || slot)`,
14//! where `serialize` is Neo's StdLib binary serializer applied to the
15//! canonicalized key stack item and the current slot is appended LAST.
16//! Dynamic arrays store their length at the base slot and element `i` at
17//! `keccak256(serialize(i) || slot)`.
18//! - Struct field inside a mapping value: `keccak256(field_key || slot)`
19//! where `field_key = SHA256("Struct::field")`.
20//!
21//! The mapping-entry derivation depends on Neo's StdLib `serialize` native
22//! call (the serialized form embeds the stack-item type byte), so it cannot
23//! be reproduced faithfully off-chain without replicating Neo's
24//! BinarySerializer byte-for-byte. A previous `derive_mapping_slot` /
25//! `KeyFragment` API in this module implemented a DIFFERENT, untyped
26//! SHA-256-based scheme that matched nothing the compiler emits; it has been
27//! removed so off-chain consumers cannot silently compute wrong keys.
28
29use sha2::{Digest, Sha256};
30
31/// Compute the canonical storage slot hash for a state variable name.
32///
33/// The returned value is the 32-byte SHA-256 digest of the UTF-8 name.
34pub fn compute_state_slot(name: &str) -> [u8; 32] {
35 let mut hasher = Sha256::new();
36 hasher.update(name.as_bytes());
37 let digest = hasher.finalize();
38 let mut out = [0u8; 32];
39 out.copy_from_slice(&digest);
40 out
41}
42
43#[cfg(test)]
44mod tests;