starknet-devnet-types 0.8.0-rc.1

Starknet types for the devnet
Documentation
use num_bigint::BigUint;
use serde::Serialize;
use starknet_types_core::felt::Felt;

use super::block::BlockRoot;
use crate::contract_address::ContractAddress;
use crate::felt::{BlockHash, ClassHash, CompiledClassHash, Nonce};
use crate::patricia_key::PatriciaKey;

pub type Balance = BigUint;

#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "testing", derive(serde::Deserialize), serde(deny_unknown_fields))]
pub enum StateUpdateResult {
    StateUpdate(StateUpdate),
    PreConfirmedStateUpdate(PreConfirmedStateUpdate),
}

impl StateUpdateResult {
    pub fn get_state_diff(&self) -> &ThinStateDiff {
        match self {
            StateUpdateResult::StateUpdate(s) => &s.state_diff,
            StateUpdateResult::PreConfirmedStateUpdate(s) => &s.state_diff,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "testing", derive(serde::Deserialize), serde(deny_unknown_fields))]
pub struct StateUpdate {
    pub block_hash: BlockHash,
    pub new_root: BlockRoot,
    pub old_root: BlockRoot,
    pub state_diff: ThinStateDiff,
}

impl StateUpdate {
    /// New and old root are not computed - Devnet does not store block data in a tree.
    pub fn new(block_hash: Felt, state_diff: ThinStateDiff) -> Self {
        Self { block_hash, new_root: Felt::default(), old_root: Felt::default(), state_diff }
    }
}

#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "testing", derive(serde::Deserialize), serde(deny_unknown_fields))]
pub struct PreConfirmedStateUpdate {
    pub old_root: Option<BlockRoot>,
    pub state_diff: ThinStateDiff,
}

#[derive(Debug, Default, Clone, Serialize)]
#[cfg_attr(
    feature = "testing",
    derive(serde::Deserialize, Eq, PartialEq),
    serde(deny_unknown_fields)
)]
pub struct ThinStateDiff {
    pub deployed_contracts: Vec<DeployedContract>,
    pub storage_diffs: Vec<StorageDiff>,
    pub declared_classes: Vec<ClassHashPair>,
    pub deprecated_declared_classes: Vec<ClassHash>,
    pub nonces: Vec<ContractNonce>,
    pub replaced_classes: Vec<ReplacedClasses>,
    // In Devnet, this will always be None as:
    // 1) There is no migration process when starting Devnet without forking as state is empty.
    // 2) When forking, there is no RPC support for fetching compiled classes from origin (yet).
    //    This is added for adherence to Starknet spec and/or future use.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub migrated_compiled_classes: Option<Vec<ClassHashPair>>,
}

impl ThinStateDiff {
    pub fn len(&self) -> usize {
        let mut result = 0usize;
        result += self.deployed_contracts.len();
        result += self.declared_classes.len();
        result += self.deprecated_declared_classes.len();
        result += self.nonces.len();
        for diff in &self.storage_diffs {
            result += diff.storage_entries.len();
        }
        result
    }
    pub fn is_empty(&self) -> bool {
        self.deployed_contracts.is_empty()
            && self.declared_classes.is_empty()
            && self.deprecated_declared_classes.is_empty()
            && self.nonces.is_empty()
            && self.storage_diffs.iter().all(|s| s.storage_entries.is_empty())
    }

    pub fn filter_by_address(&self, contract_addresses: Vec<ContractAddress>) -> Self {
        let mut result = self.clone();
        result.deployed_contracts.retain(|c| contract_addresses.contains(&c.address));
        result.storage_diffs.retain(|s| contract_addresses.contains(&s.address));
        result.nonces.retain(|n| contract_addresses.contains(&n.contract_address));
        result.replaced_classes.retain(|r| contract_addresses.contains(&r.contract_address));
        result
    }
}

/// A deployed contract in Starknet.
#[derive(Debug, Default, Clone, Serialize)]
#[cfg_attr(
    feature = "testing",
    derive(serde::Deserialize, Eq, PartialEq),
    serde(deny_unknown_fields)
)]
pub struct DeployedContract {
    pub address: ContractAddress,
    pub class_hash: ClassHash,
}

/// Storage differences in Starknet.
// Invariant: Storage keys are strictly increasing. In particular, no key appears twice.
#[derive(Debug, Default, Clone, Serialize)]
#[cfg_attr(
    feature = "testing",
    derive(serde::Deserialize, Eq, PartialEq),
    serde(deny_unknown_fields)
)]
pub struct StorageDiff {
    pub address: ContractAddress,
    pub storage_entries: Vec<StorageEntry>,
}

/// A storage entry in a contract.
#[derive(Debug, Default, Clone, Serialize)]
#[cfg_attr(
    feature = "testing",
    derive(serde::Deserialize, Eq, PartialEq),
    serde(deny_unknown_fields)
)]
pub struct StorageEntry {
    pub key: PatriciaKey,
    pub value: Felt,
}

#[derive(Debug, Clone, Default, Serialize)]
#[cfg_attr(feature = "testing", derive(PartialEq, Eq, serde::Deserialize))]
pub struct ClassHashPair {
    pub class_hash: ClassHash,
    pub compiled_class_hash: CompiledClassHash,
}

#[derive(Debug, Clone, Default, Serialize)]
#[cfg_attr(feature = "testing", derive(Eq, PartialEq, serde::Deserialize))]
pub struct ReplacedClasses {
    pub contract_address: ContractAddress,
    pub class_hash: ClassHash,
}

/// The nonce of a Starknet contract.
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(
    feature = "testing",
    derive(serde::Deserialize, Eq, PartialEq),
    serde(deny_unknown_fields)
)]
pub struct ContractNonce {
    pub contract_address: ContractAddress,
    pub nonce: Nonce,
}