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

Implemented GetAccountProofs endpoint #506

Merged
merged 14 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Optimized state synchronizations by removing unnecessary fetching and parsing of note details (#462).
- [BREAKING] Changed `GetAccountDetailsResponse` field to `details` (#481).
- Improve `--version` by adding build metadata (#495).
- Added `GetAccountStates` endpoint (#506).

## 0.5.1 (2024-09-12)

Expand Down
18 changes: 15 additions & 3 deletions crates/proto/src/domain/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fmt::{Debug, Display, Formatter};

use miden_node_utils::formatting::format_opt;
use miden_objects::{
accounts::{Account, AccountId},
accounts::{Account, AccountHeader, AccountId},
crypto::{hash::rpo::RpoDigest, merkle::MerklePath},
utils::Serializable,
Digest,
Expand All @@ -12,8 +12,8 @@ use crate::{
errors::{ConversionError, MissingFieldHelper},
generated::{
account::{
AccountId as AccountIdPb, AccountInfo as AccountInfoPb,
AccountSummary as AccountSummaryPb,
AccountHeader as AccountHeaderPb, AccountId as AccountIdPb,
AccountInfo as AccountInfoPb, AccountSummary as AccountSummaryPb,
},
responses::{AccountBlockInputRecord, AccountTransactionInputRecord},
},
Expand Down Expand Up @@ -180,6 +180,18 @@ impl From<AccountState> for AccountTransactionInputRecord {
}
}

impl From<AccountHeader> for AccountHeaderPb {
fn from(from: AccountHeader) -> Self {
Self {
account_id: Some(from.id().into()),
vault_root: Some(from.vault_root().into()),
storage_commitment: Some(from.storage_commitment().into()),
code_commitment: Some(from.code_commitment().into()),
nonce: from.nonce().try_into().expect("Nonce should fit in `u32`"),
}
}
}

impl TryFrom<AccountTransactionInputRecord> for AccountState {
type Error = ConversionError;

Expand Down
18 changes: 18 additions & 0 deletions crates/proto/src/generated/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,21 @@ pub struct AccountInfo {
#[prost(bytes = "vec", optional, tag = "2")]
pub details: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct AccountHeader {
/// Account ID.
#[prost(message, optional, tag = "1")]
pub account_id: ::core::option::Option<AccountId>,
/// Vault root hash.
#[prost(message, optional, tag = "2")]
pub vault_root: ::core::option::Option<super::digest::Digest>,
/// Storage root hash.
#[prost(message, optional, tag = "3")]
pub storage_commitment: ::core::option::Option<super::digest::Digest>,
/// Code root hash.
#[prost(message, optional, tag = "4")]
pub code_commitment: ::core::option::Option<super::digest::Digest>,
/// Account nonce.
#[prost(uint32, tag = "5")]
pub nonce: u32,
}
27 changes: 27 additions & 0 deletions crates/proto/src/generated/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,30 @@ pub struct GetAccountStateDeltaRequest {
#[prost(fixed32, tag = "3")]
pub to_block_num: u32,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountStatesRequest {
/// List of account state requests.
#[prost(message, repeated, tag = "1")]
pub account_state_requests: ::prost::alloc::vec::Vec<AccountStateRequest>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AccountStateRequest {
/// ID of the account for which we'd like to retrieve the state.
#[prost(message, optional, tag = "1")]
pub account_id: ::core::option::Option<super::account::AccountId>,
/// Keys of storage maps for which we'd like to get values.
#[prost(message, repeated, tag = "2")]
pub storage_map_keys: ::prost::alloc::vec::Vec<StorageMapKey>,
/// Whether to include assets in the response.
#[prost(bool, tag = "3")]
pub include_assets: bool,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct StorageMapKey {
/// Index of the storage slot containing the storage map.
#[prost(uint32, tag = "1")]
pub slot_index: u32,
/// Key for which we want to request the value.
#[prost(message, optional, tag = "2")]
pub key: ::core::option::Option<super::digest::Digest>,
}
36 changes: 36 additions & 0 deletions crates/proto/src/generated/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,39 @@ pub struct GetAccountStateDeltaResponse {
#[prost(bytes = "vec", optional, tag = "1")]
pub delta: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountStatesResponse {
/// Block number at which the state of the account was returned.
#[prost(fixed32, tag = "1")]
pub block_num: u32,
/// List of account state infos for the requested account keys.
#[prost(message, repeated, tag = "2")]
pub account_state_infos: ::prost::alloc::vec::Vec<AccountStateResponse>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AccountStateResponse {
/// Account header.
#[prost(message, optional, tag = "1")]
pub header: ::core::option::Option<super::account::AccountHeader>,
/// Authentication path from the `account_root` of the block header to the account.
#[prost(message, optional, tag = "2")]
pub account_proof: ::core::option::Option<super::merkle::MerklePath>,
/// / Values of all account storage slots (max 255).
#[prost(bytes = "vec", tag = "3")]
pub storage_header: ::prost::alloc::vec::Vec<u8>,
/// A list of key-value pairs (and their corresponding proofs) for the requested keys.
#[prost(message, repeated, tag = "4")]
pub map_items: ::prost::alloc::vec::Vec<StorageMapItem>,
/// An optional list of all assets in the account.
#[prost(bytes = "vec", repeated, tag = "5")]
pub assets: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StorageMapItem {
/// Index of the storage slot containing the storage map.
#[prost(uint32, tag = "1")]
pub slot_index: u32,
/// Opening containing key, value, and a proof attesting that the key opens to the value.
#[prost(message, optional, tag = "2")]
pub opening: ::core::option::Option<super::smt::SmtOpening>,
}
79 changes: 79 additions & 0 deletions crates/proto/src/generated/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,30 @@ pub mod api_client {
req.extensions_mut().insert(GrpcMethod::new("rpc.Api", "GetAccountDetails"));
self.inner.unary(req, path, codec).await
}
pub async fn get_account_states(
&mut self,
request: impl tonic::IntoRequest<
super::super::requests::GetAccountStatesRequest,
>,
) -> std::result::Result<
tonic::Response<super::super::responses::GetAccountStatesResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static("/rpc.Api/GetAccountStates");
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new("rpc.Api", "GetAccountStates"));
self.inner.unary(req, path, codec).await
}
pub async fn get_account_state_delta(
&mut self,
request: impl tonic::IntoRequest<
Expand Down Expand Up @@ -364,6 +388,13 @@ pub mod api_server {
tonic::Response<super::super::responses::GetAccountDetailsResponse>,
tonic::Status,
>;
async fn get_account_states(
&self,
request: tonic::Request<super::super::requests::GetAccountStatesRequest>,
) -> std::result::Result<
tonic::Response<super::super::responses::GetAccountStatesResponse>,
tonic::Status,
>;
async fn get_account_state_delta(
&self,
request: tonic::Request<super::super::requests::GetAccountStateDeltaRequest>,
Expand Down Expand Up @@ -639,6 +670,54 @@ pub mod api_server {
};
Box::pin(fut)
}
"/rpc.Api/GetAccountStates" => {
#[allow(non_camel_case_types)]
struct GetAccountStatesSvc<T: Api>(pub Arc<T>);
impl<
T: Api,
> tonic::server::UnaryService<
super::super::requests::GetAccountStatesRequest,
> for GetAccountStatesSvc<T> {
type Response = super::super::responses::GetAccountStatesResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<
super::super::requests::GetAccountStatesRequest,
>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as Api>::get_account_states(&inner, request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let max_decoding_message_size = self.max_decoding_message_size;
let max_encoding_message_size = self.max_encoding_message_size;
let inner = self.inner.clone();
let fut = async move {
let method = GetAccountStatesSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
)
.apply_max_message_size_config(
max_decoding_message_size,
max_encoding_message_size,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
"/rpc.Api/GetAccountStateDelta" => {
#[allow(non_camel_case_types)]
struct GetAccountStateDeltaSvc<T: Api>(pub Arc<T>);
Expand Down
82 changes: 82 additions & 0 deletions crates/proto/src/generated/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,33 @@ pub mod api_client {
.insert(GrpcMethod::new("store.Api", "GetAccountDetails"));
self.inner.unary(req, path, codec).await
}
pub async fn get_account_states(
&mut self,
request: impl tonic::IntoRequest<
super::super::requests::GetAccountStatesRequest,
>,
) -> std::result::Result<
tonic::Response<super::super::responses::GetAccountStatesResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/store.Api/GetAccountStates",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("store.Api", "GetAccountStates"));
self.inner.unary(req, path, codec).await
}
pub async fn get_account_state_delta(
&mut self,
request: impl tonic::IntoRequest<
Expand Down Expand Up @@ -518,6 +545,13 @@ pub mod api_server {
tonic::Response<super::super::responses::GetAccountDetailsResponse>,
tonic::Status,
>;
async fn get_account_states(
&self,
request: tonic::Request<super::super::requests::GetAccountStatesRequest>,
) -> std::result::Result<
tonic::Response<super::super::responses::GetAccountStatesResponse>,
tonic::Status,
>;
async fn get_account_state_delta(
&self,
request: tonic::Request<super::super::requests::GetAccountStateDeltaRequest>,
Expand Down Expand Up @@ -876,6 +910,54 @@ pub mod api_server {
};
Box::pin(fut)
}
"/store.Api/GetAccountStates" => {
#[allow(non_camel_case_types)]
struct GetAccountStatesSvc<T: Api>(pub Arc<T>);
impl<
T: Api,
> tonic::server::UnaryService<
super::super::requests::GetAccountStatesRequest,
> for GetAccountStatesSvc<T> {
type Response = super::super::responses::GetAccountStatesResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<
super::super::requests::GetAccountStatesRequest,
>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as Api>::get_account_states(&inner, request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let max_decoding_message_size = self.max_decoding_message_size;
let max_encoding_message_size = self.max_encoding_message_size;
let inner = self.inner.clone();
let fut = async move {
let method = GetAccountStatesSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
)
.apply_max_message_size_config(
max_decoding_message_size,
max_encoding_message_size,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
"/store.Api/GetAccountStateDelta" => {
#[allow(non_camel_case_types)]
struct GetAccountStateDeltaSvc<T: Api>(pub Arc<T>);
Expand Down
13 changes: 13 additions & 0 deletions crates/rpc-proto/proto/account.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,16 @@ message AccountInfo {
AccountSummary summary = 1;
optional bytes details = 2;
}

message AccountHeader {
// Account ID.
account.AccountId account_id = 1;
// Vault root hash.
digest.Digest vault_root = 2;
// Storage root hash.
digest.Digest storage_commitment = 3;
// Code root hash.
digest.Digest code_commitment = 4;
// Account nonce.
uint32 nonce = 5;
}
23 changes: 23 additions & 0 deletions crates/rpc-proto/proto/requests.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package requests;

import "account.proto";
import "digest.proto";
import "merkle.proto";
import "note.proto";
import "smt.proto";

message ApplyBlockRequest {
bytes block = 1;
Expand Down Expand Up @@ -131,3 +133,24 @@ message GetAccountStateDeltaRequest {
// Block number up to which the delta is requested (inclusive).
fixed32 to_block_num = 3;
}

message GetAccountStatesRequest {
// List of account state requests.
repeated AccountStateRequest account_state_requests = 1;
}

message AccountStateRequest {
// ID of the account for which we'd like to retrieve the state.
account.AccountId account_id = 1;
// Keys of storage maps for which we'd like to get values.
repeated StorageMapKey storage_map_keys = 2;
// Whether to include assets in the response.
bool include_assets = 3;
}

message StorageMapKey {
// Index of the storage slot containing the storage map.
uint32 slot_index = 1;
// Key for which we want to request the value.
digest.Digest key = 2;
}
Loading
Loading