Skip to content

Commit

Permalink
Added support for on-chain (public) accounts in store (#293)
Browse files Browse the repository at this point in the history
* feat: add `account_details` table to the DB

* refactor: rename `block_number` column in nullifiers table to `block_num`

* refactor: use `BETWEEN` in interval comparison checks

* feat: implement account details protobuf messages, domain objects and conversions

* feat: (WIP) implement account details support

* feat: (WIP) implement account details support

* feat: (WIP) implement account details support

* feat: (WIP) implement account details support

* fix: db creation

* docs: remove TODO

* refactor: apply formatting

* feat: implement endpoint for getting public account details

* tests: add test for storage

* feat: add rpc endpoint for getting account details

* refactor: keep only domain object changes

* fix: compilation errors

* fix: use note tag conversion from `u64`

* refactor: remove account details protobuf messages

* fix: remove unused error invariants

* refactor: introduce `UpdatedAccount` struct

* fix: rollback details conversion

* fix: compilation error

* feat: account details in store

* refactor: add constraint name for foreign key

* refactor: small code improvement

Co-authored-by: Augusto Hack <hack.augusto@gmail.com>

* feat: account id validation

* refactor: rename `get_account_details` to `select_*`

* feat: return serialized account details

* feat: add requirement of account id to be public in RPC

* fix: remove error message used in different PR

* fix: union account details with account and process them together

* docs: remove `GetAccountDetails` from README.md

* fix: remove unused error invariants

* fix: use `Account` instead of `AccountDetails` in store

* wip

* feat: implement `GetAccountDetails` endpoint

* docs: document `GetAccountDetails` endpoint

* refactor: simplify code, make account details optional

* fix: clippy warning

* fix: address review comments

* fix: update code to the latest miden-base

* refactor: little code improvement

---------

Co-authored-by: Augusto Hack <hack.augusto@gmail.com>
  • Loading branch information
polydez and hackaugusto authored Apr 6, 2024
1 parent eeae078 commit 2f113f9
Show file tree
Hide file tree
Showing 23 changed files with 649 additions and 238 deletions.
211 changes: 105 additions & 106 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions block-producer/src/test_utils/account.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use miden_objects::{accounts::get_account_seed, Hasher};
use miden_objects::{
accounts::{get_account_seed, AccountStorageType, AccountType},
Hasher,
};

use super::*;

Expand All @@ -19,8 +22,8 @@ impl<const NUM_STATES: usize> MockPrivateAccount<NUM_STATES> {
) -> Self {
let account_seed = get_account_seed(
init_seed,
miden_objects::accounts::AccountType::RegularAccountUpdatableCode,
miden_objects::accounts::AccountStorageType::OffChain,
AccountType::RegularAccountUpdatableCode,
AccountStorageType::OffChain,
Digest::default(),
Digest::default(),
)
Expand Down
11 changes: 8 additions & 3 deletions proto/proto/account.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ message AccountId {
fixed64 id = 1;
}

message AccountInfo {
AccountId account_id = 1;
message AccountHashUpdate {
account.AccountId account_id = 1;
digest.Digest account_hash = 2;
fixed32 block_num = 3;
uint32 block_num = 3;
}

message AccountInfo {
AccountHashUpdate update = 1;
optional bytes details = 2;
}
6 changes: 6 additions & 0 deletions proto/proto/requests.proto
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,9 @@ message ListNullifiersRequest {}
message ListAccountsRequest {}

message ListNotesRequest {}

// Returns the latest state of an account with the specified ID.
message GetAccountDetailsRequest {
// Account ID to get details.
account.AccountId account_id = 1;
}
15 changes: 7 additions & 8 deletions proto/proto/responses.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ message GetBlockHeaderByNumberResponse {
block_header.BlockHeader block_header = 1;
}

message AccountHashUpdate {
account.AccountId account_id = 1;
digest.Digest account_hash = 2;
uint32 block_num = 3;
}

message NullifierUpdate {
digest.Digest nullifier = 1;
fixed32 block_num = 2;
Expand All @@ -42,7 +36,7 @@ message SyncStateResponse {
mmr.MmrDelta mmr_delta = 3;

// a list of account hashes updated after `block_num + 1` but not after `block_header.block_num`
repeated AccountHashUpdate accounts = 5;
repeated account.AccountHashUpdate accounts = 5;

// a list of all notes together with the Merkle paths from `block_header.note_root`
repeated note.NoteSyncRecord notes = 6;
Expand Down Expand Up @@ -71,7 +65,7 @@ message GetBlockInputsResponse {
// Peaks of the above block's mmr, The `forest` value is equal to the block number.
repeated digest.Digest mmr_peaks = 2;

// The hashes of the requested accouts and their authentication paths
// The hashes of the requested accounts and their authentication paths
repeated AccountBlockInputRecord account_states = 3;

// The requested nullifiers and their authentication paths
Expand Down Expand Up @@ -113,3 +107,8 @@ message ListNotesResponse {
// Lists all notes of the current chain
repeated note.Note notes = 1;
}

message GetAccountDetailsResponse {
// Account info (with details for on-chain accounts)
account.AccountInfo account = 1;
}
1 change: 1 addition & 0 deletions proto/proto/rpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ service Api {
rpc GetBlockHeaderByNumber(requests.GetBlockHeaderByNumberRequest) returns (responses.GetBlockHeaderByNumberResponse) {}
rpc SyncState(requests.SyncStateRequest) returns (responses.SyncStateResponse) {}
rpc SubmitProvenTransaction(requests.SubmitProvenTransactionRequest) returns (responses.SubmitProvenTransactionResponse) {}
rpc GetAccountDetails(requests.GetAccountDetailsRequest) returns (responses.GetAccountDetailsResponse) {}
}
1 change: 1 addition & 0 deletions proto/proto/store.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ service Api {
rpc ListNullifiers(requests.ListNullifiersRequest) returns (responses.ListNullifiersResponse) {}
rpc ListAccounts(requests.ListAccountsRequest) returns (responses.ListAccountsResponse) {}
rpc ListNotes(requests.ListNotesRequest) returns (responses.ListNotesResponse) {}
rpc GetAccountDetails(requests.GetAccountDetailsRequest) returns (responses.GetAccountDetailsResponse) {}
}
43 changes: 41 additions & 2 deletions proto/src/domain/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ use std::fmt::{Debug, Display, Formatter};

use miden_node_utils::formatting::format_opt;
use miden_objects::{
accounts::AccountId, crypto::merkle::MerklePath, transaction::AccountDetails, Digest,
accounts::{Account, AccountId},
crypto::{hash::rpo::RpoDigest, merkle::MerklePath},
transaction::AccountDetails,
utils::Serializable,
Digest,
};

use crate::{
errors::{ConversionError, MissingFieldHelper},
generated::{
account::AccountId as AccountIdPb,
account::{
AccountHashUpdate as AccountHashUpdatePb, AccountId as AccountIdPb,
AccountInfo as AccountInfoPb,
},
requests::AccountUpdate,
responses::{AccountBlockInputRecord, AccountTransactionInputRecord},
},
Expand Down Expand Up @@ -72,6 +79,38 @@ impl TryFrom<AccountIdPb> for AccountId {
// ACCOUNT UPDATE
// ================================================================================================

#[derive(Debug, PartialEq)]
pub struct AccountHashUpdate {
pub account_id: AccountId,
pub account_hash: RpoDigest,
pub block_num: u32,
}

impl From<&AccountHashUpdate> for AccountHashUpdatePb {
fn from(update: &AccountHashUpdate) -> Self {
Self {
account_id: Some(update.account_id.into()),
account_hash: Some(update.account_hash.into()),
block_num: update.block_num,
}
}
}

#[derive(Debug, PartialEq)]
pub struct AccountInfo {
pub update: AccountHashUpdate,
pub details: Option<Account>,
}

impl From<&AccountInfo> for AccountInfoPb {
fn from(AccountInfo { update, details }: &AccountInfo) -> Self {
Self {
update: Some(update.into()),
details: details.as_ref().map(|account| account.to_bytes()),
}
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UpdatedAccount {
pub account_id: AccountId,
Expand Down
13 changes: 11 additions & 2 deletions proto/src/generated/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ pub struct AccountId {
#[derive(Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AccountInfo {
pub struct AccountHashUpdate {
#[prost(message, optional, tag = "1")]
pub account_id: ::core::option::Option<AccountId>,
#[prost(message, optional, tag = "2")]
pub account_hash: ::core::option::Option<super::digest::Digest>,
#[prost(fixed32, tag = "3")]
#[prost(uint32, tag = "3")]
pub block_num: u32,
}
#[derive(Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AccountInfo {
#[prost(message, optional, tag = "1")]
pub update: ::core::option::Option<AccountHashUpdate>,
#[prost(bytes = "vec", optional, tag = "2")]
pub details: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
}
9 changes: 9 additions & 0 deletions proto/src/generated/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,12 @@ pub struct ListAccountsRequest {}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListNotesRequest {}
/// Returns the latest state of an account with the specified ID.
#[derive(Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountDetailsRequest {
/// Account ID to get details.
#[prost(message, optional, tag = "1")]
pub account_id: ::core::option::Option<super::account::AccountId>,
}
23 changes: 10 additions & 13 deletions proto/src/generated/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,6 @@ pub struct GetBlockHeaderByNumberResponse {
#[derive(Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AccountHashUpdate {
#[prost(message, optional, tag = "1")]
pub account_id: ::core::option::Option<super::account::AccountId>,
#[prost(message, optional, tag = "2")]
pub account_hash: ::core::option::Option<super::digest::Digest>,
#[prost(uint32, tag = "3")]
pub block_num: u32,
}
#[derive(Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct NullifierUpdate {
#[prost(message, optional, tag = "1")]
pub nullifier: ::core::option::Option<super::digest::Digest>,
Expand All @@ -52,7 +41,7 @@ pub struct SyncStateResponse {
pub mmr_delta: ::core::option::Option<super::mmr::MmrDelta>,
/// a list of account hashes updated after `block_num + 1` but not after `block_header.block_num`
#[prost(message, repeated, tag = "5")]
pub accounts: ::prost::alloc::vec::Vec<AccountHashUpdate>,
pub accounts: ::prost::alloc::vec::Vec<super::account::AccountHashUpdate>,
/// a list of all notes together with the Merkle paths from `block_header.note_root`
#[prost(message, repeated, tag = "6")]
pub notes: ::prost::alloc::vec::Vec<super::note::NoteSyncRecord>,
Expand Down Expand Up @@ -92,7 +81,7 @@ pub struct GetBlockInputsResponse {
/// Peaks of the above block's mmr, The `forest` value is equal to the block number.
#[prost(message, repeated, tag = "2")]
pub mmr_peaks: ::prost::alloc::vec::Vec<super::digest::Digest>,
/// The hashes of the requested accouts and their authentication paths
/// The hashes of the requested accounts and their authentication paths
#[prost(message, repeated, tag = "3")]
pub account_states: ::prost::alloc::vec::Vec<AccountBlockInputRecord>,
/// The requested nullifiers and their authentication paths
Expand Down Expand Up @@ -158,3 +147,11 @@ pub struct ListNotesResponse {
#[prost(message, repeated, tag = "1")]
pub notes: ::prost::alloc::vec::Vec<super::note::Note>,
}
#[derive(Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetAccountDetailsResponse {
/// Account info (with details for on-chain accounts)
#[prost(message, optional, tag = "1")]
pub account: ::core::option::Option<super::account::AccountInfo>,
}
82 changes: 82 additions & 0 deletions proto/src/generated/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,32 @@ pub mod api_client {
.insert(GrpcMethod::new("rpc.Api", "SubmitProvenTransaction"));
self.inner.unary(req, path, codec).await
}
pub async fn get_account_details(
&mut self,
request: impl tonic::IntoRequest<
super::super::requests::GetAccountDetailsRequest,
>,
) -> std::result::Result<
tonic::Response<super::super::responses::GetAccountDetailsResponse>,
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/GetAccountDetails",
);
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new("rpc.Api", "GetAccountDetails"));
self.inner.unary(req, path, codec).await
}
}
}
/// Generated server implementations.
Expand Down Expand Up @@ -224,6 +250,13 @@ pub mod api_server {
tonic::Response<super::super::responses::SubmitProvenTransactionResponse>,
tonic::Status,
>;
async fn get_account_details(
&self,
request: tonic::Request<super::super::requests::GetAccountDetailsRequest>,
) -> std::result::Result<
tonic::Response<super::super::responses::GetAccountDetailsResponse>,
tonic::Status,
>;
}
#[derive(Debug)]
pub struct ApiServer<T: Api> {
Expand Down Expand Up @@ -501,6 +534,55 @@ pub mod api_server {
};
Box::pin(fut)
}
"/rpc.Api/GetAccountDetails" => {
#[allow(non_camel_case_types)]
struct GetAccountDetailsSvc<T: Api>(pub Arc<T>);
impl<
T: Api,
> tonic::server::UnaryService<
super::super::requests::GetAccountDetailsRequest,
> for GetAccountDetailsSvc<T> {
type Response = super::super::responses::GetAccountDetailsResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<
super::super::requests::GetAccountDetailsRequest,
>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as Api>::get_account_details(&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 inner = inner.0;
let method = GetAccountDetailsSvc(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)
}
_ => {
Box::pin(async move {
Ok(
Expand Down
Loading

0 comments on commit 2f113f9

Please sign in to comment.