Skip to content

Commit

Permalink
Fetch class proof from pathfinder v0_8
Browse files Browse the repository at this point in the history
  • Loading branch information
GMKrieger committed Jan 8, 2025
1 parent 351a9b7 commit a7e5cee
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 7 deletions.
39 changes: 35 additions & 4 deletions crates/bin/prove_block/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use cairo_vm::vm::errors::cairo_run_errors::CairoRunError;
use cairo_vm::vm::runners::cairo_pie::CairoPie;
use cairo_vm::Felt252;
use reexecute::{reexecute_transactions_with_blockifier, ProverPerContractStorage};
use rpc_client::pathfinder::proofs::{PathfinderClassProof, ProofVerificationError};
use rpc_client::pathfinder::proofs::{PathfinderClassProof, ProofVerificationError, StorageProof};
use rpc_client::RpcClient;
use rpc_replay::block_context::build_block_context;
use rpc_replay::rpc_state_reader::AsyncRpcStateReader;
use rpc_replay::transactions::{starknet_rs_to_blockifier, ToBlockifierError};
use rpc_replay::utils::FeltConversionError;
use rpc_utils::{get_class_proofs, get_storage_proofs};
use rpc_utils::{get_08_class_proofs, get_class_proofs, get_storage_proofs};
use starknet::core::types::{BlockId, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, StarknetError};
use starknet::providers::{Provider, ProviderError};
use starknet_api::StarknetApiError;
Expand All @@ -38,7 +38,7 @@ use starknet_types_core::felt::Felt;
use state_utils::get_formatted_state_update;
use thiserror::Error;

use crate::reexecute::format_commitment_facts;
use crate::reexecute::{format_08_commitment_facts, format_commitment_facts};
use crate::rpc_utils::get_starknet_version;
use crate::types::starknet_rs_tx_to_internal_tx;

Expand Down Expand Up @@ -112,6 +112,28 @@ fn compute_class_commitment(
CommitmentInfo { previous_root, updated_root, tree_height: 251, commitment_facts: class_commitment_facts }
}

fn compute_08_class_commitment(
previous_class_proofs: &StorageProof,
class_proofs: &StorageProof,
previous_root: Felt,
updated_root: Felt,
) -> CommitmentInfo {
let previous_class_proofs: Vec<_> =
previous_class_proofs.classes_proof.clone().into_iter().map(|proof| proof.node).collect();
let class_proofs: Vec<_> = class_proofs.classes_proof.clone().into_iter().map(|proof| proof.node).collect();

let previous_class_commitment_facts = format_08_commitment_facts::<PoseidonHash>(&previous_class_proofs);
let current_class_commitment_facts = format_08_commitment_facts::<PoseidonHash>(&class_proofs);

let class_commitment_facts: HashMap<_, _> =
previous_class_commitment_facts.into_iter().chain(current_class_commitment_facts).collect();

log::debug!("previous class trie root: {}", previous_root.to_hex_string());
log::debug!("current class trie root: {}", updated_root.to_hex_string());

CommitmentInfo { previous_root, updated_root, tree_height: 251, commitment_facts: class_commitment_facts }
}

