Skip to content

Commit

Permalink
feat(katana): getStorageProof endpoint (#2809)
Browse files Browse the repository at this point in the history
  • Loading branch information
kariy committed Dec 19, 2024
1 parent d67a5fd commit b9f27ae
Show file tree
Hide file tree
Showing 49 changed files with 2,130 additions and 781 deletions.
674 changes: 353 additions & 321 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,8 @@ starknet-crypto = "0.7.1"
starknet-types-core = { version = "0.1.7", features = [ "arbitrary", "hash" ] }

bitvec = "1.0.1"

# macro
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", default-features = false }
39 changes: 15 additions & 24 deletions crates/katana/core/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use katana_primitives::state::{compute_state_diff_hash, StateUpdates};
use katana_primitives::transaction::{TxHash, TxWithHash};
use katana_primitives::Felt;
use katana_provider::traits::block::{BlockHashProvider, BlockWriter};
use katana_provider::traits::trie::{ClassTrieWriter, ContractTrieWriter};
use katana_provider::traits::trie::TrieWriter;
use katana_trie::compute_merkle_root;
use parking_lot::RwLock;
use starknet::macros::short_string;
Expand Down Expand Up @@ -158,29 +158,23 @@ impl<EF: ExecutorFactory> Backend<EF> {
}

#[derive(Debug, Clone)]
pub struct UncommittedBlock<'a, P>
where
P: ClassTrieWriter + ContractTrieWriter,
{
pub struct UncommittedBlock<'a, P: TrieWriter> {
header: PartialHeader,
transactions: Vec<TxWithHash>,
receipts: &'a [ReceiptWithTxHash],
state_updates: &'a StateUpdates,
trie_provider: P,
provider: P,
}

impl<'a, P> UncommittedBlock<'a, P>
where
P: ClassTrieWriter + ContractTrieWriter,
{
impl<'a, P: TrieWriter> UncommittedBlock<'a, P> {
pub fn new(
header: PartialHeader,
transactions: Vec<TxWithHash>,
receipts: &'a [ReceiptWithTxHash],
state_updates: &'a StateUpdates,
trie_provider: P,
) -> Self {
Self { header, transactions, receipts, state_updates, trie_provider }
Self { header, transactions, receipts, state_updates, provider: trie_provider }
}

pub fn commit(self) -> SealedBlock {
Expand Down Expand Up @@ -258,19 +252,16 @@ where

// state_commitment = hPos("STARKNET_STATE_V0", contract_trie_root, class_trie_root)
fn compute_new_state_root(&self) -> Felt {
let class_trie_root = ClassTrieWriter::insert_updates(
&self.trie_provider,
self.header.number,
&self.state_updates.declared_classes,
)
.unwrap();

let contract_trie_root = ContractTrieWriter::insert_updates(
&self.trie_provider,
self.header.number,
self.state_updates,
)
.unwrap();
println!("ohayo im committing now");
let class_trie_root = self
.provider
.trie_insert_declared_classes(self.header.number, &self.state_updates.declared_classes)
.expect("failed to update class trie");

let contract_trie_root = self
.provider
.trie_insert_contract_updates(self.header.number, self.state_updates)
.expect("failed to update contract trie");

hash::Poseidon::hash_array(&[
short_string!("STARKNET_STATE_V0"),
Expand Down
12 changes: 4 additions & 8 deletions crates/katana/core/src/backend/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ use katana_provider::traits::block::{BlockProvider, BlockWriter};
use katana_provider::traits::contract::{ContractClassWriter, ContractClassWriterExt};
use katana_provider::traits::env::BlockEnvProvider;
use katana_provider::traits::stage::StageCheckpointProvider;
use katana_provider::traits::state::{StateFactoryProvider, StateRootProvider, StateWriter};
use katana_provider::traits::state::{StateFactoryProvider, StateWriter};
use katana_provider::traits::state_update::StateUpdateProvider;
use katana_provider::traits::transaction::{
ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionTraceProvider,
TransactionsProviderExt,
};
use katana_provider::traits::trie::{ClassTrieWriter, ContractTrieWriter};
use katana_provider::traits::trie::TrieWriter;
use katana_provider::BlockchainProvider;
use num_traits::ToPrimitive;
use starknet::core::types::{BlockStatus, MaybePendingBlockWithTxHashes};
Expand All @@ -40,14 +40,12 @@ pub trait Database:
+ TransactionsProviderExt
+ ReceiptProvider
+ StateUpdateProvider
+ StateRootProvider
+ StateWriter
+ ContractClassWriter
+ ContractClassWriterExt
+ StateFactoryProvider
+ BlockEnvProvider
+ ClassTrieWriter
+ ContractTrieWriter
+ TrieWriter
+ StageCheckpointProvider
+ 'static
+ Send
Expand All @@ -65,14 +63,12 @@ impl<T> Database for T where
+ TransactionsProviderExt
+ ReceiptProvider
+ StateUpdateProvider
+ StateRootProvider
+ StateWriter
+ ContractClassWriter
+ ContractClassWriterExt
+ StateFactoryProvider
+ BlockEnvProvider
+ ClassTrieWriter
+ ContractTrieWriter
+ TrieWriter
+ StageCheckpointProvider
+ 'static
+ Send
Expand Down
1 change: 1 addition & 0 deletions crates/katana/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ version.workspace = true
[dependencies]
katana-primitives.workspace = true
katana-provider.workspace = true
katana-trie.workspace = true

parking_lot = { workspace = true, optional = true }
starknet = { workspace = true, optional = true }
Expand Down
35 changes: 34 additions & 1 deletion crates/katana/executor/src/abstraction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use katana_primitives::trace::TxExecInfo;
use katana_primitives::transaction::TxWithHash;
use katana_primitives::Felt;
use katana_provider::traits::contract::ContractClassProvider;
use katana_provider::traits::state::StateProvider;
use katana_provider::traits::state::{StateProofProvider, StateProvider, StateRootProvider};
use katana_provider::ProviderResult;
use katana_trie::MultiProof;

pub type ExecutorResult<T> = Result<T, error::ExecutorError>;

Expand Down Expand Up @@ -204,3 +205,35 @@ impl<'a> StateProvider for StateProviderDb<'a> {
self.0.storage(address, storage_key)
}
}

impl<'a> StateProofProvider for StateProviderDb<'a> {
fn class_multiproof(&self, classes: Vec<ClassHash>) -> ProviderResult<MultiProof> {
self.0.class_multiproof(classes)
}

fn contract_multiproof(&self, addresses: Vec<ContractAddress>) -> ProviderResult<MultiProof> {
self.0.contract_multiproof(addresses)
}

fn storage_multiproof(
&self,
address: ContractAddress,
key: Vec<StorageKey>,
) -> ProviderResult<MultiProof> {
self.0.storage_multiproof(address, key)
}
}

impl<'a> StateRootProvider for StateProviderDb<'a> {
fn classes_root(&self) -> ProviderResult<Felt> {
self.0.classes_root()
}

fn contracts_root(&self) -> ProviderResult<Felt> {
self.0.contracts_root()
}

fn state_root(&self) -> ProviderResult<Felt> {
self.0.state_root()
}
}
40 changes: 39 additions & 1 deletion crates/katana/executor/src/implementation/blockifier/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use katana_primitives::class::{self, CompiledClass, ContractClass};
use katana_primitives::Felt;
use katana_provider::error::ProviderError;
use katana_provider::traits::contract::ContractClassProvider;
use katana_provider::traits::state::StateProvider;
use katana_provider::traits::state::{StateProofProvider, StateProvider, StateRootProvider};
use katana_provider::ProviderResult;
use parking_lot::Mutex;

Expand Down Expand Up @@ -238,6 +238,44 @@ impl<S: StateDb> StateReader for CachedState<S> {
}
}

impl<S: StateDb> StateProofProvider for CachedState<S> {
fn class_multiproof(
&self,
classes: Vec<class::ClassHash>,
) -> ProviderResult<katana_trie::MultiProof> {
let _ = classes;
unimplemented!("not supported in executor's state")
}

fn contract_multiproof(
&self,
addresses: Vec<katana_primitives::ContractAddress>,
) -> ProviderResult<katana_trie::MultiProof> {
let _ = addresses;
unimplemented!("not supported in executor's state")
}

fn storage_multiproof(
&self,
address: katana_primitives::ContractAddress,
key: Vec<katana_primitives::contract::StorageKey>,
) -> ProviderResult<katana_trie::MultiProof> {
let _ = address;
let _ = key;
unimplemented!("not supported in executor's state")
}
}

impl<S: StateDb> StateRootProvider for CachedState<S> {
fn classes_root(&self) -> ProviderResult<Felt> {
unimplemented!("not supported in executor's state")
}

fn contracts_root(&self) -> ProviderResult<Felt> {
unimplemented!("not supported in executor's state")
}
}

#[cfg(test)]
mod tests {

Expand Down
37 changes: 36 additions & 1 deletion crates/katana/executor/src/implementation/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use katana_primitives::fee::TxFeeInfo;
use katana_primitives::transaction::{ExecutableTxWithHash, TxWithHash};
use katana_primitives::Felt;
use katana_provider::traits::contract::ContractClassProvider;
use katana_provider::traits::state::StateProvider;
use katana_provider::traits::state::{StateProofProvider, StateProvider, StateRootProvider};
use katana_provider::ProviderResult;

use crate::abstraction::{
Expand Down Expand Up @@ -170,3 +170,38 @@ impl StateProvider for NoopStateProvider {
Ok(None)
}
}

impl StateProofProvider for NoopStateProvider {
fn class_multiproof(&self, classes: Vec<ClassHash>) -> ProviderResult<katana_trie::MultiProof> {
let _ = classes;
Ok(katana_trie::MultiProof(Default::default()))
}

fn contract_multiproof(
&self,
addresses: Vec<ContractAddress>,
) -> ProviderResult<katana_trie::MultiProof> {
let _ = addresses;
Ok(katana_trie::MultiProof(Default::default()))
}

fn storage_multiproof(
&self,
address: ContractAddress,
key: Vec<StorageKey>,
) -> ProviderResult<katana_trie::MultiProof> {
let _ = address;
let _ = key;
Ok(katana_trie::MultiProof(Default::default()))
}
}

impl StateRootProvider for NoopStateProvider {
fn classes_root(&self) -> ProviderResult<Felt> {
Ok(Felt::ZERO)
}

fn contracts_root(&self) -> ProviderResult<Felt> {
Ok(Felt::ZERO)
}
}
1 change: 1 addition & 0 deletions crates/katana/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ pub mod utils;
pub use contract::ContractAddress;
pub use starknet::macros::felt;
pub use starknet_types_core::felt::{Felt, FromStrError};
pub use starknet_types_core::hash;
16 changes: 15 additions & 1 deletion crates/katana/rpc/rpc-api/src/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
use jsonrpsee::core::RpcResult;
use jsonrpsee::proc_macros::rpc;
use katana_primitives::block::{BlockIdOrTag, BlockNumber};
use katana_primitives::class::ClassHash;
use katana_primitives::transaction::TxHash;
use katana_primitives::Felt;
use katana_primitives::{ContractAddress, Felt};
use katana_rpc_types::block::{
BlockHashAndNumber, BlockTxCount, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes,
MaybePendingBlockWithTxs,
Expand All @@ -18,6 +19,7 @@ use katana_rpc_types::transaction::{
BroadcastedDeclareTx, BroadcastedDeployAccountTx, BroadcastedInvokeTx, BroadcastedTx,
DeclareTxResult, DeployAccountTxResult, InvokeTxResult, Tx,
};
use katana_rpc_types::trie::{ContractStorageKeys, GetStorageProofResponse};
use katana_rpc_types::{
FeeEstimate, FeltAsHex, FunctionCall, SimulationFlag, SimulationFlagForEstimateFee,
SyncingStatus,
Expand Down Expand Up @@ -183,6 +185,18 @@ pub trait StarknetApi {
block_id: BlockIdOrTag,
contract_address: Felt,
) -> RpcResult<FeltAsHex>;

/// Get merkle paths in one of the state tries: global state, classes, individual contract. A
/// single request can query for any mix of the three types of storage proofs (classes,
/// contracts, and storage).
#[method(name = "getStorageProof")]
async fn get_storage_proof(
&self,
block_id: BlockIdOrTag,
class_hashes: Option<Vec<ClassHash>>,
contract_addresses: Option<Vec<ContractAddress>>,
contracts_storage_keys: Option<Vec<ContractStorageKeys>>,
) -> RpcResult<GetStorageProofResponse>;
}

/// Write API.
Expand Down
19 changes: 13 additions & 6 deletions crates/katana/rpc/rpc-types-builder/src/state_update.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use katana_primitives::block::BlockHashOrNumber;
use katana_primitives::Felt;
use katana_provider::traits::block::{BlockHashProvider, BlockNumberProvider};
use katana_provider::traits::state::StateRootProvider;
use katana_provider::traits::state::{StateFactoryProvider, StateRootProvider};
use katana_provider::traits::state_update::StateUpdateProvider;
use katana_provider::ProviderResult;
use katana_rpc_types::state_update::{StateDiff, StateUpdate};
Expand All @@ -21,7 +21,7 @@ impl<P> StateUpdateBuilder<P> {

impl<P> StateUpdateBuilder<P>
where
P: BlockHashProvider + BlockNumberProvider + StateRootProvider + StateUpdateProvider,
P: BlockHashProvider + BlockNumberProvider + StateFactoryProvider + StateUpdateProvider,
{
/// Builds a state update for the given block.
pub fn build(self) -> ProviderResult<Option<StateUpdate>> {
Expand All @@ -30,16 +30,23 @@ where
return Ok(None);
};

let new_root = StateRootProvider::state_root(&self.provider, self.block_id)?
.expect("should exist if block exists");
let new_root = self
.provider
.historical(self.block_id)?
.expect("should exist if block exists")
.state_root()?;

let old_root = {
let block_num = BlockNumberProvider::block_number_by_hash(&self.provider, block_hash)?
.expect("should exist if block exists");

match block_num {
0 => Felt::ZERO,
_ => StateRootProvider::state_root(&self.provider, (block_num - 1).into())?
.expect("should exist if not genesis"),
_ => self
.provider
.historical((block_num - 1).into())?
.expect("should exist if block exists")
.state_root()?,
}
};

Expand Down
1 change: 1 addition & 0 deletions crates/katana/rpc/rpc-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ katana-executor.workspace = true
katana-pool.workspace = true
katana-primitives.workspace = true
katana-provider.workspace = true
katana-trie.workspace = true

anyhow.workspace = true
derive_more.workspace = true
Expand Down
1 change: 1 addition & 0 deletions crates/katana/rpc/rpc-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod receipt;
pub mod state_update;
pub mod trace;
pub mod transaction;
pub mod trie;
mod utils;

use std::ops::Deref;
Expand Down
Loading

0 comments on commit b9f27ae

Please sign in to comment.