diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 2f653bc132..589b50a125 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -78,7 +78,7 @@ jobs: sudo apt-get install -y clang llvm libudev-dev protobuf-compiler - name: Build the project run: | - cargo build --release --workspace --features madara-state-root + cargo build --release --workspace - name: Run benchmark run: | cd benchmarking diff --git a/.github/workflows/rust-build.yml b/.github/workflows/rust-build.yml index fcb1db56dd..986c74d427 100644 --- a/.github/workflows/rust-build.yml +++ b/.github/workflows/rust-build.yml @@ -34,4 +34,4 @@ jobs: - name: Build the project run: | - cargo build --release --workspace --features madara-state-root + cargo build --release --workspace diff --git a/CHANGELOG.md b/CHANGELOG.md index 0efd857081..8f8edd40c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - ci: fix docker and binaries build - ci: don't enforce changelog on PR's with label `dependencies` - feat: rebase of core deps and 0.12.1 +- chore: remove global state root ## v0.1.0 diff --git a/crates/client/rpc-core/src/lib.rs b/crates/client/rpc-core/src/lib.rs index 7660ef484e..a8fcca28b1 100644 --- a/crates/client/rpc-core/src/lib.rs +++ b/crates/client/rpc-core/src/lib.rs @@ -15,8 +15,6 @@ use serde_with::serde_as; mod constants; pub mod utils; -pub mod types; - use starknet_core::serde::unsigned_field_element::UfeHex; use starknet_core::types::{ BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, @@ -26,8 +24,6 @@ use starknet_core::types::{ StateUpdate, SyncStatusType, Transaction, }; -use crate::types::{RpcGetProofInput, RpcGetProofOutput}; - #[serde_as] #[derive(Serialize, Deserialize)] pub struct Felt(#[serde_as(as = "UfeHex")] pub FieldElement); @@ -140,9 +136,4 @@ pub trait StarknetRpcApi { /// Returns the receipt of a transaction by transaction hash. #[method(name = "getTransactionReceipt")] fn get_transaction_receipt(&self, transaction_hash: FieldElement) -> RpcResult; - - /// Returns all the necessary data to trustlessly verify storage slots for a particular - /// contract. - #[method(name = "getProof")] - fn get_proof(&self, get_proof_input: RpcGetProofInput) -> RpcResult; } diff --git a/crates/client/rpc-core/src/types.rs b/crates/client/rpc-core/src/types.rs deleted file mode 100644 index fdb3d60b5c..0000000000 --- a/crates/client/rpc-core/src/types.rs +++ /dev/null @@ -1,58 +0,0 @@ -use mp_starknet::crypto::merkle_patricia_tree::merkle_tree::ProofNode; -use serde::{Deserialize, Serialize}; -use serde_with::skip_serializing_none; -use starknet_core::types::{BlockId, FieldElement}; - -#[derive(Deserialize, Debug, PartialEq, Eq)] -pub struct RpcGetProofInput { - /// Block to prove - pub block_id: BlockId, - /// Address of the contract to prove the storage of - pub contract_address: FieldElement, - /// Storage keys to be proven - /// More info can be found [here](https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-storage/) - /// storage_var address is the sn_keccak of the name hashed with the pedersen hash of the keys - /// - /// e.g balance_of(key1: felt, key2: felt) -> pedersen("balance_of", pedersen("key1", - /// pedersen("key2"))) - pub keys: Vec, -} - -/// Holds the membership/non-membership of a contract and its associated contract contract if the -/// contract exists. -#[derive(Debug, Serialize)] -#[skip_serializing_none] -pub struct RpcGetProofOutput { - /// The global state commitment for Starknet 0.11.0 blocks onwards, if absent the hash - /// of the first node in the [contract_proof](RpcGetProofOutput#contract_proof) is the global - /// state commitment. - pub state_commitment: Option, - /// Required to verify that the hash of the class commitment and the root of the - /// [contract_proof](RpcGetProofOutput::contract_proof) matches the - /// [state_commitment](Self#state_commitment). Present only for Starknet blocks 0.11.0 onwards. - pub class_commitment: Option, - - /// Membership / Non-membership proof for the queried contract - pub contract_proof: Vec, - - /// Additional contract data if it exists. - pub contract_data: Option, -} - -/// Holds the data and proofs for a specific contract. -#[derive(Debug, Serialize)] -pub struct ContractData { - /// Required to verify the contract state hash to contract root calculation. - pub class_hash: FieldElement, - /// Required to verify the contract state hash to contract root calculation. - pub nonce: FieldElement, - - /// Root of the Contract state tree - pub root: FieldElement, - - /// This is currently just a constant = 0, however it might change in the future. - pub contract_state_hash_version: FieldElement, - - /// The proofs associated with the queried storage values - pub storage_proofs: Vec>, -} diff --git a/crates/client/rpc/src/constants.rs b/crates/client/rpc/src/constants.rs index f50ff4be45..5997a15cd4 100644 --- a/crates/client/rpc/src/constants.rs +++ b/crates/client/rpc/src/constants.rs @@ -2,5 +2,3 @@ pub const MAX_EVENTS_KEYS: usize = 100; /// Maximum number of events that can be fetched in a single chunk for the `get_events` RPC. pub const MAX_EVENTS_CHUNK_SIZE: usize = 1000; -/// Maximum number of keys that can be used to query a storage proof using `getProof` RPC. -pub const MAX_STORAGE_PROOF_KEYS_BY_QUERY: usize = 100; diff --git a/crates/client/rpc/src/lib.rs b/crates/client/rpc/src/lib.rs index 80c924f7e9..11f59d745e 100644 --- a/crates/client/rpc/src/lib.rs +++ b/crates/client/rpc/src/lib.rs @@ -14,13 +14,11 @@ use std::sync::Arc; use errors::StarknetRpcApiError; use jsonrpsee::core::{async_trait, RpcResult}; use log::error; -use mc_rpc_core::types::{ContractData, RpcGetProofInput, RpcGetProofOutput}; pub use mc_rpc_core::utils::*; use mc_rpc_core::Felt; pub use mc_rpc_core::StarknetRpcApiServer; use mc_storage::OverrideHandle; use mc_transaction_pool::{ChainApi, Pool}; -use mp_starknet::crypto::merkle_patricia_tree::merkle_tree::ProofNode; use mp_starknet::execution::types::Felt252Wrapper; use mp_starknet::traits::hash::HasherT; use mp_starknet::traits::ThreadSafeCopy; @@ -47,7 +45,7 @@ use starknet_core::types::{ Transaction, TransactionStatus, }; -use crate::constants::{MAX_EVENTS_CHUNK_SIZE, MAX_EVENTS_KEYS, MAX_STORAGE_PROOF_KEYS_BY_QUERY}; +use crate::constants::{MAX_EVENTS_CHUNK_SIZE, MAX_EVENTS_KEYS}; use crate::types::RpcEventFilter; /// A Starknet RPC server for Madara @@ -870,124 +868,6 @@ where None => Err(StarknetRpcApiError::TxnHashNotFound.into()), } } - - /// This endpoint aims to do the same as [EIP-1186](https://eips.ethereum.org/EIPS/eip-1186) - /// It should provide all the data necessary for someone to verify some storage - /// within a starknet smart contract thanks to its merkle proof. - /// - /// It takes advantages from the facts that the whole state is built as 2 tries: - /// 1. The contracts trie : stores state data of the contracts based on their address - /// 2. The classes trie : associates class hashes with classes - /// - /// More information on Starknet's state [here](https://docs.starknet.io/documentation/architecture_and_concepts/State/starknet-state/) - /// - /// A storage proof is *just* a merkle proof of the subtree which you can find the root within - /// the contracts trie - /// - /// This implementation is highly inspired by previous work on [pathfinder](https://github.com/eqlabs/pathfinder/pull/726) - fn get_proof(&self, get_proof_input: RpcGetProofInput) -> RpcResult { - if get_proof_input.keys.len() > MAX_STORAGE_PROOF_KEYS_BY_QUERY { - error!( - "Too many keys requested! limit: {:?}, - requested: {:?}", - MAX_STORAGE_PROOF_KEYS_BY_QUERY, - get_proof_input.keys.len() as u32 - ); - return Err(StarknetRpcApiError::ProofLimitExceeded.into()); - } - - let substrate_block_hash = - self.substrate_block_hash_from_starknet_block(get_proof_input.block_id).map_err(|e| { - error!("'{e}'"); - StarknetRpcApiError::BlockNotFound - })?; - - let block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash).unwrap_or_default(); - - let global_state_root = block.header().global_state_root; - - let mut state_commitments = self - .overrides - .for_block_hash(self.client.as_ref(), substrate_block_hash) - .state_commitments(substrate_block_hash) - .ok_or_else(|| { - error!("Failed to retrieve state commitments"); - StarknetRpcApiError::InternalServerError - })?; - - let class_commitment: FieldElement = state_commitments.class_commitment.commit().into(); - let storage_commitment: FieldElement = state_commitments.storage_commitment.commit().into(); - - let (state_commitment, class_commitment) = if class_commitment == FieldElement::ZERO { - (None, None) - } else { - (Some(global_state_root.0), Some(class_commitment)) - }; - - // Generate a proof for this contract. If the contract does not exist, this will - // be a "non membership" proof. - let contract_proof = - state_commitments.storage_commitment.get_proof(Felt252Wrapper(get_proof_input.contract_address)); - - let contract_state_hash = - match state_commitments.storage_commitment.get(Felt252Wrapper(get_proof_input.contract_address)) { - Some(contract_state_hash) => contract_state_hash, - None => { - // Contract not found: return the proof of non membership that we generated earlier. - return Ok(RpcGetProofOutput { - state_commitment, - class_commitment, - contract_proof, - contract_data: None, - }); - } - }; - - // In theory we got some state hash in the tree that means the contract's state - // has been committed already so it exists and no error should be thrown. - // If an error is still thrown it's fine and handy for debugging. - - let class_hash = self - .overrides - .for_block_hash(self.client.as_ref(), substrate_block_hash) - .contract_class_hash_by_address(substrate_block_hash, get_proof_input.contract_address.into()) - .ok_or_else(|| { - error!("Failed to retrieve contract class hash at '{0}'", get_proof_input.contract_address); - StarknetRpcApiError::ContractNotFound - })?; - - let nonce = self - .overrides - .for_block_hash(self.client.as_ref(), substrate_block_hash) - .nonce(substrate_block_hash, get_proof_input.contract_address.into()) - .ok_or_else(|| { - error!("Failed to get nonce at '{0}'", get_proof_input.contract_address); - StarknetRpcApiError::ContractNotFound - })?; - - let mut contract_state_trie = self - .overrides - .for_block_hash(self.client.as_ref(), substrate_block_hash) - .contract_state_trie_by_address(substrate_block_hash, get_proof_input.contract_address.into()) - .ok_or_else(|| { - error!("Failed to get contract state trie at '{0}'", get_proof_input.contract_address); - StarknetRpcApiError::ContractNotFound - })?; - - let storage_proofs: Vec> = - get_proof_input.keys.iter().map(|k| contract_state_trie.get_proof(Felt252Wrapper(*k))).collect(); - - let contract_data = ContractData { - class_hash: class_hash.into(), - nonce: nonce.into(), - root: contract_state_trie.commit().into(), - // Currently, this is defined as 0. Might change in the future - contract_state_hash_version: FieldElement::ZERO, - storage_proofs, - }; - - Ok(RpcGetProofOutput { state_commitment, class_commitment, contract_proof, contract_data: Some(contract_data) }) - } } async fn submit_extrinsic( diff --git a/crates/client/storage/src/overrides/mod.rs b/crates/client/storage/src/overrides/mod.rs index ce5be543e3..bf3a6e59b7 100644 --- a/crates/client/storage/src/overrides/mod.rs +++ b/crates/client/storage/src/overrides/mod.rs @@ -7,7 +7,7 @@ use frame_support::{Identity, StorageHasher}; use mp_starknet::execution::types::{ClassHashWrapper, ContractAddressWrapper, Felt252Wrapper}; use mp_starknet::storage::StarknetStorageSchemaVersion; use pallet_starknet::runtime_api::StarknetRuntimeApi; -use pallet_starknet::types::{NonceWrapper, StateCommitments, StateTrie}; +use pallet_starknet::types::NonceWrapper; use sc_client_api::{Backend, HeaderBackend, StorageProvider}; use sp_api::ProvideRuntimeApi; use sp_io::hashing::twox_128; @@ -79,17 +79,6 @@ pub trait StorageOverride: Send + Sync { ) -> Option; /// Returns the nonce for a provided contract address and block hash. fn nonce(&self, block_hash: B::Hash, address: ContractAddressWrapper) -> Option; - /// Returns the state commitments for a provider block hash - fn state_commitments(&self, block_hash: B::Hash) -> Option; - /// Returns the state root at a provided contract address for the provided block. - fn contract_state_root_by_address( - &self, - block_hash: B::Hash, - address: ContractAddressWrapper, - ) -> Option; - /// Returns the contract state trie at a provided contract address for the provided block. - fn contract_state_trie_by_address(&self, block_hash: B::Hash, address: ContractAddressWrapper) - -> Option; } /// Returns the storage prefix given the pallet module name and the storage name @@ -198,50 +187,4 @@ where fn nonce(&self, block_hash: ::Hash, contract_address: ContractAddressWrapper) -> Option { self.client.runtime_api().nonce(block_hash, contract_address).ok() } - - /// Return the state commitments for a provided block hash - /// - /// # Arguments - /// - /// * `block_hash` - The block hash - /// - /// # Returns - /// * `Some(commitments)` - The state commitments for the provided block hash - fn state_commitments(&self, block_hash: ::Hash) -> Option { - self.client.runtime_api().get_state_commitments(block_hash).ok() - } - - /// Return the contract root for a provided block hash - /// - /// # Arguments - /// - /// * `block_hash` - The block hash - /// - /// # Returns - /// * `Some(contract_root)` - The contract root for the provided block hash - fn contract_state_root_by_address( - &self, - block_hash: ::Hash, - address: ContractAddressWrapper, - ) -> Option { - let api = self.client.runtime_api(); - api.contract_state_root_by_address(block_hash, address).ok()? - } - - /// Return the contract state trie for a provided block hash - /// - /// # Arguments - /// - /// * `block_hash` - The block hash - /// - /// # Returns - /// * `Some(state_trie)` - The contract state trie for the provided block hash - fn contract_state_trie_by_address( - &self, - block_hash: ::Hash, - address: ContractAddressWrapper, - ) -> Option { - let api = self.client.runtime_api(); - api.contract_state_trie_by_address(block_hash, address).ok()? - } } diff --git a/crates/client/storage/src/overrides/schema_v1_override.rs b/crates/client/storage/src/overrides/schema_v1_override.rs index ea773b1b77..c53812ddcb 100644 --- a/crates/client/storage/src/overrides/schema_v1_override.rs +++ b/crates/client/storage/src/overrides/schema_v1_override.rs @@ -4,10 +4,9 @@ use std::sync::Arc; use blockifier::execution::contract_class::ContractClass; use mp_starknet::execution::types::{ClassHashWrapper, ContractAddressWrapper, Felt252Wrapper}; use mp_starknet::storage::{ - PALLET_STARKNET, STARKNET_CONTRACT_CLASS, STARKNET_CONTRACT_CLASS_HASH, STARKNET_CONTRACT_STATE_ROOT, - STARKNET_CONTRACT_STATE_TRIES, STARKNET_NONCE, STARKNET_STATE_COMMITMENTS, STARKNET_STORAGE, + PALLET_STARKNET, STARKNET_CONTRACT_CLASS, STARKNET_CONTRACT_CLASS_HASH, STARKNET_NONCE, STARKNET_STORAGE, }; -use pallet_starknet::types::{NonceWrapper, StateCommitments, StateTrie}; +use pallet_starknet::types::NonceWrapper; // Substrate use sc_client_api::backend::{Backend, StorageProvider}; use scale_codec::{Decode, Encode}; @@ -103,18 +102,6 @@ where ) } - fn contract_state_trie_by_address( - &self, - block_hash: ::Hash, - address: ContractAddressWrapper, - ) -> Option { - let storage_contract_class_hash_prefix = storage_prefix_build(PALLET_STARKNET, STARKNET_CONTRACT_STATE_TRIES); - self.query_storage::( - block_hash, - &StorageKey(storage_key_build(storage_contract_class_hash_prefix, &self.encode_storage_key(&address))), - ) - } - fn contract_class_by_class_hash( &self, block_hash: ::Hash, @@ -142,26 +129,4 @@ where None => Some(NonceWrapper::default()), } } - - fn state_commitments(&self, block_hash: ::Hash) -> Option { - let state_key = storage_prefix_build(PALLET_STARKNET, STARKNET_STATE_COMMITMENTS); - let commitments = self.query_storage::(block_hash, &StorageKey(state_key)); - - match commitments { - Some(commitments) => Some(commitments), - None => Some(StateCommitments::default()), - } - } - - fn contract_state_root_by_address( - &self, - block_hash: ::Hash, - address: ContractAddressWrapper, - ) -> Option { - let storage_contract_state_root_prefix = storage_prefix_build(PALLET_STARKNET, STARKNET_CONTRACT_STATE_ROOT); - self.query_storage::( - block_hash, - &StorageKey(storage_key_build(storage_contract_state_root_prefix, &self.encode_storage_key(&address))), - ) - } } diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index e4f2ee2c1a..200702217c 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -104,5 +104,4 @@ runtime-benchmarks = [ # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = ["madara-runtime/try-runtime", "try-runtime-cli/try-runtime"] -madara-state-root = ["madara-runtime/madara-state-root"] disable-transaction-fee = ["madara-runtime/disable-transaction-fee"] diff --git a/crates/pallets/starknet/src/blockifier_state_adapter.rs b/crates/pallets/starknet/src/blockifier_state_adapter.rs index 610bd14e81..4301a7339c 100644 --- a/crates/pallets/starknet/src/blockifier_state_adapter.rs +++ b/crates/pallets/starknet/src/blockifier_state_adapter.rs @@ -6,7 +6,6 @@ use blockifier::state::cached_state::{CommitmentStateDiff, ContractStorageKey}; use blockifier::state::errors::StateError; use blockifier::state::state_api::{State, StateReader, StateResult}; use indexmap::IndexMap; -use mp_starknet::crypto::commitment::{calculate_class_commitment_leaf_hash, calculate_contract_state_hash}; use mp_starknet::execution::types::{ ClassHashWrapper, CompiledClassHashWrapper, ContractAddressWrapper, Felt252Wrapper, }; @@ -123,17 +122,6 @@ impl State for BlockifierStateAdapter { let contract_storage_key: ContractStorageKeyWrapper = (contract_address, key); crate::StorageView::::insert(contract_storage_key, value); - - // Update state tries if enabled in the runtime configuration - if T::EnableStateRoot::get() { - // Store intermediary state updates - // As we update this mapping iteratively - // We will end up with only the latest storage slot update - // TODO: Estimate overhead of this approach - crate::PendingStorageChanges::::mutate(contract_address, |storage_slots| { - storage_slots.try_push((key, value)).unwrap(); // TODO: unwrap safu ?? - }); - } } fn increment_nonce(&mut self, contract_address: ContractAddress) -> StateResult<()> { @@ -143,20 +131,6 @@ impl State for BlockifierStateAdapter { crate::Nonces::::insert(contract_address, new_nonce); - // Update state tries if enabled in the runtime configuration - if T::EnableStateRoot::get() { - // Update contracts trie - let mut tree = crate::StarknetStateCommitments::::get().storage_commitment; - let class_hash = Pallet::::contract_class_hash_by_address(contract_address).unwrap_or_default(); - let contract_root = Pallet::::contract_state_root_by_address(contract_address).unwrap_or_default(); - let hash = calculate_contract_state_hash::(class_hash, contract_root, new_nonce); - tree.set(contract_address, hash); - - crate::StarknetStateCommitments::::mutate(|state| { - state.storage_commitment = tree; - }) - } - Ok(()) } @@ -167,20 +141,6 @@ impl State for BlockifierStateAdapter { crate::ContractClassHashes::::insert(contract_address, class_hash); - // Update state tries if enabled in the runtime configuration - if T::EnableStateRoot::get() { - // Update contracts trie - let mut tree = crate::StarknetStateCommitments::::get().storage_commitment; - let nonce = Pallet::::nonce(contract_address); - let contract_root = Pallet::::contract_state_root_by_address(contract_address).unwrap_or_default(); - let hash = calculate_contract_state_hash::(class_hash, contract_root, nonce); - tree.set(contract_address, hash); - - crate::StarknetStateCommitments::::mutate(|state| { - state.storage_commitment = tree; - }) - } - Ok(()) } @@ -204,18 +164,6 @@ impl State for BlockifierStateAdapter { crate::CompiledClassHashes::::insert(class_hash, compiled_class_hash); - // Update state tries if enabled in the runtime configuration - if T::EnableStateRoot::get() { - // Update classes trie - let mut tree = crate::StarknetStateCommitments::::get().class_commitment; - let final_hash = calculate_class_commitment_leaf_hash::(compiled_class_hash); - tree.set(class_hash, final_hash); - - crate::StarknetStateCommitments::::mutate(|state| { - state.class_commitment = tree; - }) - } - Ok(()) } diff --git a/crates/pallets/starknet/src/lib.rs b/crates/pallets/starknet/src/lib.rs index f2a5c24601..064e2ca1b8 100644 --- a/crates/pallets/starknet/src/lib.rs +++ b/crates/pallets/starknet/src/lib.rs @@ -33,7 +33,6 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::large_enum_variant)] -use mp_starknet::crypto::state::StateCommitment; /// Starknet pallet. /// Definition of the pallet's runtime storage items, events, errors, and dispatchable /// functions. @@ -79,9 +78,9 @@ use frame_support::pallet_prelude::*; use frame_support::traits::Time; use frame_system::pallet_prelude::*; use mp_digest_log::MADARA_ENGINE_ID; -use mp_starknet::block::{Block as StarknetBlock, Header as StarknetHeader, MaxStorageSlots, MaxTransactions}; +use mp_starknet::block::{Block as StarknetBlock, Header as StarknetHeader, MaxTransactions}; use mp_starknet::constants::INITIAL_GAS; -use mp_starknet::crypto::commitment::{self, calculate_contract_state_hash}; +use mp_starknet::crypto::commitment::{self}; use mp_starknet::execution::types::{ CallEntryPointWrapper, ClassHashWrapper, ContractAddressWrapper, EntryPointTypeWrapper, Felt252Wrapper, }; @@ -102,9 +101,7 @@ use starknet_api::transaction::EventContent; use starknet_crypto::FieldElement; use crate::alloc::string::ToString; -use crate::types::{ - ContractStorageKeyWrapper, NonceWrapper, StateCommitments, StateTrie, StorageKeyWrapper, StorageSlotWrapper, -}; +use crate::types::{ContractStorageKeyWrapper, NonceWrapper, StorageKeyWrapper}; pub(crate) const LOG_TARGET: &str = "runtime::starknet"; @@ -156,10 +153,6 @@ pub mod pallet { /// set how long transactions are kept in the mempool. #[pallet::constant] type TransactionLongevity: Get; - /// A bool to enable/disable State Root computation - /// As this is a very time-consuming process we preferred to let it optional for now - /// Not every application needs it but if you need to use it you can enable it - type EnableStateRoot: Get; /// A bool to disable transaction fees and make all transactions free #[pallet::constant] type DisableTransactionFee: Get; @@ -230,38 +223,6 @@ pub mod pallet { pub(super) type Pending = StorageValue<_, BoundedVec<(Transaction, TransactionReceiptWrapper), MaxTransactions>, ValueQuery>; - /// The Starknet pallet storage items. - /// STORAGE - /// State commitments of the current block. - #[pallet::storage] - #[pallet::unbounded] - #[pallet::getter(fn starknet_state_commitments)] - pub(super) type StarknetStateCommitments = StorageValue<_, StateCommitments, ValueQuery>; - - /// The Starknet pallet storage items. - /// STORAGE - /// Mapping of contract address to state trie. - #[pallet::storage] - #[pallet::unbounded] - #[pallet::getter(fn contract_state_trie_by_address)] - pub(super) type ContractTries = StorageMap<_, Identity, ContractAddressWrapper, StateTrie, OptionQuery>; - - /// The Starknet pallet storage items. - /// STORAGE - /// Mapping of contract address to state root. - #[pallet::storage] - #[pallet::getter(fn contract_state_root_by_address)] - pub(super) type ContractsStateRoots = - StorageMap<_, Identity, ContractAddressWrapper, Felt252Wrapper, OptionQuery>; - - /// Pending storage slot updates - /// STORAGE - /// Mapping storage key to storage value. - #[pallet::storage] - #[pallet::getter(fn pending_storage_changes)] - pub(super) type PendingStorageChanges = - StorageMap<_, Identity, ContractAddressWrapper, BoundedVec, ValueQuery>; - /// Current building block's events. // TODO: This is redundant information but more performant // than removing this and computing events from the tx reciepts. @@ -382,20 +343,6 @@ pub mod pallet { for (address, class_hash) in self.contracts.iter() { ContractClassHashes::::insert(address, class_hash); - - // Update state tries if enabled in the runtime configuration - if T::EnableStateRoot::get() { - // Update contracts trie - let mut tree = crate::StarknetStateCommitments::::get().storage_commitment; - let nonce = Pallet::::nonce(address); - let contract_root = Pallet::::contract_state_root_by_address(address).unwrap_or_default(); - let hash = calculate_contract_state_hash::(*class_hash, contract_root, nonce); - tree.set(*address, hash); - - crate::StarknetStateCommitments::::mutate(|state| { - state.storage_commitment = tree; - }) - } } for (class_hash, contract_class) in self.contract_classes.iter() { @@ -404,17 +351,6 @@ pub mod pallet { for (key, value) in self.storage.iter() { StorageView::::insert(key, value); - - // Update state tries if enabled in the runtime configuration - if T::EnableStateRoot::get() { - // Store intermediary state updates - // As we update this mapping iteratively - // We will end up with only the latest storage slot update - // TODO: Estimate overhead of this approach - PendingStorageChanges::::mutate(key.0, |storage_slots| { - storage_slots.try_push((key.1, *value)).unwrap(); // TODO: unwrap safu ?? - }); - } } LastKnownEthBlock::::set(None); @@ -1011,8 +947,7 @@ impl Pallet { let parent_block_hash = Self::parent_block_hash(&block_number); let pending = Self::pending(); - let global_state_root = - if T::EnableStateRoot::get() { Self::compute_and_store_state_root() } else { Felt252Wrapper::default() }; + let global_state_root = Felt252Wrapper::default(); let sequencer_address = Self::sequencer_address(); let block_timestamp = Self::block_timestamp(); @@ -1193,58 +1128,6 @@ impl Pallet { Ok(events) } - /// Compute the global state root and store it in the runtime storage. - /// This function is called at the end of each block. - /// It iterates through all the pending storage changes and updates the storage trie. - /// It then computes the state root and stores it in the runtime storage. - /// - /// # Returns - /// - /// The global state root. - pub fn compute_and_store_state_root() -> Felt252Wrapper { - // Update contracts trie - let mut commitments = Self::starknet_state_commitments(); - let pending_storage_changes = PendingStorageChanges::::drain(); - - pending_storage_changes.for_each(|(contract_address, storage_diffs)| { - // Retrieve state trie for this contract. - // TODO: Investigate what to do in case of failure of the state root computation - let mut state_tree = ContractTries::::get(contract_address).unwrap_or_default(); - // For each smart contract, iterate through storage diffs and update the state trie. - storage_diffs.into_iter().for_each(|(storage_key, storage_value)| { - state_tree.set(storage_key, storage_value); - }); - - // We then compute the state root - // And update the storage trie - let state_root = state_tree.commit(); - - // Update the state trie for this contract in runtime storage. - ContractTries::::set(contract_address, Some(state_tree.clone())); - - // Update contracts' states root mapping - ContractsStateRoots::::set(contract_address, Some(state_root)); - - let nonce = Self::nonce(contract_address); - let class_hash = Self::contract_class_hash_by_address(contract_address).unwrap_or_default(); - let hash = calculate_contract_state_hash::(class_hash, state_root, nonce); - commitments.storage_commitment.set(contract_address, hash); - }); - - // Compute the final state root - let global_state_root = StateCommitment::::calculate( - commitments.storage_commitment.commit(), - commitments.class_commitment.commit(), - ); - - // Finally update the contracts trie in runtime storage. - StarknetStateCommitments::::mutate(|state| { - state.storage_commitment = commitments.clone().storage_commitment; - }); - - global_state_root - } - pub fn chain_id() -> Felt252Wrapper { T::ChainId::get() } diff --git a/crates/pallets/starknet/src/runtime_api.rs b/crates/pallets/starknet/src/runtime_api.rs index 1650e894f6..fd1a8a3836 100644 --- a/crates/pallets/starknet/src/runtime_api.rs +++ b/crates/pallets/starknet/src/runtime_api.rs @@ -15,8 +15,7 @@ use alloc::vec::Vec; use sp_runtime::DispatchError; -use crate::types::{NonceWrapper, StateCommitments}; -use crate::StateTrie; +use crate::types::NonceWrapper; #[derive(scale_codec::Encode, scale_codec::Decode, scale_info::TypeInfo)] pub enum StarknetTransactionExecutionError { @@ -41,18 +40,12 @@ sp_api::decl_runtime_apis! { fn contract_class_hash_by_address(address: ContractAddressWrapper) -> Option; /// Returns the contract class for the given class hash. fn contract_class_by_class_hash(class_hash: ClassHashWrapper) -> Option; - /// Returns the contract root for the given address - fn contract_state_root_by_address(address: ContractAddressWrapper) -> Option; - /// Returns the contract state trie for the given address - fn contract_state_trie_by_address(address: ContractAddressWrapper) -> Option; /// Returns the chain id. fn chain_id() -> Felt252Wrapper; /// Returns fee estimate fn estimate_fee(transaction: Transaction) -> Result<(u64, u64), DispatchError>; /// Returns the hasher used by the runtime. fn get_hasher() -> Hasher; - /// Returns state commitments - fn get_state_commitments() -> StateCommitments; /// Filters extrinsic transactions to return only Starknet transactions /// /// To support runtime upgrades, the client must be unaware of the specific extrinsic diff --git a/crates/pallets/starknet/src/tests/mock/setup_mock.rs b/crates/pallets/starknet/src/tests/mock/setup_mock.rs index c585a1342b..5700b0a651 100644 --- a/crates/pallets/starknet/src/tests/mock/setup_mock.rs +++ b/crates/pallets/starknet/src/tests/mock/setup_mock.rs @@ -5,7 +5,7 @@ use crate::{Config, GenesisConfig}; // Configure a mock runtime to test the pallet. macro_rules! mock_runtime { - ($mock_runtime:ident, $enable_state_root:expr, $disable_transaction_fee:expr, $disable_nonce_validation: expr) => { + ($mock_runtime:ident, $disable_transaction_fee:expr, $disable_nonce_validation: expr) => { pub mod $mock_runtime { use frame_support::parameter_types; use frame_support::traits::{ConstU16, ConstU64}; @@ -74,7 +74,6 @@ macro_rules! mock_runtime { pub const TransactionLongevity: u64 = u64::MAX; pub const InvokeTxMaxNSteps: u32 = 1_000_000; pub const ValidateMaxNSteps: u32 = 1_000_000; - pub const EnableStateRoot: bool = $enable_state_root; pub const DisableTransactionFee: bool = $disable_transaction_fee; pub const DisableNonceValidation: bool = $disable_nonce_validation; pub const ProtocolVersion: u8 = 0; @@ -90,7 +89,6 @@ macro_rules! mock_runtime { type TransactionLongevity = TransactionLongevity; type InvokeTxMaxNSteps = InvokeTxMaxNSteps; type ValidateMaxNSteps = ValidateMaxNSteps; - type EnableStateRoot = EnableStateRoot; type DisableTransactionFee = DisableTransactionFee; type DisableNonceValidation = DisableNonceValidation; type ProtocolVersion = ProtocolVersion; @@ -135,7 +133,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { t.into() } -mock_runtime!(default_mock, false, false, false); -mock_runtime!(state_root_mock, true, false, false); -mock_runtime!(fees_disabled_mock, false, true, false); -mock_runtime!(no_nonce_validation_mock, false, true, true); +mock_runtime!(default_mock, false, false); +mock_runtime!(fees_disabled_mock, true, false); +mock_runtime!(no_nonce_validation_mock, true, true); diff --git a/crates/pallets/starknet/src/tests/mod.rs b/crates/pallets/starknet/src/tests/mod.rs index 6b4312f4e4..e93b1d3243 100644 --- a/crates/pallets/starknet/src/tests/mod.rs +++ b/crates/pallets/starknet/src/tests/mod.rs @@ -22,7 +22,6 @@ mod l1_message; mod nonce_validation; mod query_tx; mod sequencer_address; -mod state_root; mod block; mod constants; diff --git a/crates/pallets/starknet/src/tests/state_root.rs b/crates/pallets/starknet/src/tests/state_root.rs deleted file mode 100644 index 86e342206a..0000000000 --- a/crates/pallets/starknet/src/tests/state_root.rs +++ /dev/null @@ -1,37 +0,0 @@ -use mp_starknet::execution::types::Felt252Wrapper; - -use super::mock::{default_mock, state_root_mock, *}; - -#[test] -fn given_default_runtime_with_state_root_disabled_default_value_is_correct() { - new_test_ext::().execute_with(|| { - default_mock::basic_test_setup(2); - - // Check that state root is not set when disabled - pretty_assertions::assert_eq!( - default_mock::Starknet::compute_and_store_state_root(), - Felt252Wrapper::default() - ); - }); -} - -#[test] -fn given_default_runtime_with_state_root_enabled_default_value_is_correct() { - new_test_ext::().execute_with(|| { - state_root_mock::basic_test_setup(2); - - // Check the default state root value when enabled - // We fetch this value using current genesis state and starkware python package - pretty_assertions::assert_eq!( - state_root_mock::Starknet::compute_and_store_state_root(), - Felt252Wrapper::from_hex_be("0x066a4b57d6d9f0c3d15f1bebfac552d0e0e39ca89a1627b190838344620ecbe1").unwrap() - ); - - let account_address = get_account_address(AccountType::V0(AccountTypeV0Inner::Argent)); - - pretty_assertions::assert_eq!( - state_root_mock::Starknet::contract_state_root_by_address(account_address).unwrap(), - Felt252Wrapper::from_hex_be("0x04b9de03767569b7b86924fd58d86cb1a0ba1b9c3eb3078187b4533d0d2af340").unwrap() - ) - }); -} diff --git a/crates/pallets/starknet/src/types.rs b/crates/pallets/starknet/src/types.rs index dbca726da0..dfb84863f7 100644 --- a/crates/pallets/starknet/src/types.rs +++ b/crates/pallets/starknet/src/types.rs @@ -1,8 +1,5 @@ //! Starknet pallet custom types. use blockifier::execution::contract_class::ContractClass; -use mp_starknet::crypto::commitment::StateCommitmentTree; -use mp_starknet::crypto::hash::pedersen::PedersenHasher; -use mp_starknet::crypto::hash::poseidon::PoseidonHasher; use mp_starknet::execution::types::{ContractAddressWrapper, Felt252Wrapper}; use sp_core::ConstU32; use starknet_api::api_core::ClassHash; @@ -25,9 +22,6 @@ pub type ContractClassMapping = HashMap; /// Type wrapper for a storage slot. pub type StorageSlotWrapper = (StorageKeyWrapper, Felt252Wrapper); -/// State trie type. -pub type StateTrie = StateCommitmentTree; - /// Declare Transaction Output #[derive( Clone, @@ -47,16 +41,6 @@ pub struct DeployAccountTransactionOutput { pub contract_address: ContractAddressWrapper, } -/// State Commitments -/// TODO: Make hashers configurable in runtime config -#[derive(Default, Clone, scale_codec::Encode, scale_codec::Decode, scale_info::TypeInfo)] -pub struct StateCommitments { - /// Storage Commitment - pub storage_commitment: StateCommitmentTree, - /// Class Commitment - pub class_commitment: StateCommitmentTree, -} - /// Build invoke transaction for transfer utils pub struct BuildTransferInvokeTransaction { pub sender_address: Felt252Wrapper, diff --git a/crates/primitives/starknet/src/storage/mod.rs b/crates/primitives/starknet/src/storage/mod.rs index 6669c376b2..161ae7282a 100644 --- a/crates/primitives/starknet/src/storage/mod.rs +++ b/crates/primitives/starknet/src/storage/mod.rs @@ -24,12 +24,6 @@ pub const STARKNET_CONTRACT_CLASS: &[u8] = b"ContractClasses"; pub const STARKNET_NONCE: &[u8] = b"Nonces"; /// Starknet storage pub const STARKNET_STORAGE: &[u8] = b"StorageView"; -/// Starknet state commitment tries -pub const STARKNET_STATE_COMMITMENTS: &[u8] = b"StarknetStateCommitments"; -/// Starknet contract roots -pub const STARKNET_CONTRACT_STATE_ROOT: &[u8] = b"ContractStateRoots"; -/// Starknet contract state tries -pub const STARKNET_CONTRACT_STATE_TRIES: &[u8] = b"ContractTries"; /// The schema version for Pallet Starknet's storage. #[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)] diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index f3a1361ac2..fe0bbfa822 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -105,7 +105,6 @@ try-runtime = [ "pallet-starknet/try-runtime", ] default = ["std"] -madara-state-root = [] disable-transaction-fee = [] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index 728f892e7e..4538de8198 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -37,7 +37,7 @@ use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as G pub use pallet_starknet; use pallet_starknet::pallet::Error as PalletError; use pallet_starknet::runtime_api::StarknetTransactionExecutionError; -use pallet_starknet::types::{NonceWrapper, StateCommitments, StateTrie}; +use pallet_starknet::types::NonceWrapper; use pallet_starknet::Call::{declare, deploy_account, invoke}; use pallet_starknet::Event; pub use pallet_timestamp::Call as TimestampCall; @@ -263,14 +263,6 @@ impl_runtime_apis! { Starknet::contract_class_hash_by_address(address) } - fn contract_state_root_by_address(address: ContractAddressWrapper) -> Option { - Starknet::contract_state_root_by_address(address) - } - - fn contract_state_trie_by_address(address: ContractAddressWrapper) -> Option { - Starknet::contract_state_trie_by_address(address) - } - fn contract_class_by_class_hash(class_hash: ClassHashWrapper) -> Option { Starknet::contract_class_by_class_hash(class_hash) } @@ -287,10 +279,6 @@ impl_runtime_apis! { Starknet::get_system_hash().into() } - fn get_state_commitments() -> StateCommitments { - Starknet::starknet_state_commitments() - } - fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec { let chain_id = Starknet::chain_id(); diff --git a/crates/runtime/src/pallets.rs b/crates/runtime/src/pallets.rs index 9d612b0b6a..6496e0e701 100644 --- a/crates/runtime/src/pallets.rs +++ b/crates/runtime/src/pallets.rs @@ -37,10 +37,6 @@ impl pallet_starknet::Config for Runtime { type TimestampProvider = Timestamp; type UnsignedPriority = UnsignedPriority; type TransactionLongevity = TransactionLongevity; - #[cfg(not(feature = "madara-state-root"))] - type EnableStateRoot = ConstBool; - #[cfg(feature = "madara-state-root")] - type EnableStateRoot = ConstBool; #[cfg(not(feature = "disable-transaction-fee"))] type DisableTransactionFee = ConstBool; #[cfg(feature = "disable-transaction-fee")] diff --git a/scripts/run_node.sh b/scripts/run_node.sh index 8a9cf12457..9073d4f877 100755 --- a/scripts/run_node.sh +++ b/scripts/run_node.sh @@ -2,27 +2,5 @@ # This script is meant to be run on Unix/Linux based systems set -e -while [[ $# -gt 0 ]]; do - case $1 in - --with-state-root) - with_state_root=true - ;; - *) - echo "Unknown argument: $1" - exit 1 - ;; - esac - shift -done - -# Check if the --with-state-root flag is provided -if [[ $with_state_root ]]; then - echo "Running with state root..." - cargo build --release --features madara-state-root - exec ../target/release/madara --dev --tmp --rpc-external --execution native --pool-limit=100000 --pool-kbytes=500000 --rpc-methods=unsafe --rpc-cors=all --in-peers=0 --out-peers=1 --no-telemetry -else - echo "Running without state root..." - cargo build --release - exec ../target/release/madara --dev --tmp --rpc-external --execution native --pool-limit=100000 --pool-kbytes=500000 --rpc-methods=unsafe --rpc-cors=all --in-peers=0 --out-peers=1 --no-telemetry -fi - +cargo build --release +exec ../target/release/madara --dev --tmp --rpc-external --execution native --pool-limit=100000 --pool-kbytes=500000 --rpc-methods=unsafe --rpc-cors=all --in-peers=0 --out-peers=1 --no-telemetry diff --git a/tests/tests/test-starknet-rpc/test-state-root.ts b/tests/tests/test-starknet-rpc/test-state-root.ts deleted file mode 100644 index 7d2f7c8802..0000000000 --- a/tests/tests/test-starknet-rpc/test-state-root.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { RpcProvider } from "starknet"; -import { describeDevMadara } from "../../util/setup-dev-tests"; -import { expect } from "chai"; -import { jumpBlocks } from "../../util/block"; - -describeDevMadara( - "Starknet RPC - State Root Enabled Test", - (context) => { - let providerRPC: RpcProvider; - - before(async function () { - providerRPC = new RpcProvider({ - nodeUrl: `http://127.0.0.1:${context.rpcPort}/`, - retries: 3, - }); // substrate node - }); - - describe("state root", async () => { - // TODO: Find a way to run integration tests with feature flags - it("should return default when disabled", async function () { - const latestBlock = await providerRPC.getBlock("latest"); - expect(latestBlock.new_root).to.eq("0x0"); - }); - - it("should return default when enabled", async function () { - await jumpBlocks(context, 2); - - const latestBlock = await providerRPC.getBlock("latest"); - expect(latestBlock.new_root).to.eq( - "0x5092d16e8b238b12b0830c71c6ad21dce5edf3ed41aaa935a79a8d7bd7481e5", - ); - }); - }); - - describe("getProof", async () => { - it("should return proof of non-membership", async function () { - await jumpBlocks(context, 1); - - const params = { - get_proof_input: { - block_id: "latest", - contract_address: "0x111222333", - keys: ["0x1", "0xfffffffff"], - }, - }; - let storage_proof = await providerRPC.fetch( - "starknet_getProof", - params, - ); - storage_proof = await storage_proof.json(); - - // Check contract root - expect(storage_proof["result"]["contract_data"]).to.be.null; - }); - - it("should return proof of membership", async function () { - await jumpBlocks(context, 1); - - const params = { - get_proof_input: { - block_id: "latest", - contract_address: "0x2", - keys: ["0x1", "0xfffffffff"], - }, - }; - let storage_proof = await providerRPC.fetch( - "starknet_getProof", - params, - ); - storage_proof = await storage_proof.json(); - - // Check contract root - expect(storage_proof["result"]["contract_data"]["root"]).to.be.eq( - "2137650382361045467996332368791861747902403628779494221252963710317158396736", - ); - }); - }); - }, - { runNewNode: true }, -);