Skip to content

Commit

Permalink
chore: remove global state root (keep-starknet-strange#1039)
Browse files Browse the repository at this point in the history
  • Loading branch information
apoorvsadana authored Aug 24, 2023
1 parent e847a76 commit 1729adc
Show file tree
Hide file tree
Showing 23 changed files with 19 additions and 658 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rust-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ jobs:
- name: Build the project
run: |
cargo build --release --workspace --features madara-state-root
cargo build --release --workspace
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 0 additions & 9 deletions crates/client/rpc-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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<MaybePendingTransactionReceipt>;

/// 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<RpcGetProofOutput>;
}
58 changes: 0 additions & 58 deletions crates/client/rpc-core/src/types.rs

This file was deleted.

2 changes: 0 additions & 2 deletions crates/client/rpc/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
122 changes: 1 addition & 121 deletions crates/client/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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<RpcGetProofOutput> {
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<Vec<ProofNode>> =
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<P, B>(
Expand Down
59 changes: 1 addition & 58 deletions crates/client/storage/src/overrides/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -79,17 +79,6 @@ pub trait StorageOverride<B: BlockT>: Send + Sync {
) -> Option<ContractClass>;
/// Returns the nonce for a provided contract address and block hash.
fn nonce(&self, block_hash: B::Hash, address: ContractAddressWrapper) -> Option<NonceWrapper>;
/// Returns the state commitments for a provider block hash
fn state_commitments(&self, block_hash: B::Hash) -> Option<StateCommitments>;
/// 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<Felt252Wrapper>;
/// 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<StateTrie>;
}

/// Returns the storage prefix given the pallet module name and the storage name
Expand Down Expand Up @@ -198,50 +187,4 @@ where
fn nonce(&self, block_hash: <B as BlockT>::Hash, contract_address: ContractAddressWrapper) -> Option<NonceWrapper> {
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: <B as BlockT>::Hash) -> Option<StateCommitments> {
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: <B as BlockT>::Hash,
address: ContractAddressWrapper,
) -> Option<Felt252Wrapper> {
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: <B as BlockT>::Hash,
address: ContractAddressWrapper,
) -> Option<StateTrie> {
let api = self.client.runtime_api();
api.contract_state_trie_by_address(block_hash, address).ok()?
}
}
Loading

0 comments on commit 1729adc

Please sign in to comment.