pub async fn prove_block(
compiled_os: &[u8],
block_number: u64,
Expand Down Expand Up @@ -282,6 +304,12 @@ pub async fn prove_block(
let class_hashes: Vec<&Felt252> = class_hash_to_compiled_class_hash.keys().collect();
// TODO: we fetch proofs here for block-1, but we probably also need to fetch at the current
// block, likely for contracts that are deployed in this block
let class_proofs_08 =
get_08_class_proofs(&rpc_client, block_number, &class_hashes[..]).await.expect("Failed to fetch class proofs");
let previous_class_proofs_08 = get_08_class_proofs(&rpc_client, block_number - 1, &class_hashes[..])
.await
.expect("Failed to fetch previous class proofs");

let class_proofs =
get_class_proofs(&rpc_client, block_number, &class_hashes[..]).await.expect("Failed to fetch class proofs");
let previous_class_proofs = get_class_proofs(&rpc_client, block_number - 1, &class_hashes[..])
Expand Down Expand Up @@ -339,9 +367,12 @@ pub async fn prove_block(
let contract_class_commitment_info =
compute_class_commitment(&previous_class_proofs, &class_proofs, previous_root, updated_root);

let contract_class_commitment_info_08 =
compute_08_class_commitment(&previous_class_proofs_08, &class_proofs_08, previous_root, updated_root);

let os_input = Rc::new(StarknetOsInput {
contract_state_commitment_info,
contract_class_commitment_info,
contract_class_commitment_info: contract_class_commitment_info_08,
deprecated_compiled_classes,
compiled_classes,
compiled_class_visited_pcs: visited_pcs,
Expand Down
41 changes: 40 additions & 1 deletion crates/bin/prove_block/src/reexecute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use blockifier::transaction::objects::TransactionExecutionInfo;
use blockifier::transaction::transaction_execution::Transaction;
use blockifier::transaction::transactions::ExecutableTransaction;
use cairo_vm::Felt252;
use rpc_client::pathfinder::proofs::{ContractData, PathfinderProof, TrieNode};
use rpc_client::pathfinder::proofs::{ContractData, MerkleNode, PathfinderProof, PathfinderProof, TrieNode, TrieNode};
use rpc_client::RpcClient;
use starknet::core::types::{BlockId, StarknetError};
use starknet::providers::{Provider as _, ProviderError};
Expand Down Expand Up @@ -160,6 +160,45 @@ pub(crate) fn format_commitment_facts<H: HashFunctionType>(
facts
}

pub(crate) fn format_08_commitment_facts<H: HashFunctionType>(
trie_nodes: &Vec<MerkleNode>,
) -> HashMap<Felt252, Vec<Felt252>> {
let mut facts = HashMap::new();

for node in trie_nodes {
let (key, fact_as_tuple) = match node {
MerkleNode::Binary { left, right } => {
let fact = BinaryNodeFact::new((*left).into(), (*right).into())
.expect("storage proof endpoint gave us an invalid binary node");

// TODO: the hash function should probably be split from the Fact trait.
// we use a placeholder for the Storage trait in the meantime.
let node_hash = Felt252::from(<BinaryNodeFact as Fact<DictStorage, H>>::hash(&fact));
let fact_as_tuple = <BinaryNodeFact as InnerNodeFact<DictStorage, H>>::to_tuple(&fact);

(node_hash, fact_as_tuple)
}
MerkleNode::Edge { child, path, length } => {
let len = *length;
let fact =
EdgeNodeFact::new((*child).into(), NodePath(path.to_biguint()), Length(len.try_into().unwrap()))
.expect("storage proof endpoint gave us an invalid edge node");
// TODO: the hash function should probably be split from the Fact trait.
// we use a placeholder for the Storage trait in the meantime.
let node_hash = Felt252::from(<EdgeNodeFact as Fact<DictStorage, H>>::hash(&fact));
let fact_as_tuple = <EdgeNodeFact as InnerNodeFact<DictStorage, H>>::to_tuple(&fact);

(node_hash, fact_as_tuple)
}
};

let fact_as_tuple_of_felts: Vec<_> = fact_as_tuple.into_iter().map(Felt252::from).collect();
facts.insert(key, fact_as_tuple_of_felts);
}

facts
}

impl PerContractStorage for ProverPerContractStorage {
async fn compute_commitment(&mut self) -> Result<CommitmentInfo, CommitmentInfoError> {
// TODO: error code
Expand Down
10 changes: 9 additions & 1 deletion crates/bin/prove_block/src/rpc_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cairo_vm::Felt252;
use num_bigint::BigInt;
use rpc_client::pathfinder::client::ClientError;
use rpc_client::pathfinder::proofs::{
ContractData, EdgePath, PathfinderClassProof, PathfinderProof, ProofVerificationError, TrieNode,
ContractData, EdgePath, PathfinderClassProof, PathfinderProof, ProofVerificationError, StorageProof, TrieNode,
};
use rpc_client::RpcClient;
use starknet::core::types::BlockWithTxs;
Expand Down Expand Up @@ -240,6 +240,14 @@ pub(crate) async fn get_class_proofs(
Ok(proofs)
}

pub(crate) async fn get_08_class_proofs(
rpc_client: &RpcClient,
block_number: u64,
class_hashes: &[&Felt],
) -> Result<StorageProof, ClientError> {
rpc_client.pathfinder_rpc().get_storage_class_proof(block_number, class_hashes).await
}

pub(crate) fn get_starknet_version(block_with_txs: &BlockWithTxs) -> blockifier::versioned_constants::StarknetVersion {
let starknet_version_str = &block_with_txs.starknet_version;
match starknet_version_str.as_ref() {
Expand Down
35 changes: 34 additions & 1 deletion crates/rpc-client/src/pathfinder/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde_json::json;
use starknet::core::types::TransactionTraceWithHash;
use starknet_types_core::felt::Felt;

use crate::pathfinder::proofs::{PathfinderClassProof, PathfinderProof};
use crate::pathfinder::proofs::{PathfinderClassProof, PathfinderProof, StorageProof};

#[derive(Debug, thiserror::Error)]
pub enum ClientError {
Expand Down Expand Up @@ -62,6 +62,25 @@ async fn post_jsonrpc_07_request<T: DeserializeOwned>(
Ok(response.result)
}

async fn post_jsonrpc_08_request<T: DeserializeOwned>(
client: &reqwest::Client,
rpc_provider: &str,
method: &str,
params: serde_json::Value,
) -> Result<T, ClientError> {
let request = jsonrpc_request(method, params);
let response = client.post(format!("{}/rpc/v0_8", rpc_provider)).json(&request).send().await?;

#[derive(Deserialize)]
struct TransactionReceiptResponse<T> {
result: T,
}

let response: TransactionReceiptResponse<T> = handle_error(response).await?;

Ok(response.result)
}

async fn handle_error<T: DeserializeOwned>(response: Response) -> Result<T, ClientError> {
match response.status() {
StatusCode::OK => Ok(response.json().await?),
Expand Down Expand Up @@ -117,6 +136,20 @@ impl PathfinderRpcClient {
.await
}

pub async fn get_storage_class_proof(
&self,
block_number: u64,
class_hashes: &[&Felt],
) -> Result<StorageProof, ClientError> {
post_jsonrpc_08_request(
&self.http_client,
&self.rpc_base_url,
"starknet_getStorageProof",
json!({ "block_id": { "block_number": block_number }, "class_hashes": class_hashes }),
)
.await
}

pub async fn get_block_traces(&self, block_number: u64) -> Result<Vec<TransactionTraceWithHash>, ClientError> {
post_jsonrpc_07_request(
&self.http_client,
Expand Down
46 changes: 46 additions & 0 deletions crates/rpc-client/src/pathfinder/proofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,49 @@ pub fn verify_proof<H: HashFunctionType>(

Ok(())
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct ContractStorageKeysItem {
pub contract_address: Felt,
pub storage_keys: Vec<Felt>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(untagged)]
pub enum MerkleNode {
Binary { left: Felt, right: Felt },
Edge { child: Felt, path: Felt, length: usize },
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct NodeHashToNodeMappingItem {
pub node_hash: Felt,
pub node: MerkleNode,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct ContractLeavesDataItem {
pub nonce: Felt,
pub class_hash: Felt,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct ContractsProof {
pub nodes: Vec<NodeHashToNodeMappingItem>,
pub contract_leaves_data: Vec<ContractLeavesDataItem>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct GlobalRoots {
pub contracts_tree_root: Felt,
pub classes_tree_root: Felt,
pub block_hash: Felt,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct StorageProof {
pub classes_proof: Vec<NodeHashToNodeMappingItem>,
pub contracts_proof: ContractsProof,
pub contracts_storage_proofs: Vec<Vec<NodeHashToNodeMappingItem>>,
pub global_roots: GlobalRoots,
}

0 comments on commit a7e5cee

Please sign in to comment.