Skip to main content

starknet_devnet_types/rpc/
state.rs

1use num_bigint::BigUint;
2use serde::Serialize;
3use starknet_types_core::felt::Felt;
4
5use super::block::BlockRoot;
6use crate::contract_address::ContractAddress;
7use crate::felt::{BlockHash, ClassHash, CompiledClassHash, Nonce};
8use crate::patricia_key::PatriciaKey;
9
10pub type Balance = BigUint;
11
12#[derive(Debug, Clone, Serialize)]
13#[cfg_attr(feature = "testing", derive(serde::Deserialize), serde(deny_unknown_fields))]
14pub enum StateUpdateResult {
15    StateUpdate(StateUpdate),
16    PreConfirmedStateUpdate(PreConfirmedStateUpdate),
17}
18
19impl StateUpdateResult {
20    pub fn get_state_diff(&self) -> &ThinStateDiff {
21        match self {
22            StateUpdateResult::StateUpdate(s) => &s.state_diff,
23            StateUpdateResult::PreConfirmedStateUpdate(s) => &s.state_diff,
24        }
25    }
26}
27
28#[derive(Debug, Clone, Serialize)]
29#[cfg_attr(feature = "testing", derive(serde::Deserialize), serde(deny_unknown_fields))]
30pub struct StateUpdate {
31    pub block_hash: BlockHash,
32    pub new_root: BlockRoot,
33    pub old_root: BlockRoot,
34    pub state_diff: ThinStateDiff,
35}
36
37impl StateUpdate {
38    /// New and old root are not computed - Devnet does not store block data in a tree.
39    pub fn new(block_hash: Felt, state_diff: ThinStateDiff) -> Self {
40        Self { block_hash, new_root: Felt::default(), old_root: Felt::default(), state_diff }
41    }
42}
43
44#[derive(Debug, Clone, Serialize)]
45#[cfg_attr(feature = "testing", derive(serde::Deserialize), serde(deny_unknown_fields))]
46pub struct PreConfirmedStateUpdate {
47    pub old_root: Option<BlockRoot>,
48    pub state_diff: ThinStateDiff,
49}
50
51#[derive(Debug, Default, Clone, Serialize)]
52#[cfg_attr(
53    feature = "testing",
54    derive(serde::Deserialize, Eq, PartialEq),
55    serde(deny_unknown_fields)
56)]
57pub struct ThinStateDiff {
58    pub deployed_contracts: Vec<DeployedContract>,
59    pub storage_diffs: Vec<StorageDiff>,
60    pub declared_classes: Vec<ClassHashPair>,
61    pub deprecated_declared_classes: Vec<ClassHash>,
62    pub nonces: Vec<ContractNonce>,
63    pub replaced_classes: Vec<ReplacedClasses>,
64    // In Devnet, this will always be None as:
65    // 1) There is no migration process when starting Devnet without forking as state is empty.
66    // 2) When forking, there is no RPC support for fetching compiled classes from origin (yet).
67    //    This is added for adherence to Starknet spec and/or future use.
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub migrated_compiled_classes: Option<Vec<ClassHashPair>>,
70}
71
72impl ThinStateDiff {
73    pub fn len(&self) -> usize {
74        let mut result = 0usize;
75        result += self.deployed_contracts.len();
76        result += self.declared_classes.len();
77        result += self.deprecated_declared_classes.len();
78        result += self.nonces.len();
79        for diff in &self.storage_diffs {
80            result += diff.storage_entries.len();
81        }
82        result
83    }
84    pub fn is_empty(&self) -> bool {
85        self.deployed_contracts.is_empty()
86            && self.declared_classes.is_empty()
87            && self.deprecated_declared_classes.is_empty()
88            && self.nonces.is_empty()
89            && self.storage_diffs.iter().all(|s| s.storage_entries.is_empty())
90    }
91
92    pub fn filter_by_address(&self, contract_addresses: Vec<ContractAddress>) -> Self {
93        let mut result = self.clone();
94        result.deployed_contracts.retain(|c| contract_addresses.contains(&c.address));
95        result.storage_diffs.retain(|s| contract_addresses.contains(&s.address));
96        result.nonces.retain(|n| contract_addresses.contains(&n.contract_address));
97        result.replaced_classes.retain(|r| contract_addresses.contains(&r.contract_address));
98        result
99    }
100}
101
102/// A deployed contract in Starknet.
103#[derive(Debug, Default, Clone, Serialize)]
104#[cfg_attr(
105    feature = "testing",
106    derive(serde::Deserialize, Eq, PartialEq),
107    serde(deny_unknown_fields)
108)]
109pub struct DeployedContract {
110    pub address: ContractAddress,
111    pub class_hash: ClassHash,
112}
113
114/// Storage differences in Starknet.
115// Invariant: Storage keys are strictly increasing. In particular, no key appears twice.
116#[derive(Debug, Default, Clone, Serialize)]
117#[cfg_attr(
118    feature = "testing",
119    derive(serde::Deserialize, Eq, PartialEq),
120    serde(deny_unknown_fields)
121)]
122pub struct StorageDiff {
123    pub address: ContractAddress,
124    pub storage_entries: Vec<StorageEntry>,
125}
126
127/// A storage entry in a contract.
128#[derive(Debug, Default, Clone, Serialize)]
129#[cfg_attr(
130    feature = "testing",
131    derive(serde::Deserialize, Eq, PartialEq),
132    serde(deny_unknown_fields)
133)]
134pub struct StorageEntry {
135    pub key: PatriciaKey,
136    pub value: Felt,
137}
138
139#[derive(Debug, Clone, Default, Serialize)]
140#[cfg_attr(feature = "testing", derive(PartialEq, Eq, serde::Deserialize))]
141pub struct ClassHashPair {
142    pub class_hash: ClassHash,
143    pub compiled_class_hash: CompiledClassHash,
144}
145
146#[derive(Debug, Clone, Default, Serialize)]
147#[cfg_attr(feature = "testing", derive(Eq, PartialEq, serde::Deserialize))]
148pub struct ReplacedClasses {
149    pub contract_address: ContractAddress,
150    pub class_hash: ClassHash,
151}
152
153/// The nonce of a Starknet contract.
154#[derive(Debug, Clone, Serialize)]
155#[cfg_attr(
156    feature = "testing",
157    derive(serde::Deserialize, Eq, PartialEq),
158    serde(deny_unknown_fields)
159)]
160pub struct ContractNonce {
161    pub contract_address: ContractAddress,
162    pub nonce: Nonce,
163}