-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from starkware-libs/dafna/add-committer
chore: add committer
- Loading branch information
Showing
68 changed files
with
6,455 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
[package] | ||
name = "committer" | ||
version.workspace = true | ||
edition.workspace = true | ||
repository.workspace = true | ||
license-file.workspace = true | ||
description = "Computes and manages Starknet state." | ||
|
||
[lints] | ||
workspace = true | ||
|
||
[features] | ||
testing = [] | ||
|
||
[dev-dependencies] | ||
pretty_assertions.workspace = true | ||
rand.workspace = true | ||
rstest.workspace = true | ||
|
||
[dependencies] | ||
async-recursion.workspace = true | ||
bisection.workspace = true | ||
derive_more.workspace = true | ||
ethnum.workspace = true | ||
hex.workspace = true | ||
rand.workspace = true | ||
rstest.workspace = true | ||
serde.workspace = true | ||
serde_json.workspace = true | ||
starknet-types-core.workspace = true | ||
strum.workspace = true | ||
strum_macros.workspace = true | ||
thiserror.workspace = true | ||
tokio.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub mod commit; | ||
pub mod errors; | ||
pub mod input; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use crate::block_committer::errors::BlockCommitmentError; | ||
use crate::block_committer::input::{Input, StateDiff}; | ||
use crate::patricia_merkle_tree::filled_tree::forest::FilledForestImpl; | ||
use crate::patricia_merkle_tree::node_data::leaf::LeafDataImpl; | ||
use crate::patricia_merkle_tree::original_skeleton_tree::skeleton_forest::{ | ||
OriginalSkeletonForest, OriginalSkeletonForestImpl, | ||
}; | ||
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeImpl; | ||
use crate::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunctionImpl; | ||
use crate::patricia_merkle_tree::updated_skeleton_tree::skeleton_forest::{ | ||
UpdatedSkeletonForest, UpdatedSkeletonForestImpl, | ||
}; | ||
use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl; | ||
use crate::storage::map_storage::MapStorage; | ||
|
||
#[allow(dead_code)] | ||
type BlockCommitmentResult<T> = Result<T, BlockCommitmentError<LeafDataImpl>>; | ||
|
||
#[allow(dead_code)] | ||
pub async fn commit_block(input: Input) -> BlockCommitmentResult<FilledForestImpl> { | ||
let mut original_forest = OriginalSkeletonForestImpl::<OriginalSkeletonTreeImpl>::create( | ||
MapStorage::from(input.storage), | ||
input.contracts_trie_root_hash, | ||
input.classes_trie_root_hash, | ||
&input.current_contracts_trie_leaves, | ||
&input.state_diff, | ||
)?; | ||
|
||
let updated_forest = UpdatedSkeletonForestImpl::<UpdatedSkeletonTreeImpl>::create( | ||
&mut original_forest, | ||
&StateDiff::skeleton_classes_updates(&input.state_diff.class_hash_to_compiled_class_hash), | ||
&input.state_diff.skeleton_storage_updates(), | ||
&input.current_contracts_trie_leaves, | ||
&input.state_diff.address_to_class_hash, | ||
&input.state_diff.address_to_nonce, | ||
)?; | ||
|
||
Ok( | ||
FilledForestImpl::create::<UpdatedSkeletonTreeImpl, TreeHashFunctionImpl>( | ||
updated_forest, | ||
input.state_diff.actual_storage_updates(), | ||
StateDiff::actual_classes_updates(&input.state_diff.class_hash_to_compiled_class_hash), | ||
&input.current_contracts_trie_leaves, | ||
&input.state_diff.address_to_class_hash, | ||
&input.state_diff.address_to_nonce, | ||
) | ||
.await?, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use thiserror::Error; | ||
|
||
use crate::{forest_errors::ForestError, patricia_merkle_tree::node_data::leaf::LeafData}; | ||
|
||
#[derive(Debug, Error)] | ||
pub enum BlockCommitmentError<L: LeafData> { | ||
#[error(transparent)] | ||
ForestError(#[from] ForestError<L>), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
use crate::felt::Felt; | ||
use crate::hash::hash_trait::HashOutput; | ||
use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; | ||
use crate::patricia_merkle_tree::node_data::leaf::{ | ||
ContractState, LeafDataImpl, LeafModifications, SkeletonLeaf, | ||
}; | ||
use crate::patricia_merkle_tree::types::NodeIndex; | ||
use crate::storage::storage_trait::{StorageKey, StorageValue}; | ||
use std::collections::{HashMap, HashSet}; | ||
|
||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
// TODO(Nimrod, 1/6/2024): Swap to starknet-types-core types once implemented. | ||
pub struct ContractAddress(pub Felt); | ||
|
||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
// TODO(Nimrod, 1/6/2024): Swap to starknet-types-core types once implemented. | ||
pub struct StarknetStorageKey(pub Felt); | ||
|
||
#[derive(Debug, Eq, PartialEq)] | ||
pub struct StarknetStorageValue(pub Felt); | ||
|
||
#[derive(Debug, Default, Eq, PartialEq)] | ||
pub struct StateDiff { | ||
pub address_to_class_hash: HashMap<ContractAddress, ClassHash>, | ||
pub address_to_nonce: HashMap<ContractAddress, Nonce>, | ||
pub class_hash_to_compiled_class_hash: HashMap<ClassHash, CompiledClassHash>, | ||
pub storage_updates: | ||
HashMap<ContractAddress, HashMap<StarknetStorageKey, StarknetStorageValue>>, | ||
} | ||
|
||
#[derive(Debug, Eq, PartialEq)] | ||
pub struct Input { | ||
pub storage: HashMap<StorageKey, StorageValue>, | ||
/// All relevant information for the state diff commitment. | ||
pub state_diff: StateDiff, | ||
pub current_contracts_trie_leaves: HashMap<ContractAddress, ContractState>, | ||
pub contracts_trie_root_hash: HashOutput, | ||
pub classes_trie_root_hash: HashOutput, | ||
} | ||
|
||
impl StateDiff { | ||
pub(crate) fn accessed_addresses(&self) -> HashSet<&ContractAddress> { | ||
HashSet::from_iter( | ||
self.address_to_class_hash | ||
.keys() | ||
.chain(self.address_to_nonce.keys()) | ||
.chain(self.storage_updates.keys()), | ||
) | ||
} | ||
|
||
/// For each modified contract calculates it's actual storage updates. | ||
pub(crate) fn skeleton_storage_updates( | ||
&self, | ||
) -> HashMap<ContractAddress, LeafModifications<SkeletonLeaf>> { | ||
self.accessed_addresses() | ||
.iter() | ||
.map(|address| { | ||
let updates = match self.storage_updates.get(address) { | ||
Some(inner_updates) => inner_updates | ||
.iter() | ||
.map(|(key, value)| { | ||
( | ||
NodeIndex::from_starknet_storage_key(key), | ||
SkeletonLeaf::from(value.0), | ||
) | ||
}) | ||
.collect(), | ||
None => HashMap::new(), | ||
}; | ||
(**address, updates) | ||
}) | ||
.collect() | ||
} | ||
|
||
pub(crate) fn skeleton_classes_updates( | ||
class_hash_to_compiled_class_hash: &HashMap<ClassHash, CompiledClassHash>, | ||
) -> LeafModifications<SkeletonLeaf> { | ||
class_hash_to_compiled_class_hash | ||
.iter() | ||
.map(|(class_hash, compiled_class_hash)| { | ||
( | ||
NodeIndex::from_class_hash(class_hash), | ||
SkeletonLeaf::from(compiled_class_hash.0), | ||
) | ||
}) | ||
.collect() | ||
} | ||
|
||
pub(crate) fn actual_storage_updates( | ||
&self, | ||
) -> HashMap<ContractAddress, LeafModifications<LeafDataImpl>> { | ||
self.accessed_addresses() | ||
.iter() | ||
.map(|address| { | ||
let updates = match self.storage_updates.get(address) { | ||
Some(inner_updates) => inner_updates | ||
.iter() | ||
.map(|(key, value)| { | ||
( | ||
NodeIndex::from_starknet_storage_key(key), | ||
LeafDataImpl::StorageValue(value.0), | ||
) | ||
}) | ||
.collect(), | ||
None => HashMap::new(), | ||
}; | ||
(**address, updates) | ||
}) | ||
.collect() | ||
} | ||
|
||
pub(crate) fn actual_classes_updates( | ||
class_hash_to_compiled_class_hash: &HashMap<ClassHash, CompiledClassHash>, | ||
) -> LeafModifications<LeafDataImpl> { | ||
class_hash_to_compiled_class_hash | ||
.iter() | ||
.map(|(class_hash, compiled_class_hash)| { | ||
( | ||
NodeIndex::from_class_hash(class_hash), | ||
LeafDataImpl::CompiledClassHash(*compiled_class_hash), | ||
) | ||
}) | ||
.collect() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
use crate::patricia_merkle_tree::errors::TypesError; | ||
use ethnum::U256; | ||
use serde::{Deserialize, Serialize}; | ||
use starknet_types_core::felt::{Felt as StarknetTypesFelt, FromStrError}; | ||
|
||
#[derive( | ||
Eq, | ||
PartialEq, | ||
Clone, | ||
Copy, | ||
Debug, | ||
Default, | ||
Hash, | ||
derive_more::Add, | ||
derive_more::Sub, | ||
PartialOrd, | ||
Ord, | ||
Serialize, | ||
Deserialize, | ||
)] | ||
pub struct Felt(pub StarknetTypesFelt); | ||
|
||
#[macro_export] | ||
macro_rules! impl_from { | ||
($to:ty, $from:ty, $($other_from: ty),+) => { | ||
$crate::impl_from!($to, $from); | ||
$crate::impl_from!($to $(, $other_from)*); | ||
}; | ||
($to:ty, $from:ty) => { | ||
impl From<$from> for $to { | ||
fn from(value: $from) -> Self { | ||
Self(value.into()) | ||
} | ||
} | ||
}; | ||
} | ||
impl_from!(Felt, StarknetTypesFelt, u128, u8); | ||
|
||
impl From<Felt> for StarknetTypesFelt { | ||
fn from(felt: Felt) -> Self { | ||
felt.0 | ||
} | ||
} | ||
|
||
impl From<&Felt> for U256 { | ||
fn from(felt: &Felt) -> Self { | ||
U256::from_be_bytes(felt.to_bytes_be()) | ||
} | ||
} | ||
|
||
#[cfg(feature = "testing")] | ||
impl TryFrom<&U256> for Felt { | ||
type Error = TypesError<U256>; | ||
fn try_from(value: &U256) -> Result<Self, Self::Error> { | ||
if *value > U256::from(&Felt::MAX) { | ||
return Err(TypesError::ConversionError { | ||
from: *value, | ||
to: "Felt", | ||
reason: "value is bigger than felt::max", | ||
}); | ||
} | ||
Ok(Self::from_bytes_be(&value.to_be_bytes())) | ||
} | ||
} | ||
|
||
impl std::ops::Mul for Felt { | ||
type Output = Self; | ||
|
||
fn mul(self, rhs: Self) -> Self { | ||
Self(self.0 * rhs.0) | ||
} | ||
} | ||
|
||
impl Felt { | ||
pub const ZERO: Felt = Felt(StarknetTypesFelt::ZERO); | ||
#[allow(dead_code)] | ||
pub(crate) const ONE: Felt = Felt(StarknetTypesFelt::ONE); | ||
#[allow(dead_code)] | ||
pub(crate) const TWO: Felt = Felt(StarknetTypesFelt::TWO); | ||
#[allow(dead_code)] | ||
pub(crate) const THREE: Felt = Felt(StarknetTypesFelt::THREE); | ||
pub const MAX: Felt = Felt(StarknetTypesFelt::MAX); | ||
|
||
pub fn from_bytes_be_slice(bytes: &[u8]) -> Self { | ||
Self(StarknetTypesFelt::from_bytes_be_slice(bytes)) | ||
} | ||
|
||
/// Raises `self` to the power of `exponent`. | ||
#[allow(dead_code)] | ||
pub(crate) fn pow(&self, exponent: impl Into<u128>) -> Self { | ||
Self(self.0.pow(exponent.into())) | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub(crate) fn bits(&self) -> u8 { | ||
self.0 | ||
.bits() | ||
.try_into() | ||
// Should not fail as it takes less than 252 bits to represent a felt. | ||
.expect("Unexpected error occurred when extracting bits of a Felt.") | ||
} | ||
|
||
pub fn from_bytes_be(bytes: &[u8; 32]) -> Self { | ||
StarknetTypesFelt::from_bytes_be(bytes).into() | ||
} | ||
|
||
pub fn to_bytes_be(self) -> [u8; 32] { | ||
self.0.to_bytes_be() | ||
} | ||
|
||
/// Parse a hex-encoded number into `Felt`. | ||
pub fn from_hex(hex_string: &str) -> Result<Self, FromStrError> { | ||
Ok(StarknetTypesFelt::from_hex(hex_string)?.into()) | ||
} | ||
|
||
pub fn to_hex(&self) -> String { | ||
self.0.to_hex_string() | ||
} | ||
|
||
// Convert to a 64-character hexadecimal string without the "0x" prefix. | ||
pub fn to_fixed_hex_string(&self) -> String { | ||
// Zero-pad the remaining string | ||
self.0 | ||
.to_fixed_hex_string() | ||
.strip_prefix("0x") | ||
.unwrap_or("0") | ||
.to_string() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use crate::block_committer::input::ContractAddress; | ||
use crate::patricia_merkle_tree::filled_tree::errors::FilledTreeError; | ||
use crate::patricia_merkle_tree::node_data::leaf::{LeafData, LeafDataImpl}; | ||
use crate::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; | ||
use crate::patricia_merkle_tree::updated_skeleton_tree::errors::UpdatedSkeletonTreeError; | ||
|
||
use thiserror::Error; | ||
use tokio::task::JoinError; | ||
|
||
pub(crate) type ForestResult<T> = Result<T, ForestError<LeafDataImpl>>; | ||
|
||
#[derive(Debug, Error)] | ||
pub enum ForestError<L: LeafData> { | ||
#[error(transparent)] | ||
OriginalSkeleton(#[from] OriginalSkeletonTreeError), | ||
#[error(transparent)] | ||
UpdatedSkeleton(#[from] UpdatedSkeletonTreeError), | ||
#[error(transparent)] | ||
Filled(#[from] FilledTreeError<L>), | ||
#[error("Missing input: Couldn't find the storage trie's current state of address {0:?}")] | ||
MissingContractCurrentState(ContractAddress), | ||
#[error("Can't build storage trie's updated skeleton, because there is no original skeleton at address {0:?}")] | ||
MissingOriginalSkeleton(ContractAddress), | ||
#[error("Can't fill storage trie, because there is no updated skeleton at address {0:?}")] | ||
MissingUpdatedSkeleton(ContractAddress), | ||
#[error(transparent)] | ||
JoinError(#[from] JoinError), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod hash_trait; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use crate::felt::Felt; | ||
|
||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] | ||
pub struct HashOutput(pub Felt); | ||
|
||
impl HashOutput { | ||
#[allow(dead_code)] | ||
pub(crate) const ZERO: HashOutput = HashOutput(Felt::ZERO); | ||
pub(crate) const ROOT_OF_EMPTY_TREE: HashOutput = Self::ZERO; | ||
} |
Oops, something went wrong.