Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: move RPC-related structs from mod to domain #608

Merged
merged 8 commits into from
Nov 29, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

### Changes

* [BREAKING] Moved structs from `miden-client::rpc` to `miden-client::rpc::domain::*` and changed prost-generated code location (#608, #610, #615).
* Refactored `Client::import_note` to return an error when the note is already being processed (#602).
* [BREAKING] Added per transaction prover support to the client (#599).
* [BREAKING] Removed unused dependencies (#584).
Expand Down
10 changes: 5 additions & 5 deletions crates/rust-client/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use miden_rpc_proto::write_proto;
use miette::IntoDiagnostic;
use prost::Message;

const TONIC_CLIENT_PROTO_OUT_DIR: &str = "src/rpc/tonic_client/generated";
const WEB_TONIC_CLIENT_PROTO_OUT_DIR: &str = "src/rpc/web_tonic_client/generated";
const STD_PROTO_OUT_DIR: &str = "src/rpc/generated/std";
const NO_STD_PROTO_OUT_DIR: &str = "src/rpc/generated/nostd";

fn main() -> miette::Result<()> {
println!("cargo:rerun-if-changed=Cargo.toml");
Expand Down Expand Up @@ -59,15 +59,15 @@ fn compile_tonic_client_proto(proto_dir: &Path) -> miette::Result<()> {
.build_server(false)
.file_descriptor_set_path(&file_descriptor_path)
.skip_protoc_run()
.out_dir(WEB_TONIC_CLIENT_PROTO_OUT_DIR)
.out_dir(NO_STD_PROTO_OUT_DIR)
.compile_protos_with_config(web_tonic_prost_config, protos, includes)
.into_diagnostic()?;

tonic_build::configure()
.build_server(false)
.file_descriptor_set_path(&file_descriptor_path)
.skip_protoc_run()
.out_dir(TONIC_CLIENT_PROTO_OUT_DIR)
.out_dir(STD_PROTO_OUT_DIR)
.compile_protos_with_config(prost_config, protos, includes)
.into_diagnostic()?;

Expand All @@ -78,7 +78,7 @@ fn compile_tonic_client_proto(proto_dir: &Path) -> miette::Result<()> {
/// for the web tonic client. This is needed as `tonic_build` doesn't generate `no_std` compatible
/// files and we want to build wasm without `std`.
fn replace_no_std_types() {
let path = WEB_TONIC_CLIENT_PROTO_OUT_DIR.to_string() + "/rpc.rs";
let path = NO_STD_PROTO_OUT_DIR.to_string() + "/rpc.rs";
let file_str = fs::read_to_string(&path).unwrap();
let new_file_str = file_str
.replace("std::result", "core::result")
Expand Down
10 changes: 7 additions & 3 deletions crates/rust-client/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ use uuid::Uuid;

use crate::{
rpc::{
domain::{
accounts::{AccountDetails, AccountProofs},
notes::{NoteDetails, NoteInclusionDetails, NoteSyncInfo},
sync::StateSyncInfo,
},
generated::{
note::NoteSyncRecord,
responses::{NullifierUpdate, SyncNoteResponse, SyncStateResponse},
},
AccountDetails, AccountProofs, NodeRpcClient, NoteDetails, NoteInclusionDetails, RpcError,
StateSyncInfo,
NodeRpcClient, RpcError,
},
store::{sqlite_store::SqliteStore, StoreAuthenticator},
Client,
Expand Down Expand Up @@ -205,7 +209,7 @@ impl NodeRpcClient for MockRpcApi {
&mut self,
_block_num: u32,
_note_tags: &[NoteTag],
) -> Result<crate::rpc::NoteSyncInfo, RpcError> {
) -> Result<NoteSyncInfo, RpcError> {
let response = SyncNoteResponse {
chain_tip: self.blocks.len() as u32,
notes: vec![],
Expand Down
7 changes: 4 additions & 3 deletions crates/rust-client/src/notes/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use miden_objects::{
};

use crate::{
rpc::domain::notes::NoteDetails as RpcNoteDetails,
store::{input_note_states::ExpectedNoteState, InputNoteRecord, InputNoteState},
sync::NoteTagRecord,
Client, ClientError,
Expand Down Expand Up @@ -87,7 +88,7 @@ impl<R: FeltRng> Client<R> {
return Err(ClientError::NoteNotFoundOnChain(id));
}

let note_details: crate::rpc::NoteDetails =
let note_details: RpcNoteDetails =
chain_notes.pop().expect("chain_notes should have at least one element");

let inclusion_details = note_details.inclusion_details();
Expand All @@ -113,8 +114,8 @@ impl<R: FeltRng> Client<R> {
},
None => {
let node_note = match note_details {
crate::rpc::NoteDetails::Public(note, _) => note,
crate::rpc::NoteDetails::Private(..) => {
RpcNoteDetails::Public(note, _) => note,
RpcNoteDetails::Private(..) => {
return Err(ClientError::NoteImportError(
"Incomplete imported note is private".to_string(),
))
Expand Down
179 changes: 163 additions & 16 deletions crates/rust-client/src/rpc/domain/accounts.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,65 @@
use alloc::string::{String, ToString};
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::fmt::{self, Debug, Display, Formatter};

use miden_objects::{
accounts::{AccountCode, AccountHeader, AccountId, AccountStorageHeader},
Felt,
accounts::{Account, AccountCode, AccountHeader, AccountId, AccountStorageHeader},
crypto::merkle::MerklePath,
Digest, Felt,
};
use miden_tx::utils::Deserializable;

#[cfg(feature = "tonic")]
use crate::rpc::{
tonic_client::generated::account::AccountHeader as ProtoAccountHeader,
tonic_client::generated::account::AccountId as ProtoAccountId,
tonic_client::generated::responses::AccountStateHeader as ProtoAccountStateHeader,
RpcConversionError,
};
#[cfg(feature = "web-tonic")]
use crate::rpc::{
web_tonic_client::generated::account::AccountHeader as ProtoAccountHeader,
web_tonic_client::generated::account::AccountId as ProtoAccountId,
web_tonic_client::generated::responses::AccountStateHeader as ProtoAccountStateHeader,
RpcConversionError,
errors::RpcConversionError,
generated::{
account::{AccountHeader as ProtoAccountHeader, AccountId as ProtoAccountId},
responses::AccountStateHeader as ProtoAccountStateHeader,
},
RpcError,
};
use crate::rpc::{RpcError, StateHeaders};

// ACCOUNT DETAILS
// ================================================================================================

/// Describes the possible responses from the `GetAccountDetails` endpoint for an account
pub enum AccountDetails {
/// Private accounts are stored off-chain. Only a commitment to the state of the account is
/// shared with the network. The full account state is to be tracked locally.
Private(AccountId, AccountUpdateSummary),
/// Public accounts are recorded on-chain. As such, its state is shared with the network and
/// can always be retrieved through the appropriate RPC method.
Public(Account, AccountUpdateSummary),
}

impl AccountDetails {
/// Returns the account ID.
pub fn account_id(&self) -> AccountId {
match self {
Self::Private(account_id, _) => *account_id,
Self::Public(account, _) => account.id(),
}
}
}

// ACCOUNT UPDATE SUMMARY
// ================================================================================================

/// Contains public updated information about the account requested.
pub struct AccountUpdateSummary {
/// Hash of the account, that represents a commitment to its updated state.
pub hash: Digest,
/// Block number of last account update.
pub last_block_num: u32,
}

impl AccountUpdateSummary {
/// Creates a new [AccountUpdateSummary].
pub fn new(hash: Digest, last_block_num: u32) -> Self {
Self { hash, last_block_num }
}
}

// ACCOUNT ID
// ================================================================================================
Expand Down Expand Up @@ -109,3 +147,112 @@ impl ProtoAccountStateHeader {
})
}
}

// ACCOUNT PROOF
// ================================================================================================

/// Contains a block number, and a list of account proofs at that block.
pub type AccountProofs = (u32, Vec<AccountProof>);

/// Account state headers.
pub struct StateHeaders {
pub account_header: AccountHeader,
pub storage_header: AccountStorageHeader,
pub code: Option<AccountCode>,
}

/// Represents a proof of existence of an account's state at a specific block number.
pub struct AccountProof {
/// Account ID.
account_id: AccountId,
/// Authentication path from the `account_root` of the block header to the account.
merkle_proof: MerklePath,
/// Account hash for the current state.
account_hash: Digest,
/// State headers of public accounts.
state_headers: Option<StateHeaders>,
}

impl AccountProof {
pub fn new(
account_id: AccountId,
merkle_proof: MerklePath,
account_hash: Digest,
state_headers: Option<StateHeaders>,
) -> Result<Self, AccountProofError> {
if let Some(StateHeaders { account_header, storage_header: _, code }) = &state_headers {
if account_header.hash() != account_hash {
return Err(AccountProofError::InconsistentAccountHash);
}
if account_id != account_header.id() {
return Err(AccountProofError::InconsistentAccountId);
}
if let Some(code) = code {
if code.commitment() != account_header.code_commitment() {
return Err(AccountProofError::InconsistentCodeCommitment);
}
}
}

Ok(Self {
account_id,
merkle_proof,
account_hash,
state_headers,
})
}

pub fn account_id(&self) -> AccountId {
self.account_id
}

pub fn account_header(&self) -> Option<&AccountHeader> {
self.state_headers.as_ref().map(|headers| &headers.account_header)
}

pub fn storage_header(&self) -> Option<&AccountStorageHeader> {
self.state_headers.as_ref().map(|headers| &headers.storage_header)
}

pub fn account_code(&self) -> Option<&AccountCode> {
if let Some(StateHeaders { code, .. }) = &self.state_headers {
code.as_ref()
} else {
None
}
}

pub fn code_commitment(&self) -> Option<Digest> {
match &self.state_headers {
Some(StateHeaders { code: Some(code), .. }) => Some(code.commitment()),
_ => None,
}
}

pub fn account_hash(&self) -> Digest {
self.account_hash
}

pub fn merkle_proof(&self) -> &MerklePath {
&self.merkle_proof
}
}

// ERRORS
// ================================================================================================

pub enum AccountProofError {
InconsistentAccountHash,
InconsistentAccountId,
InconsistentCodeCommitment,
}

impl fmt::Display for AccountProofError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AccountProofError::InconsistentAccountHash => write!(f,"The received account hash does not match the received account header's account hash"),
AccountProofError::InconsistentAccountId => write!(f,"The received account ID does not match the received account header's ID"),
AccountProofError::InconsistentCodeCommitment => write!(f,"The received code commitment does not match the received account header's code commitment"),
}
}
}
6 changes: 1 addition & 5 deletions crates/rust-client/src/rpc/domain/blocks.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
use miden_objects::{crypto::merkle::MerklePath, BlockHeader};

use super::MissingFieldHelper;
#[cfg(feature = "tonic")]
use crate::rpc::tonic_client::generated::block;
#[cfg(feature = "web-tonic")]
use crate::rpc::web_tonic_client::generated::block;
use crate::rpc::RpcConversionError;
use crate::rpc::{errors::RpcConversionError, generated::block};

// BLOCK HEADER
// ================================================================================================
Expand Down
6 changes: 1 addition & 5 deletions crates/rust-client/src/rpc/domain/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ use core::fmt::{self, Debug, Display, Formatter};
use hex::ToHex;
use miden_objects::{notes::NoteId, Digest, Felt, StarkField};

#[cfg(feature = "tonic")]
use crate::rpc::tonic_client::generated::digest;
#[cfg(feature = "web-tonic")]
use crate::rpc::web_tonic_client::generated::digest;
use crate::rpc::RpcConversionError;
use crate::rpc::{errors::RpcConversionError, generated::digest};

// CONSTANTS
// ================================================================================================
Expand Down
6 changes: 1 addition & 5 deletions crates/rust-client/src/rpc/domain/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ use miden_objects::{
Digest,
};

#[cfg(feature = "tonic")]
use crate::rpc::tonic_client::generated;
#[cfg(feature = "web-tonic")]
use crate::rpc::web_tonic_client::generated;
use crate::rpc::RpcConversionError;
use crate::rpc::{errors::RpcConversionError, generated};

// MERKLE PATH
// ================================================================================================
Expand Down
3 changes: 2 additions & 1 deletion crates/rust-client/src/rpc/domain/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use core::any::type_name;

use crate::rpc::RpcConversionError;
use super::errors::RpcConversionError;

pub mod accounts;
pub mod blocks;
pub mod digest;
pub mod merkle;
pub mod notes;
pub mod nullifiers;
pub mod sync;
pub mod transactions;

// UTILITIES
Expand Down
Loading