From b6c529f737f5e6765a86b0f1e3418839b5cacd40 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 8 Mar 2024 18:21:58 +0500 Subject: [PATCH 01/23] feat: add `account_details` table to the DB --- store/src/db/migrations.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/store/src/db/migrations.rs b/store/src/db/migrations.rs index 3eec2bc0b..3d34cfbe7 100644 --- a/store/src/db/migrations.rs +++ b/store/src/db/migrations.rs @@ -42,6 +42,20 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { CONSTRAINT accounts_block_num_is_u32 CHECK (block_num >= 0 AND block_num < 4294967296) ) STRICT, WITHOUT ROWID; + CREATE TABLE + account_details + ( + account_id INTEGER NOT NULL, + nonce INTEGER NOT NULL, + vault BLOB NOT NULL, + storage BLOB NOT NULL, + code BLOB NOT NULL, + + PRIMARY KEY (account_id), + CONSTRAINT account_details_nonce_non_negative CHECK (nonce >= 0), + FOREIGN KEY (account_id) REFERENCES accounts (account_id) + ) STRICT, WITHOUT ROWID; + CREATE TABLE nullifiers ( From ed04d5a79173bb9794e817e46400d6d254250cfc Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 8 Mar 2024 18:23:10 +0500 Subject: [PATCH 02/23] refactor: rename `block_number` column in nullifiers table to `block_num` --- store/src/db/migrations.rs | 7 ++++--- store/src/db/sql.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/store/src/db/migrations.rs b/store/src/db/migrations.rs index 3d34cfbe7..c4e13da8e 100644 --- a/store/src/db/migrations.rs +++ b/store/src/db/migrations.rs @@ -39,7 +39,7 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { PRIMARY KEY (account_id), CONSTRAINT fk_block_num FOREIGN KEY (block_num) REFERENCES block_headers (block_num), - CONSTRAINT accounts_block_num_is_u32 CHECK (block_num >= 0 AND block_num < 4294967296) + CONSTRAINT accounts_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF) ) STRICT, WITHOUT ROWID; CREATE TABLE @@ -61,13 +61,14 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { ( nullifier BLOB NOT NULL, nullifier_prefix INTEGER NOT NULL, - block_number INTEGER NOT NULL, + block_num INTEGER NOT NULL, PRIMARY KEY (nullifier), CONSTRAINT fk_block_num FOREIGN KEY (block_number) REFERENCES block_headers (block_num), CONSTRAINT nullifiers_nullifier_is_digest CHECK (length(nullifier) = 32), CONSTRAINT nullifiers_nullifier_prefix_is_u16 CHECK (nullifier_prefix >= 0 AND nullifier_prefix < 65536), - CONSTRAINT nullifiers_block_number_is_u32 CHECK (block_number >= 0 AND block_number < 4294967296) + CONSTRAINT nullifiers_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), + FOREIGN KEY (block_num) REFERENCES block_header (block_num) ) STRICT, WITHOUT ROWID; ", )]) diff --git a/store/src/db/sql.rs b/store/src/db/sql.rs index 55d2ddf65..3d5e816e6 100644 --- a/store/src/db/sql.rs +++ b/store/src/db/sql.rs @@ -157,7 +157,7 @@ pub fn insert_nullifiers_for_block( block_num: BlockNumber, ) -> Result { let mut stmt = transaction.prepare( - "INSERT INTO nullifiers (nullifier, nullifier_prefix, block_number) VALUES (?1, ?2, ?3);", + "INSERT INTO nullifiers (nullifier, nullifier_prefix, block_num) VALUES (?1, ?2, ?3);", )?; let mut count = 0; @@ -175,7 +175,7 @@ pub fn insert_nullifiers_for_block( /// A vector with nullifiers and the block height at which they were created, or an error. pub fn select_nullifiers(conn: &mut Connection) -> Result> { let mut stmt = - conn.prepare("SELECT nullifier, block_number FROM nullifiers ORDER BY block_number ASC;")?; + conn.prepare("SELECT nullifier, block_num FROM nullifiers ORDER BY block_num ASC;")?; let mut rows = stmt.query([])?; let mut result = vec![]; @@ -211,15 +211,15 @@ pub fn select_nullifiers_by_block_range( " SELECT nullifier, - block_number + block_num FROM nullifiers WHERE - block_number > ?1 AND - block_number <= ?2 AND + block_num > ?1 AND + block_num <= ?2 AND nullifier_prefix IN rarray(?3) ORDER BY - block_number ASC + block_num ASC ", )?; From 4cc4ba8a3cdee5b6ce8468042a258ebe05408f00 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 8 Mar 2024 18:24:34 +0500 Subject: [PATCH 03/23] refactor: use `BETWEEN` in interval comparison checks --- store/src/db/migrations.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/store/src/db/migrations.rs b/store/src/db/migrations.rs index c4e13da8e..22201b62c 100644 --- a/store/src/db/migrations.rs +++ b/store/src/db/migrations.rs @@ -11,7 +11,7 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { block_header BLOB NOT NULL, PRIMARY KEY (block_num), - CONSTRAINT block_header_block_num_is_u32 CHECK (block_num >= 0 AND block_num < 4294967296) + CONSTRAINT block_header_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF) ) STRICT, WITHOUT ROWID; CREATE TABLE @@ -26,8 +26,8 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { PRIMARY KEY (block_num, note_index), CONSTRAINT fk_block_num FOREIGN KEY (block_num) REFERENCES block_headers (block_num), - CONSTRAINT notes_block_number_is_u32 CHECK (block_num >= 0 AND block_num < 4294967296), - CONSTRAINT notes_note_index_is_u32 CHECK (note_index >= 0 AND note_index < 4294967296) + CONSTRAINT notes_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), + CONSTRAINT notes_note_index_is_u32 CHECK (note_index BETWEEN 0 AND 0xFFFFFFFF), ) STRICT, WITHOUT ROWID; CREATE TABLE @@ -66,7 +66,8 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { PRIMARY KEY (nullifier), CONSTRAINT fk_block_num FOREIGN KEY (block_number) REFERENCES block_headers (block_num), CONSTRAINT nullifiers_nullifier_is_digest CHECK (length(nullifier) = 32), - CONSTRAINT nullifiers_nullifier_prefix_is_u16 CHECK (nullifier_prefix >= 0 AND nullifier_prefix < 65536), + CONSTRAINT nullifiers_nullifier_prefix_is_u16 CHECK (nullifier_prefix BETWEEN 0 AND 0xFFFF), + CONSTRAINT nullifiers_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), CONSTRAINT nullifiers_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), FOREIGN KEY (block_num) REFERENCES block_header (block_num) ) STRICT, WITHOUT ROWID; From 8f0935a415ef9ca7e6ac7a35ebd3f3f332d29b1b Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Sun, 10 Mar 2024 20:27:55 +0500 Subject: [PATCH 04/23] feat: implement account details protobuf messages, domain objects and conversions --- block-producer/src/errors.rs | 6 +- block-producer/src/store/mod.rs | 4 +- proto/proto/account.proto | 83 ++++++++ proto/proto/requests.proto | 2 + proto/src/domain/accounts.rs | 361 ++++++++++++++++++++++++++++++-- proto/src/domain/blocks.rs | 6 +- proto/src/domain/digest.rs | 18 +- proto/src/domain/merkle.rs | 14 +- proto/src/domain/nullifiers.rs | 6 +- proto/src/errors.rs | 28 ++- proto/src/generated/account.rs | 147 +++++++++++++ proto/src/generated/requests.rs | 3 + 12 files changed, 626 insertions(+), 52 deletions(-) diff --git a/block-producer/src/errors.rs b/block-producer/src/errors.rs index a597714a1..ae77ce9db 100644 --- a/block-producer/src/errors.rs +++ b/block-producer/src/errors.rs @@ -1,4 +1,4 @@ -use miden_node_proto::errors::ParseError; +use miden_node_proto::errors::ConversionError; use miden_node_utils::formatting::format_opt; use miden_objects::{ accounts::AccountId, @@ -101,7 +101,7 @@ pub enum BlockProverError { #[derive(Debug, PartialEq, Error)] pub enum BlockInputsError { #[error("failed to parse protobuf message: {0}")] - ParseError(#[from] ParseError), + ConversionError(#[from] ConversionError), #[error("MmrPeaks error: {0}")] MmrPeaksError(#[from] MmrError), #[error("gRPC client failed with error: {0}")] @@ -153,7 +153,7 @@ pub enum TxInputsError { #[error("malformed response from store: {0}")] MalformedResponse(String), #[error("failed to parse protobuf message: {0}")] - ParseError(#[from] ParseError), + ConversionError(#[from] ConversionError), #[error("dummy")] Dummy, } diff --git a/block-producer/src/store/mod.rs b/block-producer/src/store/mod.rs index 542c47d31..bd0fd81e3 100644 --- a/block-producer/src/store/mod.rs +++ b/block-producer/src/store/mod.rs @@ -6,7 +6,7 @@ use std::{ use async_trait::async_trait; use miden_node_proto::{ convert, - errors::{MissingFieldHelper, ParseError}, + errors::{ConversionError, MissingFieldHelper}, generated::{ account, digest, requests::{ApplyBlockRequest, GetBlockInputsRequest, GetTransactionInputsRequest}, @@ -83,7 +83,7 @@ impl Display for TransactionInputs { } impl TryFrom for TransactionInputs { - type Error = ParseError; + type Error = ConversionError; fn try_from(response: GetTransactionInputsResponse) -> Result { let AccountState { diff --git a/proto/proto/account.proto b/proto/proto/account.proto index 25d63bf73..6819ccfa0 100644 --- a/proto/proto/account.proto +++ b/proto/proto/account.proto @@ -15,3 +15,86 @@ message AccountInfo { digest.Digest account_hash = 2; fixed32 block_num = 3; } + +message FungibleAsset { + // Faucet ID. + AccountId faucet_id = 1; + // Amount of asset. + uint64 amount = 2; +} + +message NonFungibleAsset { + // Non-fungible asset in internal (`Word`) representation. + digest.Digest asset = 1; +} + +message Asset { + // Asset enumeration. + oneof asset { + FungibleAsset fungible = 1; + NonFungibleAsset non_fungible = 2; + } +} + +message AssetVault { + // Assets vector. + repeated Asset assets = 1; +} + +message AccountStorage { + // Full account storage serialized using Miden serialization procedure. + bytes data = 1; +} + +message AccountCode { + // Module AST tree serialized using Miden serialization procedure. + bytes module = 1; + // Procedures vector. + repeated digest.Digest procedures = 2; +} + +message AccountFullDetails { + // Account ID. + AccountId id = 1; + // All account's assets. + AssetVault vault = 2; + // Account storage. + AccountStorage storage = 3; + // Account code. + AccountCode code = 4; + // Account nonce. + uint64 nonce = 5; +} + +message AccountStorageDelta { + // Items to be cleared in the account's storage. + bytes cleared_items = 1; + // Vector of slots to be updated in the account's storage in the same order, as items. + bytes updated_storage_slots = 2; + // Vector of items to be updated in the account's storage in the same order, as slots. + repeated digest.Digest updated_items = 3; +} + +message AccountVaultDelta { + // Assets to be added into the account's vault. + repeated Asset added_assets = 1; + // Assets to be removed from the account's vault. + repeated Asset removed_assets = 2; +} + +message AccountDelta { + // Account's storage delta. + AccountStorageDelta storage = 1; + // Account's assets vault delta. + AccountVaultDelta vault = 2; + // Account's new nonce. + optional uint64 nonce = 3; +} + +message AccountDetails { + // Details enumeration for public accounts. + oneof details { + account.AccountFullDetails full = 1; + account.AccountDelta delta = 2; + } +} diff --git a/proto/proto/requests.proto b/proto/proto/requests.proto index d872b3d58..d5186764f 100644 --- a/proto/proto/requests.proto +++ b/proto/proto/requests.proto @@ -10,6 +10,8 @@ import "note.proto"; message AccountUpdate { account.AccountId account_id = 1; digest.Digest account_hash = 2; + // Details for public account. + account.AccountDetails details = 3; } message ApplyBlockRequest { diff --git a/proto/src/domain/accounts.rs b/proto/src/domain/accounts.rs index 2cc367018..fe6cd1587 100644 --- a/proto/src/domain/accounts.rs +++ b/proto/src/domain/accounts.rs @@ -1,21 +1,43 @@ use std::fmt::{Debug, Display, Formatter}; use miden_node_utils::formatting::format_opt; -use miden_objects::{accounts::AccountId, crypto::merkle::MerklePath, Digest}; +use miden_objects::{ + accounts::{ + Account, AccountCode, AccountDelta, AccountId, AccountStorage, AccountStorageDelta, + AccountVaultDelta, + }, + assembly::{AstSerdeOptions, ModuleAst}, + assets::{Asset, AssetVault, FungibleAsset, NonFungibleAsset}, + crypto::{hash::rpo::RpoDigest, merkle::MerklePath}, + transaction::AccountDetails, + utils::{Deserializable, Serializable}, + Digest, Felt, Word, +}; use crate::{ - errors::{MissingFieldHelper, ParseError}, + convert, + errors::{ConversionError, MissingFieldHelper}, generated::{ - self, + account::{ + account_details::{Details as DetailsPb, Details}, + asset::Asset as AssetEnumPb, + AccountCode as AccountCodePb, AccountDelta as AccountDeltaPb, + AccountDetails as AccountDetailsPb, AccountFullDetails as AccountFullDetailsPb, + AccountId as AccountIdPb, AccountStorage as AccountStoragePb, + AccountStorageDelta as AccountStorageDeltaPb, AccountVaultDelta as AccountVaultDeltaPb, + Asset as AssetPb, AssetVault as AssetVaultPb, FungibleAsset as FungibleAssetPb, + NonFungibleAsset as NonFungibleAssetPb, + }, requests::AccountUpdate, responses::{AccountBlockInputRecord, AccountTransactionInputRecord}, }, + try_convert, }; // ACCOUNT ID // ================================================================================================ -impl Display for generated::account::AccountId { +impl Display for AccountIdPb { fn fmt( &self, f: &mut Formatter<'_>, @@ -24,7 +46,7 @@ impl Display for generated::account::AccountId { } } -impl Debug for generated::account::AccountId { +impl Debug for AccountIdPb { fn fmt( &self, f: &mut Formatter<'_>, @@ -36,13 +58,13 @@ impl Debug for generated::account::AccountId { // INTO PROTO ACCOUNT ID // ------------------------------------------------------------------------------------------------ -impl From for generated::account::AccountId { +impl From for AccountIdPb { fn from(value: u64) -> Self { - generated::account::AccountId { id: value } + AccountIdPb { id: value } } } -impl From for generated::account::AccountId { +impl From for AccountIdPb { fn from(account_id: AccountId) -> Self { Self { id: account_id.into(), @@ -53,28 +75,327 @@ impl From for generated::account::AccountId { // FROM PROTO ACCOUNT ID // ------------------------------------------------------------------------------------------------ -impl From for u64 { - fn from(value: generated::account::AccountId) -> Self { +impl From for u64 { + fn from(value: AccountIdPb) -> Self { value.id } } -impl TryFrom for AccountId { - type Error = ParseError; +impl TryFrom for AccountId { + type Error = ConversionError; + + fn try_from(account_id: AccountIdPb) -> Result { + account_id.id.try_into().map_err(|_| ConversionError::NotAValidFelt) + } +} + +// INTO ACCOUNT DETAILS +// ================================================================================================ + +impl From<&FungibleAsset> for FungibleAssetPb { + fn from(fungible: &FungibleAsset) -> Self { + Self { + faucet_id: Some(fungible.faucet_id().into()), + amount: fungible.amount(), + } + } +} + +impl From<&NonFungibleAsset> for NonFungibleAssetPb { + fn from(non_fungible: &NonFungibleAsset) -> Self { + Self { + asset: Some(non_fungible.vault_key().into()), + } + } +} + +impl From<&Asset> for AssetPb { + fn from(asset: &Asset) -> Self { + let asset = Some(match asset { + Asset::Fungible(fungible) => AssetEnumPb::Fungible(fungible.into()), + Asset::NonFungible(non_fungible) => AssetEnumPb::NonFungible(non_fungible.into()), + }); + + Self { asset } + } +} + +impl From for AssetPb { + fn from(asset: Asset) -> Self { + asset.into() + } +} + +impl From<&AssetVault> for AssetVaultPb { + fn from(vault: &AssetVault) -> Self { + Self { + assets: convert(vault.assets()), + } + } +} + +impl From<&AccountStorage> for AccountStoragePb { + fn from(storage: &AccountStorage) -> Self { + Self { + data: storage.to_bytes(), + } + } +} + +impl From<&AccountCode> for AccountCodePb { + fn from(code: &AccountCode) -> Self { + Self { + module: code.module().to_bytes(AstSerdeOptions::new(true)), + procedures: convert(code.procedures()), + } + } +} + +impl From<&Account> for AccountFullDetailsPb { + fn from(account: &Account) -> Self { + Self { + id: Some(account.id().into()), + vault: Some(account.vault().into()), + storage: Some(account.storage().into()), + code: Some(account.code().into()), + nonce: account.nonce().as_int(), + } + } +} + +impl From<&AccountStorageDelta> for AccountStorageDeltaPb { + fn from(delta: &AccountStorageDelta) -> Self { + Self { + cleared_items: delta.cleared_items.clone(), + updated_storage_slots: delta.updated_items.iter().map(|(slot, _)| *slot).collect(), + updated_items: delta + .updated_items + .iter() + .map(|(_, value)| Into::::into(value)) + .map(Into::into) + .collect(), + } + } +} + +impl From<&AccountVaultDelta> for AccountVaultDeltaPb { + fn from(delta: &AccountVaultDelta) -> Self { + Self { + added_assets: convert(delta.added_assets.iter()), + removed_assets: convert(delta.removed_assets.iter()), + } + } +} + +impl From<&AccountDelta> for AccountDeltaPb { + fn from(delta: &AccountDelta) -> Self { + Self { + storage: Some(delta.storage().into()), + vault: Some(delta.vault().into()), + nonce: delta.nonce().as_ref().map(Felt::as_int), + } + } +} + +impl From<&AccountDetails> for AccountDetailsPb { + fn from(details: &AccountDetails) -> Self { + let details = Some(match details { + AccountDetails::Full(full) => DetailsPb::Full(full.into()), + AccountDetails::Delta(delta) => DetailsPb::Delta(delta.into()), + }); + + Self { details } + } +} + +// FROM ACCOUNT DETAILS +// ================================================================================================ + +impl TryFrom<&FungibleAssetPb> for FungibleAsset { + type Error = ConversionError; + + fn try_from(fungible: &FungibleAssetPb) -> Result { + let faucet_id = fungible + .faucet_id + .clone() + .ok_or(FungibleAssetPb::missing_field(stringify!(faucet_id)))? + .try_into()?; + + Ok(Self::new(faucet_id, fungible.amount)?) + } +} + +impl TryFrom<&NonFungibleAssetPb> for NonFungibleAsset { + type Error = ConversionError; + + fn try_from(non_fungible: &NonFungibleAssetPb) -> Result { + let asset: Word = non_fungible + .asset + .clone() + .ok_or(NonFungibleAssetPb::missing_field(stringify!(asset)))? + .try_into()?; + + Ok(Self::try_from(asset)?) + } +} + +impl TryFrom<&AssetPb> for Asset { + type Error = ConversionError; + + fn try_from(asset: &AssetPb) -> Result { + let from = asset.asset.as_ref().ok_or(AssetPb::missing_field(stringify!(asset)))?; + Ok(match from { + AssetEnumPb::Fungible(fungible) => Asset::Fungible(fungible.try_into()?), + AssetEnumPb::NonFungible(non_fungible) => Asset::NonFungible(non_fungible.try_into()?), + }) + } +} + +impl TryFrom<&AssetVaultPb> for AssetVault { + type Error = ConversionError; + + fn try_from(vault: &AssetVaultPb) -> Result { + let assets = try_convert(vault.assets.iter())?; + + Ok(Self::new(&assets)?) + } +} + +impl TryFrom<&AccountStoragePb> for AccountStorage { + type Error = ConversionError; + + fn try_from(storage: &AccountStoragePb) -> Result { + Ok(Self::read_from_bytes(&storage.data)?) + } +} + +impl TryFrom<&AccountCodePb> for AccountCode { + type Error = ConversionError; + + fn try_from(code: &AccountCodePb) -> Result { + let module = ModuleAst::from_bytes(&code.module)?; + let procedures = try_convert(&code.procedures)?; + + Ok(Self::from_parts(module, procedures)) + } +} + +impl TryFrom<&AccountFullDetailsPb> for Account { + type Error = ConversionError; + + fn try_from(account: &AccountFullDetailsPb) -> Result { + Ok(Self::new( + account + .id + .clone() + .ok_or(AccountFullDetailsPb::missing_field(stringify!(id)))? + .try_into()?, + account + .vault + .as_ref() + .ok_or(AccountFullDetailsPb::missing_field(stringify!(vault)))? + .try_into()?, + account + .storage + .as_ref() + .ok_or(AccountFullDetailsPb::missing_field(stringify!(storage)))? + .try_into()?, + account + .code + .as_ref() + .ok_or(AccountFullDetailsPb::missing_field(stringify!(code)))? + .try_into()?, + Felt::new(account.nonce), + )) + } +} + +impl TryFrom<&AccountStorageDeltaPb> for AccountStorageDelta { + type Error = ConversionError; + + fn try_from(from: &AccountStorageDeltaPb) -> Result { + let updated_items: Result<_, ConversionError> = from + .updated_storage_slots + .iter() + .zip(from.updated_items.iter()) + .map(|(slot, value)| Ok((*slot, value.try_into()?))) + .collect(); + let storage_delta = Self { + cleared_items: from.cleared_items.clone(), + updated_items: updated_items?, + }; + + storage_delta.validate()?; + + Ok(storage_delta) + } +} + +impl TryFrom<&AccountVaultDeltaPb> for AccountVaultDelta { + type Error = ConversionError; + + fn try_from(delta: &AccountVaultDeltaPb) -> Result { + Ok(Self { + added_assets: try_convert(delta.added_assets.iter())?, + removed_assets: try_convert(delta.removed_assets.iter())?, + }) + } +} + +impl TryFrom<&AccountDeltaPb> for AccountDelta { + type Error = ConversionError; + + fn try_from(delta: &AccountDeltaPb) -> Result { + Ok(Self::new( + delta + .storage + .as_ref() + .ok_or(AccountDeltaPb::missing_field(stringify!(storage)))? + .try_into()?, + delta + .vault + .as_ref() + .ok_or(AccountDeltaPb::missing_field(stringify!(vault)))? + .try_into()?, + delta.nonce.map(Felt::new), + )?) + } +} + +impl TryFrom<&DetailsPb> for AccountDetails { + type Error = ConversionError; + + fn try_from(details: &DetailsPb) -> Result { + Ok(match details { + Details::Full(full) => AccountDetails::Full(full.try_into()?), + Details::Delta(delta) => AccountDetails::Delta(delta.try_into()?), + }) + } +} + +impl TryFrom<&AccountDetailsPb> for AccountDetails { + type Error = ConversionError; - fn try_from(account_id: generated::account::AccountId) -> Result { - account_id.id.try_into().map_err(|_| ParseError::NotAValidFelt) + fn try_from(details: &AccountDetailsPb) -> Result { + details + .details + .as_ref() + .ok_or(AccountDetailsPb::missing_field(stringify!(details)))? + .try_into() } } // INTO ACCOUNT UPDATE // ================================================================================================ -impl From<(AccountId, Digest)> for AccountUpdate { - fn from((account_id, account_hash): (AccountId, Digest)) -> Self { +impl From<(AccountId, Option, Digest)> for AccountUpdate { + fn from( + (account_id, details, account_hash): (AccountId, Option, Digest) + ) -> Self { Self { account_id: Some(account_id.into()), account_hash: Some(account_hash.into()), + details: details.as_ref().map(Into::into), } } } @@ -100,7 +421,7 @@ impl From for AccountBlockInputRecord { } impl TryFrom for AccountInputRecord { - type Error = ParseError; + type Error = ConversionError; fn try_from(account_input_record: AccountBlockInputRecord) -> Result { Ok(Self { @@ -155,7 +476,7 @@ impl From for AccountTransactionInputRecord { } impl TryFrom for AccountState { - type Error = ParseError; + type Error = ConversionError; fn try_from(from: AccountTransactionInputRecord) -> Result { let account_id = from @@ -185,7 +506,7 @@ impl TryFrom for AccountState { } impl TryFrom for AccountState { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: AccountUpdate) -> Result { Ok(Self { @@ -199,7 +520,7 @@ impl TryFrom for AccountState { } impl TryFrom<&AccountUpdate> for AccountState { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: &AccountUpdate) -> Result { value.clone().try_into() diff --git a/proto/src/domain/blocks.rs b/proto/src/domain/blocks.rs index 3916308d1..c33ace75f 100644 --- a/proto/src/domain/blocks.rs +++ b/proto/src/domain/blocks.rs @@ -1,7 +1,7 @@ use miden_objects::BlockHeader; use crate::{ - errors::{MissingFieldHelper, ParseError}, + errors::{ConversionError, MissingFieldHelper}, generated::block_header, }; @@ -28,7 +28,7 @@ impl From for block_header::BlockHeader { } impl TryFrom<&block_header::BlockHeader> for BlockHeader { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: &block_header::BlockHeader) -> Result { value.clone().try_into() @@ -36,7 +36,7 @@ impl TryFrom<&block_header::BlockHeader> for BlockHeader { } impl TryFrom for BlockHeader { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: block_header::BlockHeader) -> Result { Ok(BlockHeader::new( diff --git a/proto/src/domain/digest.rs b/proto/src/domain/digest.rs index 8b2d14a66..e9bfb00a8 100644 --- a/proto/src/domain/digest.rs +++ b/proto/src/domain/digest.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Display, Formatter}; use hex::{FromHex, ToHex}; use miden_objects::{notes::NoteId, Digest, Felt, StarkField}; -use crate::{errors::ParseError, generated::digest}; +use crate::{errors::ConversionError, generated::digest}; // CONSTANTS // ================================================================================================ @@ -62,17 +62,17 @@ impl ToHex for digest::Digest { } impl FromHex for digest::Digest { - type Error = ParseError; + type Error = ConversionError; fn from_hex>(hex: T) -> Result { let data = hex::decode(hex)?; match data.len() { - size if size < DIGEST_DATA_SIZE => Err(ParseError::InsufficientData { + size if size < DIGEST_DATA_SIZE => Err(ConversionError::InsufficientData { expected: DIGEST_DATA_SIZE, got: size, }), - size if size > DIGEST_DATA_SIZE => Err(ParseError::TooMuchData { + size if size > DIGEST_DATA_SIZE => Err(ConversionError::TooMuchData { expected: DIGEST_DATA_SIZE, got: size, }), @@ -164,14 +164,14 @@ impl From for [u64; 4] { } impl TryFrom for [Felt; 4] { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: digest::Digest) -> Result { if ![value.d0, value.d1, value.d2, value.d3] .iter() .all(|v| *v < ::MODULUS) { - Err(ParseError::NotAValidFelt) + Err(ConversionError::NotAValidFelt) } else { Ok([ Felt::new(value.d0), @@ -184,7 +184,7 @@ impl TryFrom for [Felt; 4] { } impl TryFrom for Digest { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: digest::Digest) -> Result { Ok(Self::new(value.try_into()?)) @@ -192,7 +192,7 @@ impl TryFrom for Digest { } impl TryFrom<&digest::Digest> for [Felt; 4] { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: &digest::Digest) -> Result { value.clone().try_into() @@ -200,7 +200,7 @@ impl TryFrom<&digest::Digest> for [Felt; 4] { } impl TryFrom<&digest::Digest> for Digest { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: &digest::Digest) -> Result { value.clone().try_into() diff --git a/proto/src/domain/merkle.rs b/proto/src/domain/merkle.rs index a038ef033..04d890247 100644 --- a/proto/src/domain/merkle.rs +++ b/proto/src/domain/merkle.rs @@ -5,7 +5,7 @@ use miden_objects::{ use super::{convert, try_convert}; use crate::{ - errors::{MissingFieldHelper, ParseError}, + errors::{ConversionError, MissingFieldHelper}, generated, }; @@ -20,7 +20,7 @@ impl From for generated::merkle::MerklePath { } impl TryFrom for MerklePath { - type Error = ParseError; + type Error = ConversionError; fn try_from(merkle_path: generated::merkle::MerklePath) -> Result { merkle_path.siblings.into_iter().map(Digest::try_from).collect() @@ -41,10 +41,10 @@ impl From for generated::mmr::MmrDelta { } impl TryFrom for MmrDelta { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: generated::mmr::MmrDelta) -> Result { - let data: Result, ParseError> = + let data: Result, ConversionError> = value.data.into_iter().map(Digest::try_from).collect(); Ok(MmrDelta { @@ -61,7 +61,7 @@ impl TryFrom for MmrDelta { // ------------------------------------------------------------------------------------------------ impl TryFrom for SmtLeaf { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: generated::smt::SmtLeaf) -> Result { let leaf = value.leaf.ok_or(generated::smt::SmtLeaf::missing_field(stringify!(leaf)))?; @@ -104,7 +104,7 @@ impl From for generated::smt::SmtLeaf { // ------------------------------------------------------------------------------------------------ impl TryFrom for (Digest, Word) { - type Error = ParseError; + type Error = ConversionError; fn try_from(entry: generated::smt::SmtLeafEntry) -> Result { let key: Digest = entry @@ -133,7 +133,7 @@ impl From<(Digest, Word)> for generated::smt::SmtLeafEntry { // ------------------------------------------------------------------------------------------------ impl TryFrom for SmtProof { - type Error = ParseError; + type Error = ConversionError; fn try_from(opening: generated::smt::SmtOpening) -> Result { let path: MerklePath = opening diff --git a/proto/src/domain/nullifiers.rs b/proto/src/domain/nullifiers.rs index ef0179b6e..0b3cc0d0c 100644 --- a/proto/src/domain/nullifiers.rs +++ b/proto/src/domain/nullifiers.rs @@ -4,7 +4,7 @@ use miden_objects::{ }; use crate::{ - errors::{MissingFieldHelper, ParseError}, + errors::{ConversionError, MissingFieldHelper}, generated::{digest::Digest, responses::NullifierBlockInputRecord}, }; @@ -27,7 +27,7 @@ impl From for Digest { // ================================================================================================ impl TryFrom for Nullifier { - type Error = ParseError; + type Error = ConversionError; fn try_from(value: Digest) -> Result { let digest: RpoDigest = value.try_into()?; @@ -45,7 +45,7 @@ pub struct NullifierWitness { } impl TryFrom for NullifierWitness { - type Error = ParseError; + type Error = ConversionError; fn try_from(nullifier_input_record: NullifierBlockInputRecord) -> Result { Ok(Self { diff --git a/proto/src/errors.rs b/proto/src/errors.rs index 5b432c661..28cdb438a 100644 --- a/proto/src/errors.rs +++ b/proto/src/errors.rs @@ -1,16 +1,28 @@ use std::any::type_name; -use miden_objects::crypto::merkle::{SmtLeafError, SmtProofError}; +use miden_objects::{ + crypto::merkle::{SmtLeafError, SmtProofError}, + utils::DeserializationError, + AccountDeltaError, AssetError, AssetVaultError, +}; use thiserror::Error; #[derive(Error, Debug, Clone, PartialEq)] -pub enum ParseError { +pub enum ConversionError { #[error("Hex error: {0}")] HexError(#[from] hex::FromHexError), #[error("SMT leaf error: {0}")] SmtLeafError(#[from] SmtLeafError), #[error("SMT proof error: {0}")] SmtProofError(#[from] SmtProofError), + #[error("Account delta error: {0}")] + AccountDeltaError(#[from] AccountDeltaError), + #[error("Asset error: {0}")] + AssetError(#[from] AssetError), + #[error("Asset vault error: {0}")] + AssetVaultError(#[from] AssetVaultError), + #[error("Deserialization error: {0}")] + DeserializationError(DeserializationError), #[error("Too much data, expected {expected}, got {got}")] TooMuchData { expected: usize, got: usize }, #[error("Not enough data, expected {expected}, got {got}")] @@ -26,13 +38,19 @@ pub enum ParseError { }, } +impl From for ConversionError { + fn from(value: DeserializationError) -> Self { + Self::DeserializationError(value) + } +} + pub trait MissingFieldHelper { - fn missing_field(field_name: &'static str) -> ParseError; + fn missing_field(field_name: &'static str) -> ConversionError; } impl MissingFieldHelper for T { - fn missing_field(field_name: &'static str) -> ParseError { - ParseError::MissingFieldInProtobufRepresentation { + fn missing_field(field_name: &'static str) -> ConversionError { + ConversionError::MissingFieldInProtobufRepresentation { entity: type_name::(), field_name, } diff --git a/proto/src/generated/account.rs b/proto/src/generated/account.rs index 923c1d896..39a28184a 100644 --- a/proto/src/generated/account.rs +++ b/proto/src/generated/account.rs @@ -20,3 +20,150 @@ pub struct AccountInfo { #[prost(fixed32, 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 FungibleAsset { + /// Faucet ID. + #[prost(message, optional, tag = "1")] + pub faucet_id: ::core::option::Option, + /// Amount of asset. + #[prost(uint64, tag = "2")] + pub amount: u64, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NonFungibleAsset { + /// Non-fungible asset in internal (`Word`) representation. + #[prost(message, optional, tag = "1")] + pub asset: ::core::option::Option, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Asset { + /// Asset enumeration. + #[prost(oneof = "asset::Asset", tags = "1, 2")] + pub asset: ::core::option::Option, +} +/// Nested message and enum types in `Asset`. +pub mod asset { + /// Asset enumeration. + #[derive(Eq, PartialOrd, Ord, Hash)] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Asset { + #[prost(message, tag = "1")] + Fungible(super::FungibleAsset), + #[prost(message, tag = "2")] + NonFungible(super::NonFungibleAsset), + } +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssetVault { + /// Assets vector. + #[prost(message, repeated, tag = "1")] + pub assets: ::prost::alloc::vec::Vec, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountStorage { + /// Full account storage serialized using Miden serialization procedure. + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountCode { + /// Module AST tree serialized using Miden serialization procedure. + #[prost(bytes = "vec", tag = "1")] + pub module: ::prost::alloc::vec::Vec, + /// Procedures vector. + #[prost(message, repeated, tag = "2")] + pub procedures: ::prost::alloc::vec::Vec, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountFullDetails { + /// Account ID. + #[prost(message, optional, tag = "1")] + pub id: ::core::option::Option, + /// All account's assets. + #[prost(message, optional, tag = "2")] + pub vault: ::core::option::Option, + /// Account storage. + #[prost(message, optional, tag = "3")] + pub storage: ::core::option::Option, + /// Account code. + #[prost(message, optional, tag = "4")] + pub code: ::core::option::Option, + /// Account nonce. + #[prost(uint64, tag = "5")] + pub nonce: u64, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountStorageDelta { + /// Items to be cleared in the account's storage. + #[prost(bytes = "vec", tag = "1")] + pub cleared_items: ::prost::alloc::vec::Vec, + /// Vector of slots to be updated in the account's storage in the same order, as items. + #[prost(bytes = "vec", tag = "2")] + pub updated_storage_slots: ::prost::alloc::vec::Vec, + /// Vector of items to be updated in the account's storage in the same order, as slots. + #[prost(message, repeated, tag = "3")] + pub updated_items: ::prost::alloc::vec::Vec, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountVaultDelta { + /// Assets to be added into the account's vault. + #[prost(message, repeated, tag = "1")] + pub added_assets: ::prost::alloc::vec::Vec, + /// Assets to be removed from the account's vault. + #[prost(message, repeated, tag = "2")] + pub removed_assets: ::prost::alloc::vec::Vec, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountDelta { + /// Account's storage delta. + #[prost(message, optional, tag = "1")] + pub storage: ::core::option::Option, + /// Account's assets vault delta. + #[prost(message, optional, tag = "2")] + pub vault: ::core::option::Option, + /// Account's new nonce. + #[prost(uint64, optional, tag = "3")] + pub nonce: ::core::option::Option, +} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountDetails { + /// Details enumeration for public accounts. + #[prost(oneof = "account_details::Details", tags = "1, 2")] + pub details: ::core::option::Option, +} +/// Nested message and enum types in `AccountDetails`. +pub mod account_details { + /// Details enumeration for public accounts. + #[derive(Eq, PartialOrd, Ord, Hash)] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Details { + #[prost(message, tag = "1")] + Full(super::AccountFullDetails), + #[prost(message, tag = "2")] + Delta(super::AccountDelta), + } +} diff --git a/proto/src/generated/requests.rs b/proto/src/generated/requests.rs index 799551253..9168d81b4 100644 --- a/proto/src/generated/requests.rs +++ b/proto/src/generated/requests.rs @@ -6,6 +6,9 @@ pub struct AccountUpdate { pub account_id: ::core::option::Option, #[prost(message, optional, tag = "2")] pub account_hash: ::core::option::Option, + /// Details for public account. + #[prost(message, optional, tag = "3")] + pub details: ::core::option::Option, } #[derive(Eq, PartialOrd, Ord, Hash)] #[allow(clippy::derive_partial_eq_without_eq)] From 9f5c8325585fa29d92e5505f745d5b337db6202d Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Sun, 10 Mar 2024 20:30:20 +0500 Subject: [PATCH 05/23] feat: (WIP) implement account details support --- block-producer/src/batch_builder/batch.rs | 17 +++++++++------ block-producer/src/block.rs | 10 ++++----- block-producer/src/block_builder/mod.rs | 8 ++++--- .../src/block_builder/prover/block_witness.rs | 6 +++--- .../src/block_builder/prover/tests.rs | 2 +- block-producer/src/server/api.rs | 2 ++ block-producer/src/state_view/mod.rs | 15 +++++++------ .../src/state_view/tests/apply_block.rs | 6 +++--- block-producer/src/test_utils/block.rs | 19 +++++++++-------- block-producer/src/test_utils/proven_tx.rs | 11 +++++----- block-producer/src/test_utils/store.rs | 2 +- store/src/server/api.rs | 21 +++++++++++++------ 12 files changed, 69 insertions(+), 50 deletions(-) diff --git a/block-producer/src/batch_builder/batch.rs b/block-producer/src/batch_builder/batch.rs index 2f4752f1d..4976a15ab 100644 --- a/block-producer/src/batch_builder/batch.rs +++ b/block-producer/src/batch_builder/batch.rs @@ -7,6 +7,7 @@ use miden_objects::{ merkle::SimpleSmt, }, notes::{NoteEnvelope, Nullifier}, + transaction::AccountDetails, Digest, BATCH_OUTPUT_NOTES_TREE_DEPTH, MAX_NOTES_PER_BATCH, }; use tracing::instrument; @@ -55,6 +56,7 @@ impl TransactionBatch { AccountStates { initial_state: tx.initial_account_hash(), final_state: tx.final_account_hash(), + details: tx.account_details().cloned(), }, ) }) @@ -108,12 +110,14 @@ impl TransactionBatch { .map(|(account_id, account_states)| (*account_id, account_states.initial_state)) } - /// Returns an iterator over (account_id, new_state_hash) tuples for accounts that were + /// Returns an iterator over (account_id, details, new_state_hash) tuples for accounts that were /// modified in this transaction batch. - pub fn updated_accounts(&self) -> impl Iterator + '_ { - self.updated_accounts - .iter() - .map(|(account_id, account_states)| (*account_id, account_states.final_state)) + pub fn updated_accounts( + &self + ) -> impl Iterator, Digest)> + '_ { + self.updated_accounts.iter().map(|(account_id, account_states)| { + (*account_id, account_states.details.clone(), account_states.final_state) + }) } /// Returns an iterator over produced nullifiers for all consumed notes. @@ -147,8 +151,9 @@ impl TransactionBatch { /// account. /// /// TODO: should this be moved into domain objects? -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq)] struct AccountStates { initial_state: Digest, final_state: Digest, + details: Option, } diff --git a/block-producer/src/block.rs b/block-producer/src/block.rs index e2f818cf7..99b21ce60 100644 --- a/block-producer/src/block.rs +++ b/block-producer/src/block.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use miden_node_proto::{ - errors::{MissingFieldHelper, ParseError}, + errors::{ConversionError, MissingFieldHelper}, generated::responses::GetBlockInputsResponse, AccountInputRecord, NullifierWitness, }; @@ -9,6 +9,7 @@ use miden_objects::{ accounts::AccountId, crypto::merkle::{MerklePath, MmrPeaks, SmtProof}, notes::{NoteEnvelope, Nullifier}, + transaction::AccountDetails, BlockHeader, Digest, }; @@ -17,11 +18,10 @@ use crate::store::BlockInputsError; #[derive(Debug, Clone)] pub struct Block { pub header: BlockHeader, - pub updated_accounts: Vec<(AccountId, Digest)>, + pub updated_accounts: Vec<(AccountId, Option, Digest)>, pub created_notes: BTreeMap, pub produced_nullifiers: Vec, // TODO: - // - full states for updated public accounts // - full states for created public notes // - zk proof } @@ -94,7 +94,7 @@ impl TryFrom for BlockInputs { }; Ok((domain.account_id, witness)) }) - .collect::, ParseError>>()?; + .collect::, ConversionError>>()?; let nullifiers = get_block_inputs .nullifiers @@ -103,7 +103,7 @@ impl TryFrom for BlockInputs { let witness: NullifierWitness = entry.try_into()?; Ok((witness.nullifier, witness.proof)) }) - .collect::, ParseError>>()?; + .collect::, ConversionError>>()?; Ok(Self { block_header, diff --git a/block-producer/src/block_builder/mod.rs b/block-producer/src/block_builder/mod.rs index d92bd7943..f3924e81f 100644 --- a/block-producer/src/block_builder/mod.rs +++ b/block-producer/src/block_builder/mod.rs @@ -2,7 +2,9 @@ use std::sync::Arc; use async_trait::async_trait; use miden_node_utils::formatting::{format_array, format_blake3_digest}; -use miden_objects::{accounts::AccountId, notes::Nullifier, Digest, MAX_NOTES_PER_BATCH}; +use miden_objects::{ + accounts::AccountId, notes::Nullifier, transaction::AccountDetails, Digest, MAX_NOTES_PER_BATCH, +}; use tracing::{debug, info, instrument}; use crate::{ @@ -77,7 +79,7 @@ where batches = %format_array(batches.iter().map(|batch| format_blake3_digest(batch.id()))), ); - let updated_accounts: Vec<(AccountId, Digest)> = + let updated_accounts: Vec<(AccountId, Option, Digest)> = batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let created_notes = batches .iter() @@ -95,7 +97,7 @@ where let block_inputs = self .store .get_block_inputs( - updated_accounts.iter().map(|(account_id, _)| account_id), + updated_accounts.iter().map(|(account_id, _, _)| account_id), produced_nullifiers.iter(), ) .await?; diff --git a/block-producer/src/block_builder/prover/block_witness.rs b/block-producer/src/block_builder/prover/block_witness.rs index 87bcbcd0e..6e4f58b66 100644 --- a/block-producer/src/block_builder/prover/block_witness.rs +++ b/block-producer/src/block_builder/prover/block_witness.rs @@ -37,7 +37,7 @@ impl BlockWitness { let updated_accounts = { let mut account_initial_states: BTreeMap = - batches.iter().flat_map(|batch| batch.account_initial_states()).collect(); + batches.iter().flat_map(TransactionBatch::account_initial_states).collect(); let mut account_merkle_proofs: BTreeMap = block_inputs .accounts @@ -47,8 +47,8 @@ impl BlockWitness { batches .iter() - .flat_map(|batch| batch.updated_accounts()) - .map(|(account_id, final_state_hash)| { + .flat_map(TransactionBatch::updated_accounts) + .map(|(account_id, details, final_state_hash)| { let initial_state_hash = account_initial_states .remove(&account_id) .expect("already validated that key exists"); diff --git a/block-producer/src/block_builder/prover/tests.rs b/block-producer/src/block_builder/prover/tests.rs index 11f0324eb..ab7d91aad 100644 --- a/block-producer/src/block_builder/prover/tests.rs +++ b/block-producer/src/block_builder/prover/tests.rs @@ -235,7 +235,7 @@ async fn test_compute_account_root_success() { account_ids .iter() .zip(account_final_states.iter()) - .map(|(&account_id, &account_hash)| (account_id, account_hash.into())) + .map(|(&account_id, &account_hash)| (account_id, None, account_hash.into())) .collect(), ) .build(); diff --git a/block-producer/src/server/api.rs b/block-producer/src/server/api.rs index 192dd14e4..19616a432 100644 --- a/block-producer/src/server/api.rs +++ b/block-producer/src/server/api.rs @@ -65,6 +65,8 @@ where ); debug!(target: COMPONENT, proof = ?tx.proof()); + // TODO: Validate transaction, if it isn't validated during deserialization + self.queue .add_transaction(tx) .await diff --git a/block-producer/src/state_view/mod.rs b/block-producer/src/state_view/mod.rs index bafbf4e2d..9742a626e 100644 --- a/block-producer/src/state_view/mod.rs +++ b/block-producer/src/state_view/mod.rs @@ -121,24 +121,23 @@ where &self, block: Block, ) -> Result<(), ApplyBlockError> { - self.store.apply_block(block.clone()).await?; + let account_ids_in_block: Vec = + block.updated_accounts.iter().map(|(account_id, _, _)| *account_id).collect(); + let produced_nullifiers = block.produced_nullifiers.clone(); + + self.store.apply_block(block).await?; let mut locked_accounts_in_flight = self.accounts_in_flight.write().await; let mut locked_nullifiers_in_flight = self.nullifiers_in_flight.write().await; // Remove account ids of transactions in block - let account_ids_in_block = block - .updated_accounts - .iter() - .map(|(account_id, _final_account_hash)| account_id); - - for account_id in account_ids_in_block { + for account_id in account_ids_in_block.iter() { let was_in_flight = locked_accounts_in_flight.remove(account_id); debug_assert!(was_in_flight); } // Remove new nullifiers of transactions in block - for nullifier in block.produced_nullifiers.iter() { + for nullifier in produced_nullifiers.iter() { let was_in_flight = locked_nullifiers_in_flight.remove(nullifier); debug_assert!(was_in_flight); } diff --git a/block-producer/src/state_view/tests/apply_block.rs b/block-producer/src/state_view/tests/apply_block.rs index ac4a52348..410d2219d 100644 --- a/block-producer/src/state_view/tests/apply_block.rs +++ b/block-producer/src/state_view/tests/apply_block.rs @@ -32,7 +32,7 @@ async fn test_apply_block_ab1() { .await .account_updates( std::iter::once(account) - .map(|mock_account| (mock_account.id, mock_account.states[1])) + .map(|mock_account| (mock_account.id, None, mock_account.states[1])) .collect(), ) .build(); @@ -75,7 +75,7 @@ async fn test_apply_block_ab2() { .account_updates( accounts_in_block .into_iter() - .map(|mock_account| (mock_account.id, mock_account.states[1])) + .map(|mock_account| (mock_account.id, None, mock_account.states[1])) .collect(), ) .build(); @@ -120,7 +120,7 @@ async fn test_apply_block_ab3() { accounts .clone() .into_iter() - .map(|mock_account| (mock_account.id, mock_account.states[1])) + .map(|mock_account| (mock_account.id, None, mock_account.states[1])) .collect(), ) .build(); diff --git a/block-producer/src/test_utils/block.rs b/block-producer/src/test_utils/block.rs index a158a8d72..8cdadd9b0 100644 --- a/block-producer/src/test_utils/block.rs +++ b/block-producer/src/test_utils/block.rs @@ -4,6 +4,7 @@ use miden_objects::{ accounts::AccountId, crypto::merkle::{Mmr, SimpleSmt}, notes::{NoteEnvelope, Nullifier}, + transaction::AccountDetails, BlockHeader, Digest, ACCOUNT_TREE_DEPTH, BLOCK_OUTPUT_NOTES_TREE_DEPTH, MAX_NOTES_PER_BATCH, ONE, ZERO, }; @@ -25,11 +26,11 @@ pub async fn build_expected_block_header( let last_block_header = *store.last_block_header.read().await; // Compute new account root - let updated_accounts: Vec<(AccountId, Digest)> = + let updated_accounts: Vec<(AccountId, Option, Digest)> = batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let new_account_root = { let mut store_accounts = store.accounts.read().await.clone(); - for (account_id, new_account_state) in updated_accounts { + for (account_id, details, new_account_state) in updated_accounts { store_accounts.insert(account_id.into(), new_account_state.into()); } @@ -67,14 +68,14 @@ pub async fn build_actual_block_header( store: &MockStoreSuccess, batches: Vec, ) -> BlockHeader { - let updated_accounts: Vec<(AccountId, Digest)> = - batches.iter().flat_map(|batch| batch.updated_accounts()).collect(); + let updated_accounts: Vec<(AccountId, Option, Digest)> = + batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let produced_nullifiers: Vec = - batches.iter().flat_map(|batch| batch.produced_nullifiers()).collect(); + batches.iter().flat_map(TransactionBatch::produced_nullifiers).collect(); let block_inputs_from_store: BlockInputs = store .get_block_inputs( - updated_accounts.iter().map(|(account_id, _)| account_id), + updated_accounts.iter().map(|(account_id, _, _)| account_id), produced_nullifiers.iter(), ) .await @@ -91,7 +92,7 @@ pub struct MockBlockBuilder { store_chain_mmr: Mmr, last_block_header: BlockHeader, - updated_accounts: Option>, + updated_accounts: Option, Digest)>>, created_notes: Option>, produced_nullifiers: Option>, } @@ -111,9 +112,9 @@ impl MockBlockBuilder { pub fn account_updates( mut self, - updated_accounts: Vec<(AccountId, Digest)>, + updated_accounts: Vec<(AccountId, Option, Digest)>, ) -> Self { - for &(account_id, new_account_state) in updated_accounts.iter() { + for &(account_id, ref details, new_account_state) in updated_accounts.iter() { self.store_accounts.insert(account_id.into(), new_account_state.into()); } diff --git a/block-producer/src/test_utils/proven_tx.rs b/block-producer/src/test_utils/proven_tx.rs index 1f8f11b53..8df0a2ce2 100644 --- a/block-producer/src/test_utils/proven_tx.rs +++ b/block-producer/src/test_utils/proven_tx.rs @@ -4,7 +4,7 @@ use miden_air::HashFunction; use miden_objects::{ accounts::AccountId, notes::{NoteEnvelope, NoteMetadata, Nullifier}, - transaction::{InputNotes, OutputNotes, ProvenTransaction}, + transaction::{InputNotes, OutputNotes, ProvenTransactio, ProvenTransactionBuilder}, vm::ExecutionProof, Digest, Felt, Hasher, ONE, }; @@ -90,15 +90,16 @@ impl MockProvenTxBuilder { } pub fn build(self) -> ProvenTransaction { - ProvenTransaction::new( + ProvenTransactionBuilder::new( self.account_id, self.initial_account_hash, self.final_account_hash, - InputNotes::new(self.nullifiers.unwrap_or_default()).unwrap(), - OutputNotes::new(self.notes_created.unwrap_or_default()).unwrap(), - None, Digest::default(), ExecutionProof::new(StarkProof::new_dummy(), HashFunction::Blake3_192), ) + .add_input_notes(self.nullifiers.unwrap_or_default()) + .add_output_notes(self.notes_created.unwrap_or_default()) + .build() + .unwrap() } } diff --git a/block-producer/src/test_utils/store.rs b/block-producer/src/test_utils/store.rs index 00f26a2a1..afaf31732 100644 --- a/block-producer/src/test_utils/store.rs +++ b/block-producer/src/test_utils/store.rs @@ -180,7 +180,7 @@ impl ApplyBlock for MockStoreSuccess { let mut locked_produced_nullifiers = self.produced_nullifiers.write().await; // update accounts - for &(account_id, account_hash) in block.updated_accounts.iter() { + for &(account_id, ref details, account_hash) in block.updated_accounts.iter() { locked_accounts.insert(account_id.into(), account_hash.into()); } debug_assert_eq!(locked_accounts.root(), block.header.account_root()); diff --git a/store/src/server/api.rs b/store/src/server/api.rs index dc682bfb4..a78cedde6 100644 --- a/store/src/server/api.rs +++ b/store/src/server/api.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use miden_node_proto::{ convert, - errors::ParseError, + errors::ConversionError, generated::{ self, note::NoteSyncRecord, @@ -23,7 +23,9 @@ use miden_node_proto::{ }, AccountState, }; -use miden_objects::{notes::Nullifier, BlockHeader, Felt, ZERO}; +use miden_objects::{ + crypto::hash::rpo::RpoDigest, notes::Nullifier, transaction::AccountDetails, BlockHeader, Felt, ZERO, +}; use tonic::{Response, Status}; use tracing::{debug, info, instrument}; @@ -181,7 +183,7 @@ impl api_server::Api for StoreApi { .block .ok_or(invalid_argument("Apply block missing block header"))? .try_into() - .map_err(|err: ParseError| Status::invalid_argument(err.to_string()))?; + .map_err(|err: ConversionError| Status::invalid_argument(err.to_string()))?; info!(target: COMPONENT, block_num = block_header.block_num(), block_hash = %block_header.hash()); @@ -190,11 +192,16 @@ impl api_server::Api for StoreApi { .accounts .into_iter() .map(|account_update| { + let account_details: Option = + account_update.details.as_ref().map(TryInto::try_into).transpose().map_err( + |err: ConversionError| Status::invalid_argument(err.to_string()), + )?; let account_state: AccountState = account_update .try_into() - .map_err(|err: ParseError| Status::invalid_argument(err.to_string()))?; + .map_err(|err: ConversionError| Status::invalid_argument(err.to_string()))?; Ok(( account_state.account_id.into(), + // account_state.details, account_state .account_hash .ok_or(invalid_argument("Account update missing account hash"))?, @@ -212,7 +219,9 @@ impl api_server::Api for StoreApi { .note_id .ok_or(invalid_argument("Note missing id"))? .try_into() - .map_err(|err: ParseError| Status::invalid_argument(err.to_string()))?, + .map_err(|err: ConversionError| { + Status::invalid_argument(err.to_string()) + })?, sender: note.sender.ok_or(invalid_argument("Note missing sender"))?.into(), tag: note.tag, }) @@ -393,6 +402,6 @@ fn validate_nullifiers(nullifiers: &[generated::digest::Digest]) -> Result>() + .collect::>() .map_err(|_| invalid_argument("Digest field is not in the modulus range")) } From 58dc518999b2585cdf14805a4a839c86e5ebb845 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:41:36 +0500 Subject: [PATCH 06/23] feat: (WIP) implement account details support --- Cargo.toml | 20 +++++------ proto/proto/requests.proto | 2 +- store/src/server/api.rs | 2 +- store/src/state.rs | 73 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 81310bd4a..12cfd448b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [workspace] members = [ - "block-producer", - "node", - "proto", - "rpc", - "store", - "utils", - "test-macro", + "block-producer", + "node", + "proto", + "rpc", + "store", + "utils", + "test-macro", ] resolver = "2" @@ -31,7 +31,7 @@ miden-tx = { version = "0.1" } thiserror = { version = "1.0" } tracing = { version = "0.1" } tracing-subscriber = { version = "0.3", features = [ - "fmt", - "json", - "env-filter", + "fmt", + "json", + "env-filter", ] } diff --git a/proto/proto/requests.proto b/proto/proto/requests.proto index d5186764f..a49f54aee 100644 --- a/proto/proto/requests.proto +++ b/proto/proto/requests.proto @@ -10,7 +10,7 @@ import "note.proto"; message AccountUpdate { account.AccountId account_id = 1; digest.Digest account_hash = 2; - // Details for public account. + // Details for public (on-chain) account. account.AccountDetails details = 3; } diff --git a/store/src/server/api.rs b/store/src/server/api.rs index a78cedde6..3cb781596 100644 --- a/store/src/server/api.rs +++ b/store/src/server/api.rs @@ -201,7 +201,7 @@ impl api_server::Api for StoreApi { .map_err(|err: ConversionError| Status::invalid_argument(err.to_string()))?; Ok(( account_state.account_id.into(), - // account_state.details, + account_details, account_state .account_hash .ok_or(invalid_argument("Account update missing account hash"))?, diff --git a/store/src/state.rs b/store/src/state.rs index b34a93026..e9fa0cd77 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -4,7 +4,11 @@ //! data is atomically written, and that reads are consistent. use std::{mem, sync::Arc}; -use miden_node_proto::{AccountInputRecord, NullifierWitness}; +use miden_node_proto::{ + errors::{ConversionError, MissingFieldHelper}, + generated::requests::AccountUpdate, + AccountInputRecord, AccountState, NullifierWitness, +}; use miden_node_utils::formatting::{format_account_id, format_array}; use miden_objects::{ crypto::{ @@ -12,12 +16,14 @@ use miden_objects::{ merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, }, notes::{NoteMetadata, Nullifier, NOTE_LEAF_DEPTH}, - AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, + transaction::AccountDetails, + AccountError, BlockHeader, Digest, Felt, FieldElement, Word, ACCOUNT_TREE_DEPTH, EMPTY_WORD, }; use tokio::{ sync::{oneshot, Mutex, RwLock}, time::Instant, }; +use tonic::Status; use tracing::{error, info, info_span, instrument}; use crate::{ @@ -40,6 +46,69 @@ pub struct TransactionInputs { pub nullifiers: Vec, } +pub struct ValidAccount { + id: AccountId, + hash: RpoDigest, + details: Option, +} + +impl TryFrom for ValidAccount { + type Error = ConversionError; + + fn try_from(account_update: AccountUpdate) -> Result { + // TODO: Refactor: add storage interface and read account from it. Make available for block-producer as well. + + let AccountState { + account_id, + account_hash, + } = account_update.try_into()?; + let details = account_update.details.as_ref().map(TryInto::try_into).transpose()?; + + match (account_id.is_on_chain(), details) { + (false, None) => (), + (false, Some(_)) => ProvenTransactionError::OffChainAccountWithDetails(account_id)?, + (true, None) => ProvenTransactionError::OnChainAccountMissingDetails(account_id)?, + (true, Some(details)) => { + let is_new_account = self.initial_account_hash == Digest::default(); + + match (is_new_account, details) { + (true, AccountDetails::Delta(_)) => { + return Err(ProvenTransactionError::NewOnChainAccountRequiresFullDetails( + self.account_id, + )) + }, + (true, AccountDetails::Full(account)) => { + if account.id() != self.account_id { + return Err(ProvenTransactionError::AccountIdMismatch( + self.account_id, + account.id(), + )); + } + if account.hash() != self.final_account_hash { + return Err(ProvenTransactionError::AccountFinalHashMismatch( + self.final_account_hash, + account.hash(), + )); + } + }, + (false, AccountDetails::Full(_)) => { + return Err( + ProvenTransactionError::ExistingOnChainAccountRequiresDeltaDetails( + self.account_id, + ), + ) + }, + (false, AccountDetails::Delta(_)) => (), + } + }, + } + + let id = account_id.into(); + let hash = account_hash.ok_or(AccountUpdate::missing_field(stringify!(account_hash)))?; + id.Ok(Self { id, hash, details }) + } +} + /// Container for state that needs to be updated atomically. struct InnerState { nullifier_tree: NullifierTree, From ef7a1f7bde0bd7094e19320588baf3108993e496 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:41:36 +0500 Subject: [PATCH 07/23] feat: (WIP) implement account details support --- .gitignore | 8 +++++ proto/src/generated/requests.rs | 2 +- store/src/server/api.rs | 4 +-- store/src/state.rs | 63 --------------------------------- 4 files changed, 10 insertions(+), 67 deletions(-) diff --git a/.gitignore b/.gitignore index d03086c8a..69fd90ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,10 @@ target/ # VS Code .vscode/ +# JetBrains IDEs +.idea/ +.fleet/ + # Genesis files /accounts genesis.dat @@ -24,3 +28,7 @@ genesis.dat *.sqlite3 *.sqlite3-shm *.sqlite3-wal + +# Configs +/genesis.toml +/miden.toml diff --git a/proto/src/generated/requests.rs b/proto/src/generated/requests.rs index 9168d81b4..f892408cd 100644 --- a/proto/src/generated/requests.rs +++ b/proto/src/generated/requests.rs @@ -6,7 +6,7 @@ pub struct AccountUpdate { pub account_id: ::core::option::Option, #[prost(message, optional, tag = "2")] pub account_hash: ::core::option::Option, - /// Details for public account. + /// Details for public (on-chain) account. #[prost(message, optional, tag = "3")] pub details: ::core::option::Option, } diff --git a/store/src/server/api.rs b/store/src/server/api.rs index 3cb781596..de9df5c47 100644 --- a/store/src/server/api.rs +++ b/store/src/server/api.rs @@ -23,9 +23,7 @@ use miden_node_proto::{ }, AccountState, }; -use miden_objects::{ - crypto::hash::rpo::RpoDigest, notes::Nullifier, transaction::AccountDetails, BlockHeader, Felt, ZERO, -}; +use miden_objects::{notes::Nullifier, transaction::AccountDetails, BlockHeader, Felt, ZERO}; use tonic::{Response, Status}; use tracing::{debug, info, instrument}; diff --git a/store/src/state.rs b/store/src/state.rs index e9fa0cd77..aaf0a5e13 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -46,69 +46,6 @@ pub struct TransactionInputs { pub nullifiers: Vec, } -pub struct ValidAccount { - id: AccountId, - hash: RpoDigest, - details: Option, -} - -impl TryFrom for ValidAccount { - type Error = ConversionError; - - fn try_from(account_update: AccountUpdate) -> Result { - // TODO: Refactor: add storage interface and read account from it. Make available for block-producer as well. - - let AccountState { - account_id, - account_hash, - } = account_update.try_into()?; - let details = account_update.details.as_ref().map(TryInto::try_into).transpose()?; - - match (account_id.is_on_chain(), details) { - (false, None) => (), - (false, Some(_)) => ProvenTransactionError::OffChainAccountWithDetails(account_id)?, - (true, None) => ProvenTransactionError::OnChainAccountMissingDetails(account_id)?, - (true, Some(details)) => { - let is_new_account = self.initial_account_hash == Digest::default(); - - match (is_new_account, details) { - (true, AccountDetails::Delta(_)) => { - return Err(ProvenTransactionError::NewOnChainAccountRequiresFullDetails( - self.account_id, - )) - }, - (true, AccountDetails::Full(account)) => { - if account.id() != self.account_id { - return Err(ProvenTransactionError::AccountIdMismatch( - self.account_id, - account.id(), - )); - } - if account.hash() != self.final_account_hash { - return Err(ProvenTransactionError::AccountFinalHashMismatch( - self.final_account_hash, - account.hash(), - )); - } - }, - (false, AccountDetails::Full(_)) => { - return Err( - ProvenTransactionError::ExistingOnChainAccountRequiresDeltaDetails( - self.account_id, - ), - ) - }, - (false, AccountDetails::Delta(_)) => (), - } - }, - } - - let id = account_id.into(); - let hash = account_hash.ok_or(AccountUpdate::missing_field(stringify!(account_hash)))?; - id.Ok(Self { id, hash, details }) - } -} - /// Container for state that needs to be updated atomically. struct InnerState { nullifier_tree: NullifierTree, From bb3175357471da77bea11d6a320dd61ac1e18d97 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:19:35 +0500 Subject: [PATCH 08/23] feat: (WIP) implement account details support --- Cargo.lock | 15 +-- Cargo.toml | 6 +- .../src/block_builder/prover/block_witness.rs | 2 +- block-producer/src/test_utils/block.rs | 4 +- block-producer/src/test_utils/proven_tx.rs | 3 +- block-producer/src/test_utils/store.rs | 2 +- store/src/db/mod.rs | 5 +- store/src/db/sql.rs | 109 ++++++++++++++---- store/src/db/tests.rs | 5 +- store/src/errors.rs | 27 ++++- store/src/state.rs | 15 +-- 11 files changed, 139 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ca119d6d..3f3c7bb94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1109,9 +1109,8 @@ dependencies = [ [[package]] name = "miden-lib" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825bc94780153bd3783d9adbdf276ea38fab2ff3ce0815067badaa4d404c5fae" +version = "0.2.0" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#86a81277b236a29b9bb85d329137f1fcc84b6063" dependencies = [ "miden-assembly", "miden-objects", @@ -1258,9 +1257,8 @@ dependencies = [ [[package]] name = "miden-objects" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7379df161104e3ba97812a89e33b4cff8183964af848074d62dd49f34f00aeed" +version = "0.2.0" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#86a81277b236a29b9bb85d329137f1fcc84b6063" dependencies = [ "miden-assembly", "miden-core", @@ -1305,9 +1303,8 @@ dependencies = [ [[package]] name = "miden-tx" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d59fa14ff23132a14fd3cf215e681d99aad83d819500319f0b20c251179c671" +version = "0.2.0" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#86a81277b236a29b9bb85d329137f1fcc84b6063" dependencies = [ "miden-lib", "miden-objects", diff --git a/Cargo.toml b/Cargo.toml index 12cfd448b..9018bfd66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,11 +23,11 @@ exclude = [".github/"] [workspace.dependencies] miden-air = { version = "0.8", default-features = false } -miden-lib = { version = "0.1" } -miden-objects = { version = "0.1" } +miden-lib = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } +miden-objects = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } miden-processor = { version = "0.8" } miden-stdlib = { version = "0.8", default-features = false } -miden-tx = { version = "0.1" } +miden-tx = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } thiserror = { version = "1.0" } tracing = { version = "0.1" } tracing-subscriber = { version = "0.3", features = [ diff --git a/block-producer/src/block_builder/prover/block_witness.rs b/block-producer/src/block_builder/prover/block_witness.rs index 6e4f58b66..25f18dccb 100644 --- a/block-producer/src/block_builder/prover/block_witness.rs +++ b/block-producer/src/block_builder/prover/block_witness.rs @@ -48,7 +48,7 @@ impl BlockWitness { batches .iter() .flat_map(TransactionBatch::updated_accounts) - .map(|(account_id, details, final_state_hash)| { + .map(|(account_id, _details, final_state_hash)| { let initial_state_hash = account_initial_states .remove(&account_id) .expect("already validated that key exists"); diff --git a/block-producer/src/test_utils/block.rs b/block-producer/src/test_utils/block.rs index 8cdadd9b0..9aa12e1c4 100644 --- a/block-producer/src/test_utils/block.rs +++ b/block-producer/src/test_utils/block.rs @@ -30,7 +30,7 @@ pub async fn build_expected_block_header( batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let new_account_root = { let mut store_accounts = store.accounts.read().await.clone(); - for (account_id, details, new_account_state) in updated_accounts { + for (account_id, _details, new_account_state) in updated_accounts { store_accounts.insert(account_id.into(), new_account_state.into()); } @@ -114,7 +114,7 @@ impl MockBlockBuilder { mut self, updated_accounts: Vec<(AccountId, Option, Digest)>, ) -> Self { - for &(account_id, ref details, new_account_state) in updated_accounts.iter() { + for &(account_id, ref _details, new_account_state) in updated_accounts.iter() { self.store_accounts.insert(account_id.into(), new_account_state.into()); } diff --git a/block-producer/src/test_utils/proven_tx.rs b/block-producer/src/test_utils/proven_tx.rs index 8df0a2ce2..32f05f3d7 100644 --- a/block-producer/src/test_utils/proven_tx.rs +++ b/block-producer/src/test_utils/proven_tx.rs @@ -1,10 +1,11 @@ use std::ops::Range; use miden_air::HashFunction; +use miden_objects::transaction::ProvenTransaction; use miden_objects::{ accounts::AccountId, notes::{NoteEnvelope, NoteMetadata, Nullifier}, - transaction::{InputNotes, OutputNotes, ProvenTransactio, ProvenTransactionBuilder}, + transaction::ProvenTransactionBuilder, vm::ExecutionProof, Digest, Felt, Hasher, ONE, }; diff --git a/block-producer/src/test_utils/store.rs b/block-producer/src/test_utils/store.rs index afaf31732..9e7844676 100644 --- a/block-producer/src/test_utils/store.rs +++ b/block-producer/src/test_utils/store.rs @@ -180,7 +180,7 @@ impl ApplyBlock for MockStoreSuccess { let mut locked_produced_nullifiers = self.produced_nullifiers.write().await; // update accounts - for &(account_id, ref details, account_hash) in block.updated_accounts.iter() { + for &(account_id, ref _details, account_hash) in block.updated_accounts.iter() { locked_accounts.insert(account_id.into(), account_hash.into()); } debug_assert_eq!(locked_accounts.root(), block.header.account_root()); diff --git a/store/src/db/mod.rs b/store/src/db/mod.rs index e6ea9ee76..4a28e0732 100644 --- a/store/src/db/mod.rs +++ b/store/src/db/mod.rs @@ -1,6 +1,7 @@ use std::fs::{self, create_dir_all}; use deadpool_sqlite::{Config as SqliteConfig, Hook, HookError, Pool, Runtime}; +use miden_objects::transaction::AccountDetails; use miden_objects::{ crypto::{hash::rpo::RpoDigest, merkle::MerklePath, utils::Deserializable}, notes::Nullifier, @@ -243,7 +244,7 @@ impl Db { block_header: BlockHeader, notes: Vec, nullifiers: Vec, - accounts: Vec<(AccountId, RpoDigest)>, + accounts: Vec<(AccountId, Option, RpoDigest)>, ) -> Result<()> { self.pool .get() @@ -326,7 +327,7 @@ impl Db { let transaction = conn.transaction()?; let accounts: Vec<_> = account_smt .leaves() - .map(|(account_id, state_hash)| (account_id, state_hash.into())) + .map(|(account_id, state_hash)| (account_id, None, state_hash.into())) .collect(); sql::apply_block( &transaction, diff --git a/store/src/db/sql.rs b/store/src/db/sql.rs index 3d5e816e6..33364d451 100644 --- a/store/src/db/sql.rs +++ b/store/src/db/sql.rs @@ -1,6 +1,10 @@ //! Wrapper functions for SQL statements. use std::rc::Rc; +use miden_objects::accounts::{Account, AccountCode, AccountStorage}; +use miden_objects::assets::AssetVault; +use miden_objects::crypto::merkle::MerklePath; +use miden_objects::transaction::AccountDetails; use miden_objects::{ crypto::hash::rpo::RpoDigest, notes::Nullifier, @@ -30,7 +34,7 @@ pub fn select_accounts(conn: &mut Connection) -> Result> { let mut accounts = vec![]; while let Some(row) = rows.next()? { let account_hash_data = row.get_ref(1)?.as_blob()?; - let account_hash = deserialize(account_hash_data)?; + let account_hash = RpoDigest::read_from_bytes(account_hash_data)?; let account_id = column_value_as_u64(row, 0)?; let block_num = row.get(2)?; @@ -57,7 +61,7 @@ pub fn select_account_hashes(conn: &mut Connection) -> Result, RpoDigest)], block_num: BlockNumber, ) -> Result { - let mut stmt = transaction.prepare("INSERT OR REPLACE INTO accounts (account_id, account_hash, block_num) VALUES (?1, ?2, ?3);")?; + let mut acc_stmt = transaction.prepare( + "INSERT OR REPLACE INTO accounts (account_id, account_hash, block_num) VALUES (?1, ?2, ?3);", + )?; + let mut select_details_stmt = transaction.prepare( + "SELECT nonce, vault, storage, code FROM account_details WHERE account_id = ?1;", + )?; + let mut new_details_stmt = transaction.prepare( + "INSERT INTO account_details (account_id, nonce, vault, storage, code) VALUES (?1, ?2, ?3, ?4, ?5);" + )?; + let mut update_details_stmt = transaction.prepare( + "UPDATE account_details SET nonce = ?2, vault = ?3, storage = ?4 WHERE account_id = ?1;", + )?; let mut count = 0; - for (account_id, account_hash) in accounts.iter() { - count += - stmt.execute(params![u64_to_value(*account_id), account_hash.to_bytes(), block_num])? + for (account_id, details, account_hash) in accounts.iter() { + count += acc_stmt.execute(params![ + u64_to_value(*account_id), + account_hash.to_bytes(), + block_num + ])?; + if let Some(details) = details { + match details { + AccountDetails::Full(account) => { + debug_assert!(account.is_new()); + debug_assert_eq!(*account_id, u64::from(account.id())); + let inserted = new_details_stmt.execute(params![ + u64_to_value(account.id().into()), + u64_to_value(account.nonce().as_int()), + account.vault().to_bytes(), + account.storage().to_bytes(), + account.code().to_bytes(), + ])?; + + debug_assert_eq!(inserted, 1); + }, + AccountDetails::Delta(delta) => { + let mut rows = select_details_stmt.query(params![u64_to_value(*account_id)])?; + let Some(row) = rows.next()? else { + return Err(DatabaseError::ApplyBlockFailedAccountNotOnChain(*account_id)); + }; + + let mut account = Account::new( + (*account_id).try_into()?, + AssetVault::read_from_bytes(row.get_ref(1)?.as_blob()?)?, + AccountStorage::read_from_bytes(row.get_ref(2)?.as_blob()?)?, + AccountCode::read_from_bytes(row.get_ref(3)?.as_blob()?)?, + column_value_as_u64(row, 0)? + .try_into() + .map_err(DatabaseError::CorruptedData)?, + ); + + account.apply_delta(delta)?; + + if &account.hash() != account_hash { + return Err(DatabaseError::ApplyBlockFailedAccountHashesMismatch { + calculated: account.hash(), + expected: *account_hash, + }); + } + + let updated = update_details_stmt.execute(params![ + u64_to_value(account.id().into()), + u64_to_value(account.nonce().as_int()), + account.vault().to_bytes(), + account.storage().to_bytes(), + ])?; + + debug_assert_eq!(updated, 1); + }, + } + } } + Ok(count) } @@ -181,7 +251,7 @@ pub fn select_nullifiers(conn: &mut Connection) -> Result Result> { let mut notes = vec![]; while let Some(row) = rows.next()? { let note_id_data = row.get_ref(2)?.as_blob()?; - let note_id = deserialize(note_id_data)?; + let note_id = RpoDigest::read_from_bytes(note_id_data)?; let merkle_path_data = row.get_ref(5)?.as_blob()?; - let merkle_path = deserialize(merkle_path_data)?; + let merkle_path = MerklePath::read_from_bytes(merkle_path_data)?; notes.push(Note { block_num: row.get(0)?, @@ -378,11 +448,11 @@ pub fn select_notes_since_block_by_tag_and_sender( let block_num = row.get(0)?; let note_index = row.get(1)?; let note_id_data = row.get_ref(2)?.as_blob()?; - let note_id = deserialize(note_id_data)?; + let note_id = RpoDigest::read_from_bytes(note_id_data)?; let sender = column_value_as_u64(row, 3)?; let tag = column_value_as_u64(row, 4)?; let merkle_path_data = row.get_ref(5)?.as_blob()?; - let merkle_path = deserialize(merkle_path_data)?; + let merkle_path = MerklePath::read_from_bytes(merkle_path_data)?; let note = Note { block_num, @@ -448,7 +518,7 @@ pub fn select_block_header_by_block_num( match rows.next()? { Some(row) => { let data = row.get_ref(0)?.as_blob()?; - Ok(Some(deserialize(data)?)) + Ok(Some(BlockHeader::read_from_bytes(data)?)) }, None => Ok(None), } @@ -466,7 +536,7 @@ pub fn select_block_headers(conn: &mut Connection) -> Result> { let mut result = vec![]; while let Some(row) = rows.next()? { let block_header_data = row.get_ref(0)?.as_blob()?; - let block_header = deserialize(block_header_data)?; + let block_header = BlockHeader::read_from_bytes(block_header_data)?; result.push(block_header); } @@ -538,7 +608,7 @@ pub fn apply_block( block_header: &BlockHeader, notes: &[Note], nullifiers: &[Nullifier], - accounts: &[(AccountId, RpoDigest)], + accounts: &[(AccountId, Option, RpoDigest)], ) -> Result { let mut count = 0; count += insert_block_header(transaction, block_header)?; @@ -551,11 +621,6 @@ pub fn apply_block( // UTILITIES // ================================================================================================ -/// Decodes a blob from the database into a corresponding deserializable. -fn deserialize(data: &[u8]) -> Result { - T::read_from_bytes(data).map_err(DatabaseError::DeserializationError) -} - /// Returns the high 16 bits of the provided nullifier. pub(crate) fn get_nullifier_prefix(nullifier: &Nullifier) -> u32 { (nullifier.most_significant_felt().as_int() >> 48) as u32 diff --git a/store/src/db/tests.rs b/store/src/db/tests.rs index 57af54176..08a3b33c9 100644 --- a/store/src/db/tests.rs +++ b/store/src/db/tests.rs @@ -170,7 +170,8 @@ fn test_sql_select_accounts() { }); let transaction = conn.transaction().unwrap(); - let res = sql::upsert_accounts(&transaction, &[(account_id, account_hash)], block_num); + let res = + sql::upsert_accounts(&transaction, &[(account_id, None, account_hash)], block_num); assert_eq!(res.unwrap(), 1, "One element must have been inserted"); transaction.commit().unwrap(); let accounts = sql::select_accounts(&mut conn).unwrap(); @@ -385,7 +386,7 @@ fn test_db_account() { let transaction = conn.transaction().unwrap(); let row_count = - sql::upsert_accounts(&transaction, &[(account_id, account_hash)], block_num).unwrap(); + sql::upsert_accounts(&transaction, &[(account_id, None, account_hash)], block_num).unwrap(); transaction.commit().unwrap(); assert_eq!(row_count, 1); diff --git a/store/src/errors.rs b/store/src/errors.rs index 2856b5f96..d71b7ae34 100644 --- a/store/src/errors.rs +++ b/store/src/errors.rs @@ -3,6 +3,7 @@ use std::io; use deadpool_sqlite::PoolError; use miden_objects::{ crypto::{ + hash::rpo::RpoDigest, merkle::{MerkleError, MmrError}, utils::DeserializationError, }, @@ -13,7 +14,7 @@ use rusqlite::types::FromSqlError; use thiserror::Error; use tokio::sync::oneshot::error::RecvError; -use crate::types::BlockNumber; +use crate::types::{AccountId, BlockNumber}; // INTERNAL ERRORS // ================================================================================================= @@ -46,8 +47,32 @@ pub enum DatabaseError { InteractError(String), #[error("Deserialization of BLOB data from database failed: {0}")] DeserializationError(DeserializationError), + #[error("Corrupted data: {0}")] + CorruptedData(String), + #[error("Account error: {0}")] + AccountError(AccountError), #[error("Block applying was broken because of closed channel on state side: {0}")] ApplyBlockFailedClosedChannel(RecvError), + #[error("Failed to apply block because on-chain account details not found: {0}")] + ApplyBlockFailedAccountNotOnChain(AccountId), + #[error("Failed to apply block because of on-chain account final hashes mismatch (expected {expected}, \ + but calculated is {calculated}")] + ApplyBlockFailedAccountHashesMismatch { + expected: RpoDigest, + calculated: RpoDigest, + }, +} + +impl From for DatabaseError { + fn from(value: DeserializationError) -> Self { + Self::DeserializationError(value) + } +} + +impl From for DatabaseError { + fn from(value: AccountError) -> Self { + Self::AccountError(value) + } } // INITIALIZATION ERRORS diff --git a/store/src/state.rs b/store/src/state.rs index aaf0a5e13..67d8e1817 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -4,26 +4,21 @@ //! data is atomically written, and that reads are consistent. use std::{mem, sync::Arc}; -use miden_node_proto::{ - errors::{ConversionError, MissingFieldHelper}, - generated::requests::AccountUpdate, - AccountInputRecord, AccountState, NullifierWitness, -}; +use miden_node_proto::{AccountInputRecord, NullifierWitness}; use miden_node_utils::formatting::{format_account_id, format_array}; +use miden_objects::transaction::AccountDetails; use miden_objects::{ crypto::{ hash::rpo::RpoDigest, merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, }, notes::{NoteMetadata, Nullifier, NOTE_LEAF_DEPTH}, - transaction::AccountDetails, - AccountError, BlockHeader, Digest, Felt, FieldElement, Word, ACCOUNT_TREE_DEPTH, EMPTY_WORD, + AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, }; use tokio::{ sync::{oneshot, Mutex, RwLock}, time::Instant, }; -use tonic::Status; use tracing::{error, info, info_span, instrument}; use crate::{ @@ -111,7 +106,7 @@ impl State { &self, block_header: BlockHeader, nullifiers: Vec, - accounts: Vec<(AccountId, RpoDigest)>, + accounts: Vec<(AccountId, Option, RpoDigest)>, notes: Vec, ) -> Result<(), ApplyBlockError> { let _ = self.writer.try_lock().map_err(|_| ApplyBlockError::ConcurrentWrite)?; @@ -185,7 +180,7 @@ impl State { // update account tree let mut account_tree = inner.account_tree.clone(); - for (account_id, account_hash) in accounts.iter() { + for (account_id, _, account_hash) in accounts.iter() { account_tree.insert(LeafIndex::new_max_depth(*account_id), account_hash.into()); } From ac8150258e235db95d5e386d53171daa6c1a593d Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:27:35 +0500 Subject: [PATCH 09/23] fix: db creation --- store/src/db/migrations.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/store/src/db/migrations.rs b/store/src/db/migrations.rs index 22201b62c..6ef7028a6 100644 --- a/store/src/db/migrations.rs +++ b/store/src/db/migrations.rs @@ -27,7 +27,7 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { PRIMARY KEY (block_num, note_index), CONSTRAINT fk_block_num FOREIGN KEY (block_num) REFERENCES block_headers (block_num), CONSTRAINT notes_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), - CONSTRAINT notes_note_index_is_u32 CHECK (note_index BETWEEN 0 AND 0xFFFFFFFF), + CONSTRAINT notes_note_index_is_u32 CHECK (note_index BETWEEN 0 AND 0xFFFFFFFF) ) STRICT, WITHOUT ROWID; CREATE TABLE @@ -64,12 +64,10 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { block_num INTEGER NOT NULL, PRIMARY KEY (nullifier), - CONSTRAINT fk_block_num FOREIGN KEY (block_number) REFERENCES block_headers (block_num), + CONSTRAINT fk_block_num FOREIGN KEY (block_num) REFERENCES block_headers (block_num), CONSTRAINT nullifiers_nullifier_is_digest CHECK (length(nullifier) = 32), CONSTRAINT nullifiers_nullifier_prefix_is_u16 CHECK (nullifier_prefix BETWEEN 0 AND 0xFFFF), - CONSTRAINT nullifiers_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), - CONSTRAINT nullifiers_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), - FOREIGN KEY (block_num) REFERENCES block_header (block_num) + CONSTRAINT nullifiers_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF) ) STRICT, WITHOUT ROWID; ", )]) From ab9c457d51c376c7b5630d8ed7e31db8de78028f Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Tue, 26 Mar 2024 18:46:31 +0500 Subject: [PATCH 10/23] docs: remove TODO --- block-producer/src/server/api.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/block-producer/src/server/api.rs b/block-producer/src/server/api.rs index 19616a432..192dd14e4 100644 --- a/block-producer/src/server/api.rs +++ b/block-producer/src/server/api.rs @@ -65,8 +65,6 @@ where ); debug!(target: COMPONENT, proof = ?tx.proof()); - // TODO: Validate transaction, if it isn't validated during deserialization - self.queue .add_transaction(tx) .await From 31cfd1965d65b36e1841338f220c8edde1c55bd2 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Tue, 26 Mar 2024 18:58:11 +0500 Subject: [PATCH 11/23] refactor: apply formatting --- block-producer/src/test_utils/proven_tx.rs | 3 +-- store/src/db/mod.rs | 2 +- store/src/db/sql.rs | 9 ++++----- store/src/state.rs | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/block-producer/src/test_utils/proven_tx.rs b/block-producer/src/test_utils/proven_tx.rs index 32f05f3d7..453437f70 100644 --- a/block-producer/src/test_utils/proven_tx.rs +++ b/block-producer/src/test_utils/proven_tx.rs @@ -1,11 +1,10 @@ use std::ops::Range; use miden_air::HashFunction; -use miden_objects::transaction::ProvenTransaction; use miden_objects::{ accounts::AccountId, notes::{NoteEnvelope, NoteMetadata, Nullifier}, - transaction::ProvenTransactionBuilder, + transaction::{ProvenTransaction, ProvenTransactionBuilder}, vm::ExecutionProof, Digest, Felt, Hasher, ONE, }; diff --git a/store/src/db/mod.rs b/store/src/db/mod.rs index 4a28e0732..cc5b4384f 100644 --- a/store/src/db/mod.rs +++ b/store/src/db/mod.rs @@ -1,10 +1,10 @@ use std::fs::{self, create_dir_all}; use deadpool_sqlite::{Config as SqliteConfig, Hook, HookError, Pool, Runtime}; -use miden_objects::transaction::AccountDetails; use miden_objects::{ crypto::{hash::rpo::RpoDigest, merkle::MerklePath, utils::Deserializable}, notes::Nullifier, + transaction::AccountDetails, BlockHeader, GENESIS_BLOCK, }; use rusqlite::vtab::array; diff --git a/store/src/db/sql.rs b/store/src/db/sql.rs index 33364d451..490ce855e 100644 --- a/store/src/db/sql.rs +++ b/store/src/db/sql.rs @@ -1,13 +1,12 @@ //! Wrapper functions for SQL statements. use std::rc::Rc; -use miden_objects::accounts::{Account, AccountCode, AccountStorage}; -use miden_objects::assets::AssetVault; -use miden_objects::crypto::merkle::MerklePath; -use miden_objects::transaction::AccountDetails; use miden_objects::{ - crypto::hash::rpo::RpoDigest, + accounts::{Account, AccountCode, AccountStorage}, + assets::AssetVault, + crypto::{hash::rpo::RpoDigest, merkle::MerklePath}, notes::Nullifier, + transaction::AccountDetails, utils::serde::{Deserializable, Serializable}, BlockHeader, }; diff --git a/store/src/state.rs b/store/src/state.rs index 67d8e1817..4732a6737 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -6,13 +6,13 @@ use std::{mem, sync::Arc}; use miden_node_proto::{AccountInputRecord, NullifierWitness}; use miden_node_utils::formatting::{format_account_id, format_array}; -use miden_objects::transaction::AccountDetails; use miden_objects::{ crypto::{ hash::rpo::RpoDigest, merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, }, notes::{NoteMetadata, Nullifier, NOTE_LEAF_DEPTH}, + transaction::AccountDetails, AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, }; use tokio::{ From 6560444f0e88926442ee0416d3820e071d8309e1 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Wed, 27 Mar 2024 21:42:56 +0500 Subject: [PATCH 12/23] feat: implement endpoint for getting public account details --- proto/proto/requests.proto | 5 ++ proto/proto/responses.proto | 5 ++ proto/proto/store.proto | 1 + proto/src/generated/requests.rs | 8 +++ proto/src/generated/responses.rs | 8 +++ proto/src/generated/store.rs | 86 ++++++++++++++++++++++++++++++++ store/README.md | 55 ++++++++++++++------ store/src/db/mod.rs | 17 +++++++ store/src/db/sql.rs | 40 +++++++++++++-- store/src/errors.rs | 4 +- store/src/server/api.rs | 36 +++++++++++-- store/src/state.rs | 9 ++++ 12 files changed, 246 insertions(+), 28 deletions(-) diff --git a/proto/proto/requests.proto b/proto/proto/requests.proto index a49f54aee..8c271696d 100644 --- a/proto/proto/requests.proto +++ b/proto/proto/requests.proto @@ -86,3 +86,8 @@ message ListNullifiersRequest {} message ListAccountsRequest {} message ListNotesRequest {} + +message GetPublicAccountDetailsRequest { + // Public account ID to get details. + account.AccountId account_id = 1; +} diff --git a/proto/proto/responses.proto b/proto/proto/responses.proto index d7b8f487b..2740bcf6f 100644 --- a/proto/proto/responses.proto +++ b/proto/proto/responses.proto @@ -113,3 +113,8 @@ message ListNotesResponse { // Lists all notes of the current chain repeated note.Note notes = 1; } + +message GetPublicAccountDetailsResponse { + // Public account full details. + account.AccountFullDetails details = 1; +} diff --git a/proto/proto/store.proto b/proto/proto/store.proto index 4c5557755..58054da48 100644 --- a/proto/proto/store.proto +++ b/proto/proto/store.proto @@ -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 GetPublicAccountDetails(requests.GetPublicAccountDetailsRequest) returns (responses.GetPublicAccountDetailsResponse) {} } diff --git a/proto/src/generated/requests.rs b/proto/src/generated/requests.rs index f892408cd..796ef4bb8 100644 --- a/proto/src/generated/requests.rs +++ b/proto/src/generated/requests.rs @@ -115,3 +115,11 @@ pub struct ListAccountsRequest {} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListNotesRequest {} +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPublicAccountDetailsRequest { + /// Public account ID to get details. + #[prost(message, optional, tag = "1")] + pub account_id: ::core::option::Option, +} diff --git a/proto/src/generated/responses.rs b/proto/src/generated/responses.rs index a0d00f301..482bf2a49 100644 --- a/proto/src/generated/responses.rs +++ b/proto/src/generated/responses.rs @@ -158,3 +158,11 @@ pub struct ListNotesResponse { #[prost(message, repeated, tag = "1")] pub notes: ::prost::alloc::vec::Vec, } +#[derive(Eq, PartialOrd, Ord, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPublicAccountDetailsResponse { + /// Public account full details. + #[prost(message, optional, tag = "1")] + pub details: ::core::option::Option, +} diff --git a/proto/src/generated/store.rs b/proto/src/generated/store.rs index d2f62f986..0bc063e7e 100644 --- a/proto/src/generated/store.rs +++ b/proto/src/generated/store.rs @@ -299,6 +299,33 @@ pub mod api_client { req.extensions_mut().insert(GrpcMethod::new("store.Api", "ListNotes")); self.inner.unary(req, path, codec).await } + pub async fn get_public_account_details( + &mut self, + request: impl tonic::IntoRequest< + super::super::requests::GetPublicAccountDetailsRequest, + >, + ) -> std::result::Result< + tonic::Response, + 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/GetPublicAccountDetails", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("store.Api", "GetPublicAccountDetails")); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -373,6 +400,15 @@ pub mod api_server { tonic::Response, tonic::Status, >; + async fn get_public_account_details( + &self, + request: tonic::Request< + super::super::requests::GetPublicAccountDetailsRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct ApiServer { @@ -895,6 +931,56 @@ pub mod api_server { }; Box::pin(fut) } + "/store.Api/GetPublicAccountDetails" => { + #[allow(non_camel_case_types)] + struct GetPublicAccountDetailsSvc(pub Arc); + impl< + T: Api, + > tonic::server::UnaryService< + super::super::requests::GetPublicAccountDetailsRequest, + > for GetPublicAccountDetailsSvc { + type Response = super::super::responses::GetPublicAccountDetailsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::super::requests::GetPublicAccountDetailsRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_public_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 = GetPublicAccountDetailsSvc(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( diff --git a/store/README.md b/store/README.md index a3a95fc69..927df8bf5 100644 --- a/store/README.md +++ b/store/README.md @@ -1,7 +1,7 @@ # Miden node store -The **Store** maintains the state of the chain. It serves as the "source of truth" for the chain - i.e., if it is not in -the store, the node does not consider it to be part of the chain. +The **Store** maintains the state of the chain. It serves as the "source of truth" for the chain - i.e., if it is not in +the store, the node does not consider it to be part of the chain. **Store** is one of components of the [Miden node](..). ## Architecture @@ -22,9 +22,11 @@ cargo install --path store ### Running the Store -In order to run Store, you must provide a genesis file. To generate a genesis file you will need to use [Miden node](../README.md#generating-the-genesis-file)'s `make-genesis` command. +In order to run Store, you must provide a genesis file. To generate a genesis file you will need to +use [Miden node](../README.md#generating-the-genesis-file)'s `make-genesis` command. -You will also need to provide a configuration file. We have an example config file in [store-example.toml](store-example.toml). +You will also need to provide a configuration file. We have an example config file +in [store-example.toml](store-example.toml). Then, to run the Store: @@ -34,7 +36,8 @@ miden-node-store serve --config ## API -The **Store** serves connections using the [gRPC protocol](https://grpc.io) on a port, set in the previously mentioned configuration file. +The **Store** serves connections using the [gRPC protocol](https://grpc.io) on a port, set in the previously mentioned +configuration file. Here is a brief description of supported methods. ### ApplyBlock @@ -70,7 +73,8 @@ Retrieves block header by given block number. **Parameters** -* `block_num`: `uint32` *(optional)* – the block number of the target block. If not provided, the latest known block will be returned. +* `block_num`: `uint32` *(optional)* – the block number of the target block. If not provided, the latest known block + will be returned. **Returns:** @@ -82,7 +86,7 @@ Returns data needed by the block producer to construct and prove the next block. **Parameters** -* `account_ids`: `[AccountId]` – array of account IDs. +* `account_ids`: `[AccountId]` – array of account IDs. * `nullifiers`: `[Digest]` – array of nullifier hashes (not currently in use). **Returns** @@ -94,7 +98,7 @@ Returns data needed by the block producer to construct and prove the next block. ### GetTransactionInputs -Returns the data needed by the block producer to check validity of an incoming transaction. +Returns the data needed by the block producer to check validity of an incoming transaction. **Parameters** @@ -103,21 +107,26 @@ Returns the data needed by the block producer to check validity of an incoming t **Returns** -* `account_state`: `AccountTransactionInputRecord` – account's descriptors. -* `nullifiers`: `[NullifierTransactionInputRecord]` – the block numbers at which corresponding nullifiers have been consumed, zero if not consumed. +* `account_state`: `AccountTransactionInputRecord` – account's descriptors. +* `nullifiers`: `[NullifierTransactionInputRecord]` – the block numbers at which corresponding nullifiers have been + consumed, zero if not consumed. ### SyncState Returns info which can be used by the client to sync up to the latest state of the chain for the objects (accounts, notes, nullifiers) the client is interested in. -This request returns the next block containing requested data. It also returns `chain_tip` which is the latest block number in the chain. -Client is expected to repeat these requests in a loop until `response.block_header.block_num == response.chain_tip`, at which point the client is fully synchronized with the chain. +This request returns the next block containing requested data. It also returns `chain_tip` which is the latest block +number in the chain. +Client is expected to repeat these requests in a loop until `response.block_header.block_num == response.chain_tip`, at +which point the client is fully synchronized with the chain. -Each request also returns info about new notes, nullifiers etc. created. It also returns Chain MMR delta that can be used to update the state of Chain MMR. +Each request also returns info about new notes, nullifiers etc. created. It also returns Chain MMR delta that can be +used to update the state of Chain MMR. This includes both chain MMR peaks and chain MMR nodes. -For preserving some degree of privacy, note tags and nullifiers filters contain only high part of hashes. Thus, returned data +For preserving some degree of privacy, note tags and nullifiers filters contain only high part of hashes. Thus, returned +data contains excessive notes and nullifiers, client can make additional filtering of that data on its side. **Parameters** @@ -132,10 +141,23 @@ contains excessive notes and nullifiers, client can make additional filtering of * `chain_tip`: `uint32` – number of the latest block in the chain. * `block_header`: `BlockHeader` – block header of the block with the first note matching the specified criteria. * `mmr_delta`: `MmrDelta` – data needed to update the partial MMR from `block_num + 1` to `block_header.block_num`. -* `accounts`: `[AccountHashUpdate]` – a list of account hashes updated after `block_num + 1` but not after `block_header.block_num`. +* `accounts`: `[AccountHashUpdate]` – a list of account hashes updated after `block_num + 1` but not + after `block_header.block_num`. * `notes`: `[NoteSyncRecord]` – a list of all notes together with the Merkle paths from `block_header.note_root`. * `nullifiers`: `[NullifierUpdate]` – a list of nullifiers created between `block_num + 1` and `block_header.block_num`. +### GetPublicAccountDetails + +Returns details for public (on-chain) account by id. + +**Parameters** + +* `account_id`: `AccountId` – account id. + +**Returns** + +* `details`: `AccountFullDetails` – public account full details. + ## Methods for testing purposes ### ListNullifiers @@ -148,7 +170,7 @@ This request doesn't have any parameters. **Returns** -* `nullifiers`: `[NullifierLeaf]` – lists of all nullifiers of the current chain. +* `nullifiers`: `[NullifierLeaf]` – lists of all nullifiers of the current chain. ### ListAccounts @@ -175,4 +197,5 @@ This request doesn't have any parameters. * `notes`: `[Note]` – list of all notes of the current chain. ## License + This project is [MIT licensed](../LICENSE). diff --git a/store/src/db/mod.rs b/store/src/db/mod.rs index cc5b4384f..e0b47652d 100644 --- a/store/src/db/mod.rs +++ b/store/src/db/mod.rs @@ -2,6 +2,7 @@ use std::fs::{self, create_dir_all}; use deadpool_sqlite::{Config as SqliteConfig, Hook, HookError, Pool, Runtime}; use miden_objects::{ + accounts::Account, crypto::{hash::rpo::RpoDigest, merkle::MerklePath, utils::Deserializable}, notes::Nullifier, transaction::AccountDetails, @@ -200,6 +201,22 @@ impl Db { })? } + /// Loads public account details from the DB. + #[instrument(target = "miden-store", skip_all, ret(level = "debug"), err)] + pub async fn get_account_details( + &self, + id: AccountId, + ) -> Result { + self.pool + .get() + .await? + .interact(move |conn| sql::get_account_details(conn, id)) + .await + .map_err(|err| { + DatabaseError::InteractError(format!("Get account details task failed: {err}")) + })? + } + #[instrument(target = "miden-store", skip_all, ret(level = "debug"), err)] pub async fn get_state_sync( &self, diff --git a/store/src/db/sql.rs b/store/src/db/sql.rs index 490ce855e..c0cc11ea3 100644 --- a/store/src/db/sql.rs +++ b/store/src/db/sql.rs @@ -116,6 +116,35 @@ pub fn select_accounts_by_block_range( Ok(result) } +/// Select the latest account details by account id from the DB using the given [Connection]. +/// +/// # Returns +/// +/// The latest account details, or an error. +pub fn get_account_details( + conn: &mut Connection, + account_id: AccountId, +) -> Result { + let mut stmt = conn.prepare( + "SELECT nonce, vault, storage, code FROM account_details WHERE account_id = ?1;", + )?; + + let mut rows = stmt.query(params![u64_to_value(account_id)])?; + let Some(row) = rows.next()? else { + return Err(DatabaseError::AccountNotOnChain(account_id)); + }; + + let account = Account::new( + account_id.try_into()?, + AssetVault::read_from_bytes(row.get_ref(1)?.as_blob()?)?, + AccountStorage::read_from_bytes(row.get_ref(2)?.as_blob()?)?, + AccountCode::read_from_bytes(row.get_ref(3)?.as_blob()?)?, + column_value_as_u64(row, 0)?.try_into().map_err(DatabaseError::CorruptedData)?, + ); + + Ok(account) +} + /// Inserts or updates accounts to the DB using the given [Transaction]. /// /// # Returns @@ -146,8 +175,9 @@ pub fn upsert_accounts( let mut count = 0; for (account_id, details, account_hash) in accounts.iter() { + let account_id = *account_id; count += acc_stmt.execute(params![ - u64_to_value(*account_id), + u64_to_value(account_id), account_hash.to_bytes(), block_num ])?; @@ -155,7 +185,7 @@ pub fn upsert_accounts( match details { AccountDetails::Full(account) => { debug_assert!(account.is_new()); - debug_assert_eq!(*account_id, u64::from(account.id())); + debug_assert_eq!(account_id, u64::from(account.id())); let inserted = new_details_stmt.execute(params![ u64_to_value(account.id().into()), u64_to_value(account.nonce().as_int()), @@ -167,13 +197,13 @@ pub fn upsert_accounts( debug_assert_eq!(inserted, 1); }, AccountDetails::Delta(delta) => { - let mut rows = select_details_stmt.query(params![u64_to_value(*account_id)])?; + let mut rows = select_details_stmt.query(params![u64_to_value(account_id)])?; let Some(row) = rows.next()? else { - return Err(DatabaseError::ApplyBlockFailedAccountNotOnChain(*account_id)); + return Err(DatabaseError::AccountNotOnChain(account_id)); }; let mut account = Account::new( - (*account_id).try_into()?, + account_id.try_into()?, AssetVault::read_from_bytes(row.get_ref(1)?.as_blob()?)?, AccountStorage::read_from_bytes(row.get_ref(2)?.as_blob()?)?, AccountCode::read_from_bytes(row.get_ref(3)?.as_blob()?)?, diff --git a/store/src/errors.rs b/store/src/errors.rs index d71b7ae34..c5b8d4d13 100644 --- a/store/src/errors.rs +++ b/store/src/errors.rs @@ -53,8 +53,8 @@ pub enum DatabaseError { AccountError(AccountError), #[error("Block applying was broken because of closed channel on state side: {0}")] ApplyBlockFailedClosedChannel(RecvError), - #[error("Failed to apply block because on-chain account details not found: {0}")] - ApplyBlockFailedAccountNotOnChain(AccountId), + #[error("Public account ({0}) details not found on-chain")] + AccountNotOnChain(AccountId), #[error("Failed to apply block because of on-chain account final hashes mismatch (expected {expected}, \ but calculated is {calculated}")] ApplyBlockFailedAccountHashesMismatch { diff --git a/store/src/server/api.rs b/store/src/server/api.rs index de9df5c47..d229c374e 100644 --- a/store/src/server/api.rs +++ b/store/src/server/api.rs @@ -8,15 +8,15 @@ use miden_node_proto::{ note::NoteSyncRecord, requests::{ ApplyBlockRequest, CheckNullifiersRequest, GetBlockHeaderByNumberRequest, - GetBlockInputsRequest, GetTransactionInputsRequest, ListAccountsRequest, - ListNotesRequest, ListNullifiersRequest, SyncStateRequest, + GetBlockInputsRequest, GetPublicAccountDetailsRequest, GetTransactionInputsRequest, + ListAccountsRequest, ListNotesRequest, ListNullifiersRequest, SyncStateRequest, }, responses::{ AccountHashUpdate, AccountTransactionInputRecord, ApplyBlockResponse, CheckNullifiersResponse, GetBlockHeaderByNumberResponse, GetBlockInputsResponse, - GetTransactionInputsResponse, ListAccountsResponse, ListNotesResponse, - ListNullifiersResponse, NullifierTransactionInputRecord, NullifierUpdate, - SyncStateResponse, + GetPublicAccountDetailsResponse, GetTransactionInputsResponse, ListAccountsResponse, + ListNotesResponse, ListNullifiersResponse, NullifierTransactionInputRecord, + NullifierUpdate, SyncStateResponse, }, smt::SmtLeafEntry, store::api_server, @@ -159,6 +159,32 @@ impl api_server::Api for StoreApi { })) } + /// Returns details for public (on-chain) account by id. + #[instrument( + target = "miden-store", + name = "store:get_public_account_details", + skip_all, + ret(level = "debug"), + err + )] + async fn get_public_account_details( + &self, + request: tonic::Request, + ) -> Result, Status> { + let request = request.into_inner(); + let account = self + .state + .get_account_details( + request.account_id.ok_or(invalid_argument("Account missing id"))?.into(), + ) + .await + .map_err(internal_error)?; + + Ok(Response::new(GetPublicAccountDetailsResponse { + details: Some((&account).into()), + })) + } + // BLOCK PRODUCER ENDPOINTS // -------------------------------------------------------------------------------------------- diff --git a/store/src/state.rs b/store/src/state.rs index 4732a6737..048b6ac16 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -7,6 +7,7 @@ use std::{mem, sync::Arc}; use miden_node_proto::{AccountInputRecord, NullifierWitness}; use miden_node_utils::formatting::{format_account_id, format_array}; use miden_objects::{ + accounts::Account, crypto::{ hash::rpo::RpoDigest, merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, @@ -468,6 +469,14 @@ impl State { pub async fn list_notes(&self) -> Result, DatabaseError> { self.db.select_notes().await } + + /// Returns details for public (on-chain) account. + pub async fn get_account_details( + &self, + id: AccountId, + ) -> Result { + self.db.get_account_details(id).await + } } // UTILITIES From be2be669216b4143f5304ec4d77becc5761736b2 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 29 Mar 2024 08:29:14 +0500 Subject: [PATCH 13/23] tests: add test for storage --- Cargo.lock | 165 +++++++++++++++++- Cargo.toml | 1 + .../src/block_builder/prover/tests.rs | 7 +- block-producer/src/test_utils/proven_tx.rs | 7 +- store/Cargo.toml | 1 + store/src/db/tests.rs | 139 ++++++++++++++- store/src/state.rs | 3 +- 7 files changed, 312 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f3c7bb94..0393c81e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,6 +167,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -335,6 +344,12 @@ version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -431,6 +446,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + [[package]] name = "colorchoice" version = "1.0.0" @@ -458,6 +479,12 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + [[package]] name = "crypto-common" version = "0.1.6" @@ -546,6 +573,35 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -699,6 +755,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -724,6 +789,20 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" @@ -785,6 +864,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.28" @@ -1102,6 +1187,7 @@ dependencies = [ "cc", "glob", "libc", + "serde", "winter-crypto", "winter-math", "winter-utils", @@ -1110,13 +1196,30 @@ dependencies = [ [[package]] name = "miden-lib" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#86a81277b236a29b9bb85d329137f1fcc84b6063" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" dependencies = [ "miden-assembly", "miden-objects", "miden-stdlib", ] +[[package]] +name = "miden-mock" +version = "0.2.0" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" +dependencies = [ + "env_logger", + "hex", + "miden-lib", + "miden-objects", + "miden-processor", + "miden-prover", + "postcard", + "rand", + "rand_pcg", + "winter-rand-utils", +] + [[package]] name = "miden-node" version = "0.2.0" @@ -1217,6 +1320,7 @@ dependencies = [ "figment", "hex", "miden-lib", + "miden-mock", "miden-node-proto", "miden-node-utils", "miden-objects", @@ -1258,13 +1362,15 @@ dependencies = [ [[package]] name = "miden-objects" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#86a81277b236a29b9bb85d329137f1fcc84b6063" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" dependencies = [ + "log", "miden-assembly", "miden-core", "miden-crypto", "miden-processor", "miden-verifier", + "serde", "winter-rand-utils", ] @@ -1304,7 +1410,7 @@ dependencies = [ [[package]] name = "miden-tx" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#86a81277b236a29b9bb85d329137f1fcc84b6063" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" dependencies = [ "miden-lib", "miden-objects", @@ -1588,6 +1694,18 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "postcard" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +dependencies = [ + "cobs", + "embedded-io", + "heapless", + "serde", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1794,6 +1912,16 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core", + "serde", +] + [[package]] name = "rand_xorshift" version = "0.3.0" @@ -1903,6 +2031,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.31" @@ -1946,6 +2083,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + [[package]] name = "serde" version = "1.0.197" @@ -2042,6 +2185,21 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.0" @@ -2798,6 +2956,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0dff7a27296595fbdc653751b3718acd9518288df646e860ecb48915ff0d6c3" dependencies = [ + "serde", "winter-utils", ] diff --git a/Cargo.toml b/Cargo.toml index 9018bfd66..1da084dcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ exclude = [".github/"] [workspace.dependencies] miden-air = { version = "0.8", default-features = false } miden-lib = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } +miden-mock = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } miden-objects = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } miden-processor = { version = "0.8" } miden-stdlib = { version = "0.8", default-features = false } diff --git a/block-producer/src/block_builder/prover/tests.rs b/block-producer/src/block_builder/prover/tests.rs index ab7d91aad..c0d691d35 100644 --- a/block-producer/src/block_builder/prover/tests.rs +++ b/block-producer/src/block_builder/prover/tests.rs @@ -6,7 +6,7 @@ use miden_objects::{ EmptySubtreeRoots, LeafIndex, MerklePath, Mmr, MmrPeaks, SimpleSmt, Smt, SmtLeaf, SmtProof, SMT_DEPTH, }, - notes::{NoteEnvelope, NoteMetadata}, + notes::{NoteEnvelope, NoteMetadata, NoteType}, BLOCK_OUTPUT_NOTES_TREE_DEPTH, ONE, ZERO, }; @@ -381,7 +381,10 @@ async fn test_compute_note_root_success() { .into_iter() .zip(account_ids.iter()) .map(|(note_digest, &account_id)| { - NoteEnvelope::new(note_digest.into(), NoteMetadata::new(account_id, Felt::new(1u64))) + NoteEnvelope::new( + note_digest.into(), + NoteMetadata::new(account_id, NoteType::OffChain, Felt::new(1u64)), + ) }) .collect(); diff --git a/block-producer/src/test_utils/proven_tx.rs b/block-producer/src/test_utils/proven_tx.rs index 453437f70..8a9f5a280 100644 --- a/block-producer/src/test_utils/proven_tx.rs +++ b/block-producer/src/test_utils/proven_tx.rs @@ -3,7 +3,7 @@ use std::ops::Range; use miden_air::HashFunction; use miden_objects::{ accounts::AccountId, - notes::{NoteEnvelope, NoteMetadata, Nullifier}, + notes::{NoteEnvelope, NoteMetadata, NoteType, Nullifier}, transaction::{ProvenTransaction, ProvenTransactionBuilder}, vm::ExecutionProof, Digest, Felt, Hasher, ONE, @@ -82,7 +82,10 @@ impl MockProvenTxBuilder { .map(|note_index| { let note_hash = Hasher::hash(¬e_index.to_be_bytes()); - NoteEnvelope::new(note_hash.into(), NoteMetadata::new(self.account_id, ONE)) + NoteEnvelope::new( + note_hash.into(), + NoteMetadata::new(self.account_id, NoteType::OffChain, ONE), + ) }) .collect(); diff --git a/store/Cargo.toml b/store/Cargo.toml index db5f8b0a3..20b6fb9b2 100644 --- a/store/Cargo.toml +++ b/store/Cargo.toml @@ -42,4 +42,5 @@ tracing-subscriber = { workspace = true } [dev-dependencies] figment = { version = "0.10", features = ["toml", "env", "test"] } +miden-mock = { workspace = true } miden-node-utils = { path = "../utils", version = "0.2", features = ["tracing-forest"] } diff --git a/store/src/db/tests.rs b/store/src/db/tests.rs index 08a3b33c9..406a72b34 100644 --- a/store/src/db/tests.rs +++ b/store/src/db/tests.rs @@ -1,15 +1,26 @@ +use miden_lib::transaction::TransactionKernel; +use miden_mock::mock::account::{ + generate_account_seed, mock_account_code, AccountSeedType, + ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, +}; use miden_objects::{ + accounts::{ + Account, AccountDelta, AccountId, AccountStorage, AccountStorageDelta, AccountVaultDelta, + ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, + }, + assets::{Asset, AssetVault, FungibleAsset, NonFungibleAsset, NonFungibleAssetDetails}, crypto::{ hash::rpo::RpoDigest, merkle::{LeafIndex, MerklePath, SimpleSmt}, }, notes::{Nullifier, NOTE_LEAF_DEPTH}, - BlockHeader, Felt, FieldElement, + transaction::AccountDetails, + BlockHeader, Felt, FieldElement, Word, ONE, ZERO, }; use rusqlite::{vtab::array, Connection}; use super::{sql, AccountInfo, Note, NoteCreated, NullifierInfo}; -use crate::db::migrations; +use crate::{db::migrations, errors::DatabaseError}; fn create_db() -> Connection { let mut conn = Connection::open_in_memory().unwrap(); @@ -179,6 +190,124 @@ fn test_sql_select_accounts() { } } +#[test] +fn test_sql_public_account_details() { + let mut conn = create_db(); + + let block_num = 1; + create_block(&mut conn, block_num); + + let (account_id, _seed) = + generate_account_seed(AccountSeedType::RegularAccountUpdatableCodeOnChain); + let fungible_faucet_id = AccountId::try_from(ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN).unwrap(); + let non_fungible_faucet_id = + AccountId::try_from(ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN).unwrap(); + + let mut storage = AccountStorage::new(vec![]).unwrap(); + storage.set_item(1, num_to_word(1)).unwrap(); + storage.set_item(3, num_to_word(3)).unwrap(); + storage.set_item(5, num_to_word(5)).unwrap(); + + let nft1 = Asset::NonFungible( + NonFungibleAsset::new( + &NonFungibleAssetDetails::new(non_fungible_faucet_id, vec![1, 2, 3]).unwrap(), + ) + .unwrap(), + ); + + let mut account = Account::new( + account_id, + AssetVault::new(&[ + Asset::Fungible(FungibleAsset::new(fungible_faucet_id, 150).unwrap()), + nft1, + ]) + .unwrap(), + storage, + mock_account_code(&TransactionKernel::assembler()), + ZERO, + ); + + // test querying empty table + let res = sql::get_account_details(&mut conn, account_id.into()); + assert!(matches!(res, Err(DatabaseError::AccountNotOnChain(_)))); + + let transaction = conn.transaction().unwrap(); + let inserted = sql::upsert_accounts( + &transaction, + &[(account_id.into(), Some(AccountDetails::Full(account.clone())), account.hash())], + block_num, + ) + .unwrap(); + + assert_eq!(inserted, 1, "One element must have been inserted"); + + transaction.commit().unwrap(); + + let account_read = sql::get_account_details(&mut conn, account_id.into()).unwrap(); + + // TODO: substitute by a single check, once code imports deserialization is fixed: + // assert_eq!(account_read, account); + assert_eq!(account_read.id(), account.id()); + assert_eq!(account_read.vault(), account.vault()); + assert_eq!(account_read.storage(), account.storage()); + assert_eq!(account_read.nonce(), account.nonce()); + + let storage_delta = AccountStorageDelta { + cleared_items: vec![3], + updated_items: vec![(4, num_to_word(5)), (5, num_to_word(6))], + }; + + let nft2 = Asset::NonFungible( + NonFungibleAsset::new( + &NonFungibleAssetDetails::new(non_fungible_faucet_id, vec![4, 5, 6]).unwrap(), + ) + .unwrap(), + ); + + let vault_delta = AccountVaultDelta { + added_assets: vec![nft2], + removed_assets: vec![nft1], + }; + + let delta = AccountDelta::new(storage_delta, vault_delta, Some(ONE)).unwrap(); + + account.apply_delta(&delta).unwrap(); + + let transaction = conn.transaction().unwrap(); + let inserted = sql::upsert_accounts( + &transaction, + &[(account_id.into(), Some(AccountDetails::Delta(delta.clone())), account.hash())], + block_num, + ) + .unwrap(); + + assert_eq!(inserted, 1, "One element must have been inserted"); + + transaction.commit().unwrap(); + + let mut account_read = sql::get_account_details(&mut conn, account_id.into()).unwrap(); + + assert_eq!(account_read.id(), account.id()); + assert_eq!(account_read.vault(), account.vault()); + assert_eq!(account_read.nonce(), account.nonce()); + + // Cleared item was not serialized, check it and apply delta only with clear item second time: + assert_eq!(account_read.storage().get_item(3), RpoDigest::default()); + + let storage_delta = AccountStorageDelta { + cleared_items: vec![3], + updated_items: vec![], + }; + account_read + .apply_delta( + &AccountDelta::new(storage_delta, AccountVaultDelta::default(), Some(Felt::new(2))) + .unwrap(), + ) + .unwrap(); + + assert_eq!(account_read.storage(), account.storage()); +} + #[test] fn test_sql_select_nullifiers_by_block_range() { let mut conn = create_db(); @@ -519,7 +648,11 @@ fn test_notes() { // UTILITIES // ------------------------------------------------------------------------------------------- fn num_to_rpo_digest(n: u64) -> RpoDigest { - RpoDigest::new([Felt::ZERO, Felt::ZERO, Felt::ZERO, Felt::new(n)]) + RpoDigest::new(num_to_word(n)) +} + +fn num_to_word(n: u64) -> Word { + [Felt::ZERO, Felt::ZERO, Felt::ZERO, Felt::new(n)] } fn num_to_nullifier(n: u64) -> Nullifier { diff --git a/store/src/state.rs b/store/src/state.rs index 048b6ac16..e53d54386 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -12,7 +12,7 @@ use miden_objects::{ hash::rpo::RpoDigest, merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, }, - notes::{NoteMetadata, Nullifier, NOTE_LEAF_DEPTH}, + notes::{NoteMetadata, NoteType, Nullifier, NOTE_LEAF_DEPTH}, transaction::AccountDetails, AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, }; @@ -493,6 +493,7 @@ pub fn build_notes_tree( for note in notes.iter() { let note_metadata = NoteMetadata::new( note.sender.try_into()?, + NoteType::OffChain, // TODO: provide correct note type note.tag .try_into() .expect("tag value is greater than or equal to the field modulus"), From fbcfd6b2b55b8c91602ab58e997580c3f6b95deb Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 29 Mar 2024 12:02:47 +0500 Subject: [PATCH 14/23] feat: add rpc endpoint for getting account details --- proto/proto/rpc.proto | 1 + proto/src/generated/rpc.rs | 86 ++++++++++++++++++++++++++++++++++++++ rpc/src/server/api.rs | 25 +++++++++-- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/proto/proto/rpc.proto b/proto/proto/rpc.proto index 015b0a9d3..39ae944f4 100644 --- a/proto/proto/rpc.proto +++ b/proto/proto/rpc.proto @@ -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 GetPublicAccountDetails(requests.GetPublicAccountDetailsRequest) returns (responses.GetPublicAccountDetailsResponse) {} } diff --git a/proto/src/generated/rpc.rs b/proto/src/generated/rpc.rs index 75d47961e..dd327ccd3 100644 --- a/proto/src/generated/rpc.rs +++ b/proto/src/generated/rpc.rs @@ -183,6 +183,33 @@ pub mod api_client { .insert(GrpcMethod::new("rpc.Api", "SubmitProvenTransaction")); self.inner.unary(req, path, codec).await } + pub async fn get_public_account_details( + &mut self, + request: impl tonic::IntoRequest< + super::super::requests::GetPublicAccountDetailsRequest, + >, + ) -> std::result::Result< + tonic::Response, + 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/GetPublicAccountDetails", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("rpc.Api", "GetPublicAccountDetails")); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -224,6 +251,15 @@ pub mod api_server { tonic::Response, tonic::Status, >; + async fn get_public_account_details( + &self, + request: tonic::Request< + super::super::requests::GetPublicAccountDetailsRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct ApiServer { @@ -501,6 +537,56 @@ pub mod api_server { }; Box::pin(fut) } + "/rpc.Api/GetPublicAccountDetails" => { + #[allow(non_camel_case_types)] + struct GetPublicAccountDetailsSvc(pub Arc); + impl< + T: Api, + > tonic::server::UnaryService< + super::super::requests::GetPublicAccountDetailsRequest, + > for GetPublicAccountDetailsSvc { + type Response = super::super::responses::GetPublicAccountDetailsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::super::requests::GetPublicAccountDetailsRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_public_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 = GetPublicAccountDetailsSvc(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( diff --git a/rpc/src/server/api.rs b/rpc/src/server/api.rs index 9b98f1dd1..72e4c3812 100644 --- a/rpc/src/server/api.rs +++ b/rpc/src/server/api.rs @@ -2,12 +2,12 @@ use anyhow::Result; use miden_node_proto::generated::{ block_producer::api_client as block_producer_client, requests::{ - CheckNullifiersRequest, GetBlockHeaderByNumberRequest, SubmitProvenTransactionRequest, - SyncStateRequest, + CheckNullifiersRequest, GetBlockHeaderByNumberRequest, GetPublicAccountDetailsRequest, + SubmitProvenTransactionRequest, SyncStateRequest, }, responses::{ - CheckNullifiersResponse, GetBlockHeaderByNumberResponse, SubmitProvenTransactionResponse, - SyncStateResponse, + CheckNullifiersResponse, GetBlockHeaderByNumberResponse, GetPublicAccountDetailsResponse, + SubmitProvenTransactionResponse, SyncStateResponse, }, rpc::api_server, store::api_client as store_client, @@ -132,4 +132,21 @@ impl api_server::Api for RpcApi { self.block_producer.clone().submit_proven_transaction(request).await } + + /// Returns details for public (on-chain) account by id. + #[instrument( + target = "miden-rpc", + name = "rpc:get_public_account_details", + skip_all, + ret(level = "debug"), + err + )] + async fn get_public_account_details( + &self, + request: tonic::Request, + ) -> std::result::Result, Status> { + debug!(target: COMPONENT, request = ?request.get_ref()); + + self.store.clone().get_public_account_details(request).await + } } From 28d44fb9b701794af156d9a535d02d5d8bf800c9 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 29 Mar 2024 12:50:46 +0500 Subject: [PATCH 15/23] refactor: keep only domain object changes --- Cargo.lock | 159 ------------------ Cargo.toml | 1 - block-producer/src/batch_builder/batch.rs | 17 +- block-producer/src/block.rs | 4 +- block-producer/src/block_builder/mod.rs | 8 +- .../src/block_builder/prover/block_witness.rs | 6 +- .../src/block_builder/prover/tests.rs | 2 +- block-producer/src/state_view/mod.rs | 15 +- .../src/state_view/tests/apply_block.rs | 6 +- block-producer/src/test_utils/block.rs | 19 +-- block-producer/src/test_utils/store.rs | 2 +- proto/proto/requests.proto | 7 - proto/proto/responses.proto | 5 - proto/proto/rpc.proto | 1 - proto/proto/store.proto | 1 - proto/src/domain/accounts.rs | 7 +- proto/src/generated/requests.rs | 11 -- proto/src/generated/responses.rs | 8 - proto/src/generated/rpc.rs | 86 ---------- proto/src/generated/store.rs | 86 ---------- rpc/src/server/api.rs | 25 +-- store/Cargo.toml | 1 - store/README.md | 55 ++---- store/src/db/migrations.rs | 30 +--- store/src/db/mod.rs | 22 +-- store/src/db/sql.rs | 152 ++++------------- store/src/db/tests.rs | 144 +--------------- store/src/errors.rs | 27 +-- store/src/server/api.rs | 43 +---- store/src/state.rs | 14 +- 30 files changed, 111 insertions(+), 853 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0393c81e1..279ea0a24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,15 +167,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -344,12 +335,6 @@ version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.5.0" @@ -446,12 +431,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" -[[package]] -name = "cobs" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" - [[package]] name = "colorchoice" version = "1.0.0" @@ -479,12 +458,6 @@ dependencies = [ "libc", ] -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - [[package]] name = "crypto-common" version = "0.1.6" @@ -573,35 +546,6 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "env_filter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -755,15 +699,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -789,20 +724,6 @@ dependencies = [ "hashbrown 0.14.3", ] -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - [[package]] name = "heck" version = "0.4.1" @@ -864,12 +785,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "0.14.28" @@ -1187,7 +1102,6 @@ dependencies = [ "cc", "glob", "libc", - "serde", "winter-crypto", "winter-math", "winter-utils", @@ -1203,23 +1117,6 @@ dependencies = [ "miden-stdlib", ] -[[package]] -name = "miden-mock" -version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" -dependencies = [ - "env_logger", - "hex", - "miden-lib", - "miden-objects", - "miden-processor", - "miden-prover", - "postcard", - "rand", - "rand_pcg", - "winter-rand-utils", -] - [[package]] name = "miden-node" version = "0.2.0" @@ -1320,7 +1217,6 @@ dependencies = [ "figment", "hex", "miden-lib", - "miden-mock", "miden-node-proto", "miden-node-utils", "miden-objects", @@ -1364,13 +1260,11 @@ name = "miden-objects" version = "0.2.0" source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" dependencies = [ - "log", "miden-assembly", "miden-core", "miden-crypto", "miden-processor", "miden-verifier", - "serde", "winter-rand-utils", ] @@ -1694,18 +1588,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "postcard" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" -dependencies = [ - "cobs", - "embedded-io", - "heapless", - "serde", -] - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1912,16 +1794,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_pcg" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" -dependencies = [ - "rand_core", - "serde", -] - [[package]] name = "rand_xorshift" version = "0.3.0" @@ -2031,15 +1903,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.38.31" @@ -2083,12 +1946,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" - [[package]] name = "serde" version = "1.0.197" @@ -2185,21 +2042,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "strsim" version = "0.11.0" @@ -2956,7 +2798,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0dff7a27296595fbdc653751b3718acd9518288df646e860ecb48915ff0d6c3" dependencies = [ - "serde", "winter-utils", ] diff --git a/Cargo.toml b/Cargo.toml index 1da084dcf..9018bfd66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ exclude = [".github/"] [workspace.dependencies] miden-air = { version = "0.8", default-features = false } miden-lib = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } -miden-mock = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } miden-objects = { git = "https://github.com/0xPolygonMiden/miden-base.git", branch = "next" } miden-processor = { version = "0.8" } miden-stdlib = { version = "0.8", default-features = false } diff --git a/block-producer/src/batch_builder/batch.rs b/block-producer/src/batch_builder/batch.rs index 4976a15ab..2f4752f1d 100644 --- a/block-producer/src/batch_builder/batch.rs +++ b/block-producer/src/batch_builder/batch.rs @@ -7,7 +7,6 @@ use miden_objects::{ merkle::SimpleSmt, }, notes::{NoteEnvelope, Nullifier}, - transaction::AccountDetails, Digest, BATCH_OUTPUT_NOTES_TREE_DEPTH, MAX_NOTES_PER_BATCH, }; use tracing::instrument; @@ -56,7 +55,6 @@ impl TransactionBatch { AccountStates { initial_state: tx.initial_account_hash(), final_state: tx.final_account_hash(), - details: tx.account_details().cloned(), }, ) }) @@ -110,14 +108,12 @@ impl TransactionBatch { .map(|(account_id, account_states)| (*account_id, account_states.initial_state)) } - /// Returns an iterator over (account_id, details, new_state_hash) tuples for accounts that were + /// Returns an iterator over (account_id, new_state_hash) tuples for accounts that were /// modified in this transaction batch. - pub fn updated_accounts( - &self - ) -> impl Iterator, Digest)> + '_ { - self.updated_accounts.iter().map(|(account_id, account_states)| { - (*account_id, account_states.details.clone(), account_states.final_state) - }) + pub fn updated_accounts(&self) -> impl Iterator + '_ { + self.updated_accounts + .iter() + .map(|(account_id, account_states)| (*account_id, account_states.final_state)) } /// Returns an iterator over produced nullifiers for all consumed notes. @@ -151,9 +147,8 @@ impl TransactionBatch { /// account. /// /// TODO: should this be moved into domain objects? -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] struct AccountStates { initial_state: Digest, final_state: Digest, - details: Option, } diff --git a/block-producer/src/block.rs b/block-producer/src/block.rs index 99b21ce60..1f1c677b6 100644 --- a/block-producer/src/block.rs +++ b/block-producer/src/block.rs @@ -9,7 +9,6 @@ use miden_objects::{ accounts::AccountId, crypto::merkle::{MerklePath, MmrPeaks, SmtProof}, notes::{NoteEnvelope, Nullifier}, - transaction::AccountDetails, BlockHeader, Digest, }; @@ -18,10 +17,11 @@ use crate::store::BlockInputsError; #[derive(Debug, Clone)] pub struct Block { pub header: BlockHeader, - pub updated_accounts: Vec<(AccountId, Option, Digest)>, + pub updated_accounts: Vec<(AccountId, Digest)>, pub created_notes: BTreeMap, pub produced_nullifiers: Vec, // TODO: + // - full states for updated public accounts // - full states for created public notes // - zk proof } diff --git a/block-producer/src/block_builder/mod.rs b/block-producer/src/block_builder/mod.rs index f3924e81f..d92bd7943 100644 --- a/block-producer/src/block_builder/mod.rs +++ b/block-producer/src/block_builder/mod.rs @@ -2,9 +2,7 @@ use std::sync::Arc; use async_trait::async_trait; use miden_node_utils::formatting::{format_array, format_blake3_digest}; -use miden_objects::{ - accounts::AccountId, notes::Nullifier, transaction::AccountDetails, Digest, MAX_NOTES_PER_BATCH, -}; +use miden_objects::{accounts::AccountId, notes::Nullifier, Digest, MAX_NOTES_PER_BATCH}; use tracing::{debug, info, instrument}; use crate::{ @@ -79,7 +77,7 @@ where batches = %format_array(batches.iter().map(|batch| format_blake3_digest(batch.id()))), ); - let updated_accounts: Vec<(AccountId, Option, Digest)> = + let updated_accounts: Vec<(AccountId, Digest)> = batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let created_notes = batches .iter() @@ -97,7 +95,7 @@ where let block_inputs = self .store .get_block_inputs( - updated_accounts.iter().map(|(account_id, _, _)| account_id), + updated_accounts.iter().map(|(account_id, _)| account_id), produced_nullifiers.iter(), ) .await?; diff --git a/block-producer/src/block_builder/prover/block_witness.rs b/block-producer/src/block_builder/prover/block_witness.rs index 25f18dccb..87bcbcd0e 100644 --- a/block-producer/src/block_builder/prover/block_witness.rs +++ b/block-producer/src/block_builder/prover/block_witness.rs @@ -37,7 +37,7 @@ impl BlockWitness { let updated_accounts = { let mut account_initial_states: BTreeMap = - batches.iter().flat_map(TransactionBatch::account_initial_states).collect(); + batches.iter().flat_map(|batch| batch.account_initial_states()).collect(); let mut account_merkle_proofs: BTreeMap = block_inputs .accounts @@ -47,8 +47,8 @@ impl BlockWitness { batches .iter() - .flat_map(TransactionBatch::updated_accounts) - .map(|(account_id, _details, final_state_hash)| { + .flat_map(|batch| batch.updated_accounts()) + .map(|(account_id, final_state_hash)| { let initial_state_hash = account_initial_states .remove(&account_id) .expect("already validated that key exists"); diff --git a/block-producer/src/block_builder/prover/tests.rs b/block-producer/src/block_builder/prover/tests.rs index c0d691d35..10d23502e 100644 --- a/block-producer/src/block_builder/prover/tests.rs +++ b/block-producer/src/block_builder/prover/tests.rs @@ -235,7 +235,7 @@ async fn test_compute_account_root_success() { account_ids .iter() .zip(account_final_states.iter()) - .map(|(&account_id, &account_hash)| (account_id, None, account_hash.into())) + .map(|(&account_id, &account_hash)| (account_id, account_hash.into())) .collect(), ) .build(); diff --git a/block-producer/src/state_view/mod.rs b/block-producer/src/state_view/mod.rs index 9742a626e..bafbf4e2d 100644 --- a/block-producer/src/state_view/mod.rs +++ b/block-producer/src/state_view/mod.rs @@ -121,23 +121,24 @@ where &self, block: Block, ) -> Result<(), ApplyBlockError> { - let account_ids_in_block: Vec = - block.updated_accounts.iter().map(|(account_id, _, _)| *account_id).collect(); - let produced_nullifiers = block.produced_nullifiers.clone(); - - self.store.apply_block(block).await?; + self.store.apply_block(block.clone()).await?; let mut locked_accounts_in_flight = self.accounts_in_flight.write().await; let mut locked_nullifiers_in_flight = self.nullifiers_in_flight.write().await; // Remove account ids of transactions in block - for account_id in account_ids_in_block.iter() { + let account_ids_in_block = block + .updated_accounts + .iter() + .map(|(account_id, _final_account_hash)| account_id); + + for account_id in account_ids_in_block { let was_in_flight = locked_accounts_in_flight.remove(account_id); debug_assert!(was_in_flight); } // Remove new nullifiers of transactions in block - for nullifier in produced_nullifiers.iter() { + for nullifier in block.produced_nullifiers.iter() { let was_in_flight = locked_nullifiers_in_flight.remove(nullifier); debug_assert!(was_in_flight); } diff --git a/block-producer/src/state_view/tests/apply_block.rs b/block-producer/src/state_view/tests/apply_block.rs index 410d2219d..ac4a52348 100644 --- a/block-producer/src/state_view/tests/apply_block.rs +++ b/block-producer/src/state_view/tests/apply_block.rs @@ -32,7 +32,7 @@ async fn test_apply_block_ab1() { .await .account_updates( std::iter::once(account) - .map(|mock_account| (mock_account.id, None, mock_account.states[1])) + .map(|mock_account| (mock_account.id, mock_account.states[1])) .collect(), ) .build(); @@ -75,7 +75,7 @@ async fn test_apply_block_ab2() { .account_updates( accounts_in_block .into_iter() - .map(|mock_account| (mock_account.id, None, mock_account.states[1])) + .map(|mock_account| (mock_account.id, mock_account.states[1])) .collect(), ) .build(); @@ -120,7 +120,7 @@ async fn test_apply_block_ab3() { accounts .clone() .into_iter() - .map(|mock_account| (mock_account.id, None, mock_account.states[1])) + .map(|mock_account| (mock_account.id, mock_account.states[1])) .collect(), ) .build(); diff --git a/block-producer/src/test_utils/block.rs b/block-producer/src/test_utils/block.rs index 9aa12e1c4..a158a8d72 100644 --- a/block-producer/src/test_utils/block.rs +++ b/block-producer/src/test_utils/block.rs @@ -4,7 +4,6 @@ use miden_objects::{ accounts::AccountId, crypto::merkle::{Mmr, SimpleSmt}, notes::{NoteEnvelope, Nullifier}, - transaction::AccountDetails, BlockHeader, Digest, ACCOUNT_TREE_DEPTH, BLOCK_OUTPUT_NOTES_TREE_DEPTH, MAX_NOTES_PER_BATCH, ONE, ZERO, }; @@ -26,11 +25,11 @@ pub async fn build_expected_block_header( let last_block_header = *store.last_block_header.read().await; // Compute new account root - let updated_accounts: Vec<(AccountId, Option, Digest)> = + let updated_accounts: Vec<(AccountId, Digest)> = batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let new_account_root = { let mut store_accounts = store.accounts.read().await.clone(); - for (account_id, _details, new_account_state) in updated_accounts { + for (account_id, new_account_state) in updated_accounts { store_accounts.insert(account_id.into(), new_account_state.into()); } @@ -68,14 +67,14 @@ pub async fn build_actual_block_header( store: &MockStoreSuccess, batches: Vec, ) -> BlockHeader { - let updated_accounts: Vec<(AccountId, Option, Digest)> = - batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); + let updated_accounts: Vec<(AccountId, Digest)> = + batches.iter().flat_map(|batch| batch.updated_accounts()).collect(); let produced_nullifiers: Vec = - batches.iter().flat_map(TransactionBatch::produced_nullifiers).collect(); + batches.iter().flat_map(|batch| batch.produced_nullifiers()).collect(); let block_inputs_from_store: BlockInputs = store .get_block_inputs( - updated_accounts.iter().map(|(account_id, _, _)| account_id), + updated_accounts.iter().map(|(account_id, _)| account_id), produced_nullifiers.iter(), ) .await @@ -92,7 +91,7 @@ pub struct MockBlockBuilder { store_chain_mmr: Mmr, last_block_header: BlockHeader, - updated_accounts: Option, Digest)>>, + updated_accounts: Option>, created_notes: Option>, produced_nullifiers: Option>, } @@ -112,9 +111,9 @@ impl MockBlockBuilder { pub fn account_updates( mut self, - updated_accounts: Vec<(AccountId, Option, Digest)>, + updated_accounts: Vec<(AccountId, Digest)>, ) -> Self { - for &(account_id, ref _details, new_account_state) in updated_accounts.iter() { + for &(account_id, new_account_state) in updated_accounts.iter() { self.store_accounts.insert(account_id.into(), new_account_state.into()); } diff --git a/block-producer/src/test_utils/store.rs b/block-producer/src/test_utils/store.rs index 9e7844676..00f26a2a1 100644 --- a/block-producer/src/test_utils/store.rs +++ b/block-producer/src/test_utils/store.rs @@ -180,7 +180,7 @@ impl ApplyBlock for MockStoreSuccess { let mut locked_produced_nullifiers = self.produced_nullifiers.write().await; // update accounts - for &(account_id, ref _details, account_hash) in block.updated_accounts.iter() { + for &(account_id, account_hash) in block.updated_accounts.iter() { locked_accounts.insert(account_id.into(), account_hash.into()); } debug_assert_eq!(locked_accounts.root(), block.header.account_root()); diff --git a/proto/proto/requests.proto b/proto/proto/requests.proto index 8c271696d..d872b3d58 100644 --- a/proto/proto/requests.proto +++ b/proto/proto/requests.proto @@ -10,8 +10,6 @@ import "note.proto"; message AccountUpdate { account.AccountId account_id = 1; digest.Digest account_hash = 2; - // Details for public (on-chain) account. - account.AccountDetails details = 3; } message ApplyBlockRequest { @@ -86,8 +84,3 @@ message ListNullifiersRequest {} message ListAccountsRequest {} message ListNotesRequest {} - -message GetPublicAccountDetailsRequest { - // Public account ID to get details. - account.AccountId account_id = 1; -} diff --git a/proto/proto/responses.proto b/proto/proto/responses.proto index 2740bcf6f..d7b8f487b 100644 --- a/proto/proto/responses.proto +++ b/proto/proto/responses.proto @@ -113,8 +113,3 @@ message ListNotesResponse { // Lists all notes of the current chain repeated note.Note notes = 1; } - -message GetPublicAccountDetailsResponse { - // Public account full details. - account.AccountFullDetails details = 1; -} diff --git a/proto/proto/rpc.proto b/proto/proto/rpc.proto index 39ae944f4..015b0a9d3 100644 --- a/proto/proto/rpc.proto +++ b/proto/proto/rpc.proto @@ -10,5 +10,4 @@ service Api { rpc GetBlockHeaderByNumber(requests.GetBlockHeaderByNumberRequest) returns (responses.GetBlockHeaderByNumberResponse) {} rpc SyncState(requests.SyncStateRequest) returns (responses.SyncStateResponse) {} rpc SubmitProvenTransaction(requests.SubmitProvenTransactionRequest) returns (responses.SubmitProvenTransactionResponse) {} - rpc GetPublicAccountDetails(requests.GetPublicAccountDetailsRequest) returns (responses.GetPublicAccountDetailsResponse) {} } diff --git a/proto/proto/store.proto b/proto/proto/store.proto index 58054da48..4c5557755 100644 --- a/proto/proto/store.proto +++ b/proto/proto/store.proto @@ -17,5 +17,4 @@ service Api { rpc ListNullifiers(requests.ListNullifiersRequest) returns (responses.ListNullifiersResponse) {} rpc ListAccounts(requests.ListAccountsRequest) returns (responses.ListAccountsResponse) {} rpc ListNotes(requests.ListNotesRequest) returns (responses.ListNotesResponse) {} - rpc GetPublicAccountDetails(requests.GetPublicAccountDetailsRequest) returns (responses.GetPublicAccountDetailsResponse) {} } diff --git a/proto/src/domain/accounts.rs b/proto/src/domain/accounts.rs index fe6cd1587..337a1c77d 100644 --- a/proto/src/domain/accounts.rs +++ b/proto/src/domain/accounts.rs @@ -388,14 +388,11 @@ impl TryFrom<&AccountDetailsPb> for AccountDetails { // INTO ACCOUNT UPDATE // ================================================================================================ -impl From<(AccountId, Option, Digest)> for AccountUpdate { - fn from( - (account_id, details, account_hash): (AccountId, Option, Digest) - ) -> Self { +impl From<(AccountId, Digest)> for AccountUpdate { + fn from((account_id, account_hash): (AccountId, Digest)) -> Self { Self { account_id: Some(account_id.into()), account_hash: Some(account_hash.into()), - details: details.as_ref().map(Into::into), } } } diff --git a/proto/src/generated/requests.rs b/proto/src/generated/requests.rs index 796ef4bb8..799551253 100644 --- a/proto/src/generated/requests.rs +++ b/proto/src/generated/requests.rs @@ -6,9 +6,6 @@ pub struct AccountUpdate { pub account_id: ::core::option::Option, #[prost(message, optional, tag = "2")] pub account_hash: ::core::option::Option, - /// Details for public (on-chain) account. - #[prost(message, optional, tag = "3")] - pub details: ::core::option::Option, } #[derive(Eq, PartialOrd, Ord, Hash)] #[allow(clippy::derive_partial_eq_without_eq)] @@ -115,11 +112,3 @@ pub struct ListAccountsRequest {} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListNotesRequest {} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetPublicAccountDetailsRequest { - /// Public account ID to get details. - #[prost(message, optional, tag = "1")] - pub account_id: ::core::option::Option, -} diff --git a/proto/src/generated/responses.rs b/proto/src/generated/responses.rs index 482bf2a49..a0d00f301 100644 --- a/proto/src/generated/responses.rs +++ b/proto/src/generated/responses.rs @@ -158,11 +158,3 @@ pub struct ListNotesResponse { #[prost(message, repeated, tag = "1")] pub notes: ::prost::alloc::vec::Vec, } -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetPublicAccountDetailsResponse { - /// Public account full details. - #[prost(message, optional, tag = "1")] - pub details: ::core::option::Option, -} diff --git a/proto/src/generated/rpc.rs b/proto/src/generated/rpc.rs index dd327ccd3..75d47961e 100644 --- a/proto/src/generated/rpc.rs +++ b/proto/src/generated/rpc.rs @@ -183,33 +183,6 @@ pub mod api_client { .insert(GrpcMethod::new("rpc.Api", "SubmitProvenTransaction")); self.inner.unary(req, path, codec).await } - pub async fn get_public_account_details( - &mut self, - request: impl tonic::IntoRequest< - super::super::requests::GetPublicAccountDetailsRequest, - >, - ) -> std::result::Result< - tonic::Response, - 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/GetPublicAccountDetails", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("rpc.Api", "GetPublicAccountDetails")); - self.inner.unary(req, path, codec).await - } } } /// Generated server implementations. @@ -251,15 +224,6 @@ pub mod api_server { tonic::Response, tonic::Status, >; - async fn get_public_account_details( - &self, - request: tonic::Request< - super::super::requests::GetPublicAccountDetailsRequest, - >, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; } #[derive(Debug)] pub struct ApiServer { @@ -537,56 +501,6 @@ pub mod api_server { }; Box::pin(fut) } - "/rpc.Api/GetPublicAccountDetails" => { - #[allow(non_camel_case_types)] - struct GetPublicAccountDetailsSvc(pub Arc); - impl< - T: Api, - > tonic::server::UnaryService< - super::super::requests::GetPublicAccountDetailsRequest, - > for GetPublicAccountDetailsSvc { - type Response = super::super::responses::GetPublicAccountDetailsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request< - super::super::requests::GetPublicAccountDetailsRequest, - >, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_public_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 = GetPublicAccountDetailsSvc(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( diff --git a/proto/src/generated/store.rs b/proto/src/generated/store.rs index 0bc063e7e..d2f62f986 100644 --- a/proto/src/generated/store.rs +++ b/proto/src/generated/store.rs @@ -299,33 +299,6 @@ pub mod api_client { req.extensions_mut().insert(GrpcMethod::new("store.Api", "ListNotes")); self.inner.unary(req, path, codec).await } - pub async fn get_public_account_details( - &mut self, - request: impl tonic::IntoRequest< - super::super::requests::GetPublicAccountDetailsRequest, - >, - ) -> std::result::Result< - tonic::Response, - 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/GetPublicAccountDetails", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("store.Api", "GetPublicAccountDetails")); - self.inner.unary(req, path, codec).await - } } } /// Generated server implementations. @@ -400,15 +373,6 @@ pub mod api_server { tonic::Response, tonic::Status, >; - async fn get_public_account_details( - &self, - request: tonic::Request< - super::super::requests::GetPublicAccountDetailsRequest, - >, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; } #[derive(Debug)] pub struct ApiServer { @@ -931,56 +895,6 @@ pub mod api_server { }; Box::pin(fut) } - "/store.Api/GetPublicAccountDetails" => { - #[allow(non_camel_case_types)] - struct GetPublicAccountDetailsSvc(pub Arc); - impl< - T: Api, - > tonic::server::UnaryService< - super::super::requests::GetPublicAccountDetailsRequest, - > for GetPublicAccountDetailsSvc { - type Response = super::super::responses::GetPublicAccountDetailsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request< - super::super::requests::GetPublicAccountDetailsRequest, - >, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_public_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 = GetPublicAccountDetailsSvc(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( diff --git a/rpc/src/server/api.rs b/rpc/src/server/api.rs index 72e4c3812..9b98f1dd1 100644 --- a/rpc/src/server/api.rs +++ b/rpc/src/server/api.rs @@ -2,12 +2,12 @@ use anyhow::Result; use miden_node_proto::generated::{ block_producer::api_client as block_producer_client, requests::{ - CheckNullifiersRequest, GetBlockHeaderByNumberRequest, GetPublicAccountDetailsRequest, - SubmitProvenTransactionRequest, SyncStateRequest, + CheckNullifiersRequest, GetBlockHeaderByNumberRequest, SubmitProvenTransactionRequest, + SyncStateRequest, }, responses::{ - CheckNullifiersResponse, GetBlockHeaderByNumberResponse, GetPublicAccountDetailsResponse, - SubmitProvenTransactionResponse, SyncStateResponse, + CheckNullifiersResponse, GetBlockHeaderByNumberResponse, SubmitProvenTransactionResponse, + SyncStateResponse, }, rpc::api_server, store::api_client as store_client, @@ -132,21 +132,4 @@ impl api_server::Api for RpcApi { self.block_producer.clone().submit_proven_transaction(request).await } - - /// Returns details for public (on-chain) account by id. - #[instrument( - target = "miden-rpc", - name = "rpc:get_public_account_details", - skip_all, - ret(level = "debug"), - err - )] - async fn get_public_account_details( - &self, - request: tonic::Request, - ) -> std::result::Result, Status> { - debug!(target: COMPONENT, request = ?request.get_ref()); - - self.store.clone().get_public_account_details(request).await - } } diff --git a/store/Cargo.toml b/store/Cargo.toml index 20b6fb9b2..db5f8b0a3 100644 --- a/store/Cargo.toml +++ b/store/Cargo.toml @@ -42,5 +42,4 @@ tracing-subscriber = { workspace = true } [dev-dependencies] figment = { version = "0.10", features = ["toml", "env", "test"] } -miden-mock = { workspace = true } miden-node-utils = { path = "../utils", version = "0.2", features = ["tracing-forest"] } diff --git a/store/README.md b/store/README.md index 927df8bf5..a3a95fc69 100644 --- a/store/README.md +++ b/store/README.md @@ -1,7 +1,7 @@ # Miden node store -The **Store** maintains the state of the chain. It serves as the "source of truth" for the chain - i.e., if it is not in -the store, the node does not consider it to be part of the chain. +The **Store** maintains the state of the chain. It serves as the "source of truth" for the chain - i.e., if it is not in +the store, the node does not consider it to be part of the chain. **Store** is one of components of the [Miden node](..). ## Architecture @@ -22,11 +22,9 @@ cargo install --path store ### Running the Store -In order to run Store, you must provide a genesis file. To generate a genesis file you will need to -use [Miden node](../README.md#generating-the-genesis-file)'s `make-genesis` command. +In order to run Store, you must provide a genesis file. To generate a genesis file you will need to use [Miden node](../README.md#generating-the-genesis-file)'s `make-genesis` command. -You will also need to provide a configuration file. We have an example config file -in [store-example.toml](store-example.toml). +You will also need to provide a configuration file. We have an example config file in [store-example.toml](store-example.toml). Then, to run the Store: @@ -36,8 +34,7 @@ miden-node-store serve --config ## API -The **Store** serves connections using the [gRPC protocol](https://grpc.io) on a port, set in the previously mentioned -configuration file. +The **Store** serves connections using the [gRPC protocol](https://grpc.io) on a port, set in the previously mentioned configuration file. Here is a brief description of supported methods. ### ApplyBlock @@ -73,8 +70,7 @@ Retrieves block header by given block number. **Parameters** -* `block_num`: `uint32` *(optional)* – the block number of the target block. If not provided, the latest known block - will be returned. +* `block_num`: `uint32` *(optional)* – the block number of the target block. If not provided, the latest known block will be returned. **Returns:** @@ -86,7 +82,7 @@ Returns data needed by the block producer to construct and prove the next block. **Parameters** -* `account_ids`: `[AccountId]` – array of account IDs. +* `account_ids`: `[AccountId]` – array of account IDs. * `nullifiers`: `[Digest]` – array of nullifier hashes (not currently in use). **Returns** @@ -98,7 +94,7 @@ Returns data needed by the block producer to construct and prove the next block. ### GetTransactionInputs -Returns the data needed by the block producer to check validity of an incoming transaction. +Returns the data needed by the block producer to check validity of an incoming transaction. **Parameters** @@ -107,26 +103,21 @@ Returns the data needed by the block producer to check validity of an incoming t **Returns** -* `account_state`: `AccountTransactionInputRecord` – account's descriptors. -* `nullifiers`: `[NullifierTransactionInputRecord]` – the block numbers at which corresponding nullifiers have been - consumed, zero if not consumed. +* `account_state`: `AccountTransactionInputRecord` – account's descriptors. +* `nullifiers`: `[NullifierTransactionInputRecord]` – the block numbers at which corresponding nullifiers have been consumed, zero if not consumed. ### SyncState Returns info which can be used by the client to sync up to the latest state of the chain for the objects (accounts, notes, nullifiers) the client is interested in. -This request returns the next block containing requested data. It also returns `chain_tip` which is the latest block -number in the chain. -Client is expected to repeat these requests in a loop until `response.block_header.block_num == response.chain_tip`, at -which point the client is fully synchronized with the chain. +This request returns the next block containing requested data. It also returns `chain_tip` which is the latest block number in the chain. +Client is expected to repeat these requests in a loop until `response.block_header.block_num == response.chain_tip`, at which point the client is fully synchronized with the chain. -Each request also returns info about new notes, nullifiers etc. created. It also returns Chain MMR delta that can be -used to update the state of Chain MMR. +Each request also returns info about new notes, nullifiers etc. created. It also returns Chain MMR delta that can be used to update the state of Chain MMR. This includes both chain MMR peaks and chain MMR nodes. -For preserving some degree of privacy, note tags and nullifiers filters contain only high part of hashes. Thus, returned -data +For preserving some degree of privacy, note tags and nullifiers filters contain only high part of hashes. Thus, returned data contains excessive notes and nullifiers, client can make additional filtering of that data on its side. **Parameters** @@ -141,23 +132,10 @@ contains excessive notes and nullifiers, client can make additional filtering of * `chain_tip`: `uint32` – number of the latest block in the chain. * `block_header`: `BlockHeader` – block header of the block with the first note matching the specified criteria. * `mmr_delta`: `MmrDelta` – data needed to update the partial MMR from `block_num + 1` to `block_header.block_num`. -* `accounts`: `[AccountHashUpdate]` – a list of account hashes updated after `block_num + 1` but not - after `block_header.block_num`. +* `accounts`: `[AccountHashUpdate]` – a list of account hashes updated after `block_num + 1` but not after `block_header.block_num`. * `notes`: `[NoteSyncRecord]` – a list of all notes together with the Merkle paths from `block_header.note_root`. * `nullifiers`: `[NullifierUpdate]` – a list of nullifiers created between `block_num + 1` and `block_header.block_num`. -### GetPublicAccountDetails - -Returns details for public (on-chain) account by id. - -**Parameters** - -* `account_id`: `AccountId` – account id. - -**Returns** - -* `details`: `AccountFullDetails` – public account full details. - ## Methods for testing purposes ### ListNullifiers @@ -170,7 +148,7 @@ This request doesn't have any parameters. **Returns** -* `nullifiers`: `[NullifierLeaf]` – lists of all nullifiers of the current chain. +* `nullifiers`: `[NullifierLeaf]` – lists of all nullifiers of the current chain. ### ListAccounts @@ -197,5 +175,4 @@ This request doesn't have any parameters. * `notes`: `[Note]` – list of all notes of the current chain. ## License - This project is [MIT licensed](../LICENSE). diff --git a/store/src/db/migrations.rs b/store/src/db/migrations.rs index 6ef7028a6..3eec2bc0b 100644 --- a/store/src/db/migrations.rs +++ b/store/src/db/migrations.rs @@ -11,7 +11,7 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { block_header BLOB NOT NULL, PRIMARY KEY (block_num), - CONSTRAINT block_header_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF) + CONSTRAINT block_header_block_num_is_u32 CHECK (block_num >= 0 AND block_num < 4294967296) ) STRICT, WITHOUT ROWID; CREATE TABLE @@ -26,8 +26,8 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { PRIMARY KEY (block_num, note_index), CONSTRAINT fk_block_num FOREIGN KEY (block_num) REFERENCES block_headers (block_num), - CONSTRAINT notes_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF), - CONSTRAINT notes_note_index_is_u32 CHECK (note_index BETWEEN 0 AND 0xFFFFFFFF) + CONSTRAINT notes_block_number_is_u32 CHECK (block_num >= 0 AND block_num < 4294967296), + CONSTRAINT notes_note_index_is_u32 CHECK (note_index >= 0 AND note_index < 4294967296) ) STRICT, WITHOUT ROWID; CREATE TABLE @@ -39,21 +39,7 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { PRIMARY KEY (account_id), CONSTRAINT fk_block_num FOREIGN KEY (block_num) REFERENCES block_headers (block_num), - CONSTRAINT accounts_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF) - ) STRICT, WITHOUT ROWID; - - CREATE TABLE - account_details - ( - account_id INTEGER NOT NULL, - nonce INTEGER NOT NULL, - vault BLOB NOT NULL, - storage BLOB NOT NULL, - code BLOB NOT NULL, - - PRIMARY KEY (account_id), - CONSTRAINT account_details_nonce_non_negative CHECK (nonce >= 0), - FOREIGN KEY (account_id) REFERENCES accounts (account_id) + CONSTRAINT accounts_block_num_is_u32 CHECK (block_num >= 0 AND block_num < 4294967296) ) STRICT, WITHOUT ROWID; CREATE TABLE @@ -61,13 +47,13 @@ pub static MIGRATIONS: Lazy = Lazy::new(|| { ( nullifier BLOB NOT NULL, nullifier_prefix INTEGER NOT NULL, - block_num INTEGER NOT NULL, + block_number INTEGER NOT NULL, PRIMARY KEY (nullifier), - CONSTRAINT fk_block_num FOREIGN KEY (block_num) REFERENCES block_headers (block_num), + CONSTRAINT fk_block_num FOREIGN KEY (block_number) REFERENCES block_headers (block_num), CONSTRAINT nullifiers_nullifier_is_digest CHECK (length(nullifier) = 32), - CONSTRAINT nullifiers_nullifier_prefix_is_u16 CHECK (nullifier_prefix BETWEEN 0 AND 0xFFFF), - CONSTRAINT nullifiers_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF) + CONSTRAINT nullifiers_nullifier_prefix_is_u16 CHECK (nullifier_prefix >= 0 AND nullifier_prefix < 65536), + CONSTRAINT nullifiers_block_number_is_u32 CHECK (block_number >= 0 AND block_number < 4294967296) ) STRICT, WITHOUT ROWID; ", )]) diff --git a/store/src/db/mod.rs b/store/src/db/mod.rs index e0b47652d..e6ea9ee76 100644 --- a/store/src/db/mod.rs +++ b/store/src/db/mod.rs @@ -2,10 +2,8 @@ use std::fs::{self, create_dir_all}; use deadpool_sqlite::{Config as SqliteConfig, Hook, HookError, Pool, Runtime}; use miden_objects::{ - accounts::Account, crypto::{hash::rpo::RpoDigest, merkle::MerklePath, utils::Deserializable}, notes::Nullifier, - transaction::AccountDetails, BlockHeader, GENESIS_BLOCK, }; use rusqlite::vtab::array; @@ -201,22 +199,6 @@ impl Db { })? } - /// Loads public account details from the DB. - #[instrument(target = "miden-store", skip_all, ret(level = "debug"), err)] - pub async fn get_account_details( - &self, - id: AccountId, - ) -> Result { - self.pool - .get() - .await? - .interact(move |conn| sql::get_account_details(conn, id)) - .await - .map_err(|err| { - DatabaseError::InteractError(format!("Get account details task failed: {err}")) - })? - } - #[instrument(target = "miden-store", skip_all, ret(level = "debug"), err)] pub async fn get_state_sync( &self, @@ -261,7 +243,7 @@ impl Db { block_header: BlockHeader, notes: Vec, nullifiers: Vec, - accounts: Vec<(AccountId, Option, RpoDigest)>, + accounts: Vec<(AccountId, RpoDigest)>, ) -> Result<()> { self.pool .get() @@ -344,7 +326,7 @@ impl Db { let transaction = conn.transaction()?; let accounts: Vec<_> = account_smt .leaves() - .map(|(account_id, state_hash)| (account_id, None, state_hash.into())) + .map(|(account_id, state_hash)| (account_id, state_hash.into())) .collect(); sql::apply_block( &transaction, diff --git a/store/src/db/sql.rs b/store/src/db/sql.rs index c0cc11ea3..55d2ddf65 100644 --- a/store/src/db/sql.rs +++ b/store/src/db/sql.rs @@ -2,11 +2,8 @@ use std::rc::Rc; use miden_objects::{ - accounts::{Account, AccountCode, AccountStorage}, - assets::AssetVault, - crypto::{hash::rpo::RpoDigest, merkle::MerklePath}, + crypto::hash::rpo::RpoDigest, notes::Nullifier, - transaction::AccountDetails, utils::serde::{Deserializable, Serializable}, BlockHeader, }; @@ -33,7 +30,7 @@ pub fn select_accounts(conn: &mut Connection) -> Result> { let mut accounts = vec![]; while let Some(row) = rows.next()? { let account_hash_data = row.get_ref(1)?.as_blob()?; - let account_hash = RpoDigest::read_from_bytes(account_hash_data)?; + let account_hash = deserialize(account_hash_data)?; let account_id = column_value_as_u64(row, 0)?; let block_num = row.get(2)?; @@ -60,7 +57,7 @@ pub fn select_account_hashes(conn: &mut Connection) -> Result Result { - let mut stmt = conn.prepare( - "SELECT nonce, vault, storage, code FROM account_details WHERE account_id = ?1;", - )?; - - let mut rows = stmt.query(params![u64_to_value(account_id)])?; - let Some(row) = rows.next()? else { - return Err(DatabaseError::AccountNotOnChain(account_id)); - }; - - let account = Account::new( - account_id.try_into()?, - AssetVault::read_from_bytes(row.get_ref(1)?.as_blob()?)?, - AccountStorage::read_from_bytes(row.get_ref(2)?.as_blob()?)?, - AccountCode::read_from_bytes(row.get_ref(3)?.as_blob()?)?, - column_value_as_u64(row, 0)?.try_into().map_err(DatabaseError::CorruptedData)?, - ); - - Ok(account) -} - /// Inserts or updates accounts to the DB using the given [Transaction]. /// /// # Returns @@ -157,83 +125,16 @@ pub fn get_account_details( /// transaction. pub fn upsert_accounts( transaction: &Transaction, - accounts: &[(AccountId, Option, RpoDigest)], + accounts: &[(AccountId, RpoDigest)], block_num: BlockNumber, ) -> Result { - let mut acc_stmt = transaction.prepare( - "INSERT OR REPLACE INTO accounts (account_id, account_hash, block_num) VALUES (?1, ?2, ?3);", - )?; - let mut select_details_stmt = transaction.prepare( - "SELECT nonce, vault, storage, code FROM account_details WHERE account_id = ?1;", - )?; - let mut new_details_stmt = transaction.prepare( - "INSERT INTO account_details (account_id, nonce, vault, storage, code) VALUES (?1, ?2, ?3, ?4, ?5);" - )?; - let mut update_details_stmt = transaction.prepare( - "UPDATE account_details SET nonce = ?2, vault = ?3, storage = ?4 WHERE account_id = ?1;", - )?; + let mut stmt = transaction.prepare("INSERT OR REPLACE INTO accounts (account_id, account_hash, block_num) VALUES (?1, ?2, ?3);")?; let mut count = 0; - for (account_id, details, account_hash) in accounts.iter() { - let account_id = *account_id; - count += acc_stmt.execute(params![ - u64_to_value(account_id), - account_hash.to_bytes(), - block_num - ])?; - if let Some(details) = details { - match details { - AccountDetails::Full(account) => { - debug_assert!(account.is_new()); - debug_assert_eq!(account_id, u64::from(account.id())); - let inserted = new_details_stmt.execute(params![ - u64_to_value(account.id().into()), - u64_to_value(account.nonce().as_int()), - account.vault().to_bytes(), - account.storage().to_bytes(), - account.code().to_bytes(), - ])?; - - debug_assert_eq!(inserted, 1); - }, - AccountDetails::Delta(delta) => { - let mut rows = select_details_stmt.query(params![u64_to_value(account_id)])?; - let Some(row) = rows.next()? else { - return Err(DatabaseError::AccountNotOnChain(account_id)); - }; - - let mut account = Account::new( - account_id.try_into()?, - AssetVault::read_from_bytes(row.get_ref(1)?.as_blob()?)?, - AccountStorage::read_from_bytes(row.get_ref(2)?.as_blob()?)?, - AccountCode::read_from_bytes(row.get_ref(3)?.as_blob()?)?, - column_value_as_u64(row, 0)? - .try_into() - .map_err(DatabaseError::CorruptedData)?, - ); - - account.apply_delta(delta)?; - - if &account.hash() != account_hash { - return Err(DatabaseError::ApplyBlockFailedAccountHashesMismatch { - calculated: account.hash(), - expected: *account_hash, - }); - } - - let updated = update_details_stmt.execute(params![ - u64_to_value(account.id().into()), - u64_to_value(account.nonce().as_int()), - account.vault().to_bytes(), - account.storage().to_bytes(), - ])?; - - debug_assert_eq!(updated, 1); - }, - } - } + for (account_id, account_hash) in accounts.iter() { + count += + stmt.execute(params![u64_to_value(*account_id), account_hash.to_bytes(), block_num])? } - Ok(count) } @@ -256,7 +157,7 @@ pub fn insert_nullifiers_for_block( block_num: BlockNumber, ) -> Result { let mut stmt = transaction.prepare( - "INSERT INTO nullifiers (nullifier, nullifier_prefix, block_num) VALUES (?1, ?2, ?3);", + "INSERT INTO nullifiers (nullifier, nullifier_prefix, block_number) VALUES (?1, ?2, ?3);", )?; let mut count = 0; @@ -274,13 +175,13 @@ pub fn insert_nullifiers_for_block( /// A vector with nullifiers and the block height at which they were created, or an error. pub fn select_nullifiers(conn: &mut Connection) -> Result> { let mut stmt = - conn.prepare("SELECT nullifier, block_num FROM nullifiers ORDER BY block_num ASC;")?; + conn.prepare("SELECT nullifier, block_number FROM nullifiers ORDER BY block_number ASC;")?; let mut rows = stmt.query([])?; let mut result = vec![]; while let Some(row) = rows.next()? { let nullifier_data = row.get_ref(0)?.as_blob()?; - let nullifier = Nullifier::read_from_bytes(nullifier_data)?; + let nullifier = deserialize(nullifier_data)?; let block_number = row.get(1)?; result.push((nullifier, block_number)); } @@ -310,15 +211,15 @@ pub fn select_nullifiers_by_block_range( " SELECT nullifier, - block_num + block_number FROM nullifiers WHERE - block_num > ?1 AND - block_num <= ?2 AND + block_number > ?1 AND + block_number <= ?2 AND nullifier_prefix IN rarray(?3) ORDER BY - block_num ASC + block_number ASC ", )?; @@ -327,7 +228,7 @@ pub fn select_nullifiers_by_block_range( let mut result = Vec::new(); while let Some(row) = rows.next()? { let nullifier_data = row.get_ref(0)?.as_blob()?; - let nullifier = Nullifier::read_from_bytes(nullifier_data)?; + let nullifier = deserialize(nullifier_data)?; let block_num = row.get(1)?; result.push(NullifierInfo { nullifier, @@ -353,10 +254,10 @@ pub fn select_notes(conn: &mut Connection) -> Result> { let mut notes = vec![]; while let Some(row) = rows.next()? { let note_id_data = row.get_ref(2)?.as_blob()?; - let note_id = RpoDigest::read_from_bytes(note_id_data)?; + let note_id = deserialize(note_id_data)?; let merkle_path_data = row.get_ref(5)?.as_blob()?; - let merkle_path = MerklePath::read_from_bytes(merkle_path_data)?; + let merkle_path = deserialize(merkle_path_data)?; notes.push(Note { block_num: row.get(0)?, @@ -477,11 +378,11 @@ pub fn select_notes_since_block_by_tag_and_sender( let block_num = row.get(0)?; let note_index = row.get(1)?; let note_id_data = row.get_ref(2)?.as_blob()?; - let note_id = RpoDigest::read_from_bytes(note_id_data)?; + let note_id = deserialize(note_id_data)?; let sender = column_value_as_u64(row, 3)?; let tag = column_value_as_u64(row, 4)?; let merkle_path_data = row.get_ref(5)?.as_blob()?; - let merkle_path = MerklePath::read_from_bytes(merkle_path_data)?; + let merkle_path = deserialize(merkle_path_data)?; let note = Note { block_num, @@ -547,7 +448,7 @@ pub fn select_block_header_by_block_num( match rows.next()? { Some(row) => { let data = row.get_ref(0)?.as_blob()?; - Ok(Some(BlockHeader::read_from_bytes(data)?)) + Ok(Some(deserialize(data)?)) }, None => Ok(None), } @@ -565,7 +466,7 @@ pub fn select_block_headers(conn: &mut Connection) -> Result> { let mut result = vec![]; while let Some(row) = rows.next()? { let block_header_data = row.get_ref(0)?.as_blob()?; - let block_header = BlockHeader::read_from_bytes(block_header_data)?; + let block_header = deserialize(block_header_data)?; result.push(block_header); } @@ -637,7 +538,7 @@ pub fn apply_block( block_header: &BlockHeader, notes: &[Note], nullifiers: &[Nullifier], - accounts: &[(AccountId, Option, RpoDigest)], + accounts: &[(AccountId, RpoDigest)], ) -> Result { let mut count = 0; count += insert_block_header(transaction, block_header)?; @@ -650,6 +551,11 @@ pub fn apply_block( // UTILITIES // ================================================================================================ +/// Decodes a blob from the database into a corresponding deserializable. +fn deserialize(data: &[u8]) -> Result { + T::read_from_bytes(data).map_err(DatabaseError::DeserializationError) +} + /// Returns the high 16 bits of the provided nullifier. pub(crate) fn get_nullifier_prefix(nullifier: &Nullifier) -> u32 { (nullifier.most_significant_felt().as_int() >> 48) as u32 diff --git a/store/src/db/tests.rs b/store/src/db/tests.rs index 406a72b34..57af54176 100644 --- a/store/src/db/tests.rs +++ b/store/src/db/tests.rs @@ -1,26 +1,15 @@ -use miden_lib::transaction::TransactionKernel; -use miden_mock::mock::account::{ - generate_account_seed, mock_account_code, AccountSeedType, - ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN, -}; use miden_objects::{ - accounts::{ - Account, AccountDelta, AccountId, AccountStorage, AccountStorageDelta, AccountVaultDelta, - ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, - }, - assets::{Asset, AssetVault, FungibleAsset, NonFungibleAsset, NonFungibleAssetDetails}, crypto::{ hash::rpo::RpoDigest, merkle::{LeafIndex, MerklePath, SimpleSmt}, }, notes::{Nullifier, NOTE_LEAF_DEPTH}, - transaction::AccountDetails, - BlockHeader, Felt, FieldElement, Word, ONE, ZERO, + BlockHeader, Felt, FieldElement, }; use rusqlite::{vtab::array, Connection}; use super::{sql, AccountInfo, Note, NoteCreated, NullifierInfo}; -use crate::{db::migrations, errors::DatabaseError}; +use crate::db::migrations; fn create_db() -> Connection { let mut conn = Connection::open_in_memory().unwrap(); @@ -181,8 +170,7 @@ fn test_sql_select_accounts() { }); let transaction = conn.transaction().unwrap(); - let res = - sql::upsert_accounts(&transaction, &[(account_id, None, account_hash)], block_num); + let res = sql::upsert_accounts(&transaction, &[(account_id, account_hash)], block_num); assert_eq!(res.unwrap(), 1, "One element must have been inserted"); transaction.commit().unwrap(); let accounts = sql::select_accounts(&mut conn).unwrap(); @@ -190,124 +178,6 @@ fn test_sql_select_accounts() { } } -#[test] -fn test_sql_public_account_details() { - let mut conn = create_db(); - - let block_num = 1; - create_block(&mut conn, block_num); - - let (account_id, _seed) = - generate_account_seed(AccountSeedType::RegularAccountUpdatableCodeOnChain); - let fungible_faucet_id = AccountId::try_from(ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN).unwrap(); - let non_fungible_faucet_id = - AccountId::try_from(ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN).unwrap(); - - let mut storage = AccountStorage::new(vec![]).unwrap(); - storage.set_item(1, num_to_word(1)).unwrap(); - storage.set_item(3, num_to_word(3)).unwrap(); - storage.set_item(5, num_to_word(5)).unwrap(); - - let nft1 = Asset::NonFungible( - NonFungibleAsset::new( - &NonFungibleAssetDetails::new(non_fungible_faucet_id, vec![1, 2, 3]).unwrap(), - ) - .unwrap(), - ); - - let mut account = Account::new( - account_id, - AssetVault::new(&[ - Asset::Fungible(FungibleAsset::new(fungible_faucet_id, 150).unwrap()), - nft1, - ]) - .unwrap(), - storage, - mock_account_code(&TransactionKernel::assembler()), - ZERO, - ); - - // test querying empty table - let res = sql::get_account_details(&mut conn, account_id.into()); - assert!(matches!(res, Err(DatabaseError::AccountNotOnChain(_)))); - - let transaction = conn.transaction().unwrap(); - let inserted = sql::upsert_accounts( - &transaction, - &[(account_id.into(), Some(AccountDetails::Full(account.clone())), account.hash())], - block_num, - ) - .unwrap(); - - assert_eq!(inserted, 1, "One element must have been inserted"); - - transaction.commit().unwrap(); - - let account_read = sql::get_account_details(&mut conn, account_id.into()).unwrap(); - - // TODO: substitute by a single check, once code imports deserialization is fixed: - // assert_eq!(account_read, account); - assert_eq!(account_read.id(), account.id()); - assert_eq!(account_read.vault(), account.vault()); - assert_eq!(account_read.storage(), account.storage()); - assert_eq!(account_read.nonce(), account.nonce()); - - let storage_delta = AccountStorageDelta { - cleared_items: vec![3], - updated_items: vec![(4, num_to_word(5)), (5, num_to_word(6))], - }; - - let nft2 = Asset::NonFungible( - NonFungibleAsset::new( - &NonFungibleAssetDetails::new(non_fungible_faucet_id, vec![4, 5, 6]).unwrap(), - ) - .unwrap(), - ); - - let vault_delta = AccountVaultDelta { - added_assets: vec![nft2], - removed_assets: vec![nft1], - }; - - let delta = AccountDelta::new(storage_delta, vault_delta, Some(ONE)).unwrap(); - - account.apply_delta(&delta).unwrap(); - - let transaction = conn.transaction().unwrap(); - let inserted = sql::upsert_accounts( - &transaction, - &[(account_id.into(), Some(AccountDetails::Delta(delta.clone())), account.hash())], - block_num, - ) - .unwrap(); - - assert_eq!(inserted, 1, "One element must have been inserted"); - - transaction.commit().unwrap(); - - let mut account_read = sql::get_account_details(&mut conn, account_id.into()).unwrap(); - - assert_eq!(account_read.id(), account.id()); - assert_eq!(account_read.vault(), account.vault()); - assert_eq!(account_read.nonce(), account.nonce()); - - // Cleared item was not serialized, check it and apply delta only with clear item second time: - assert_eq!(account_read.storage().get_item(3), RpoDigest::default()); - - let storage_delta = AccountStorageDelta { - cleared_items: vec![3], - updated_items: vec![], - }; - account_read - .apply_delta( - &AccountDelta::new(storage_delta, AccountVaultDelta::default(), Some(Felt::new(2))) - .unwrap(), - ) - .unwrap(); - - assert_eq!(account_read.storage(), account.storage()); -} - #[test] fn test_sql_select_nullifiers_by_block_range() { let mut conn = create_db(); @@ -515,7 +385,7 @@ fn test_db_account() { let transaction = conn.transaction().unwrap(); let row_count = - sql::upsert_accounts(&transaction, &[(account_id, None, account_hash)], block_num).unwrap(); + sql::upsert_accounts(&transaction, &[(account_id, account_hash)], block_num).unwrap(); transaction.commit().unwrap(); assert_eq!(row_count, 1); @@ -648,11 +518,7 @@ fn test_notes() { // UTILITIES // ------------------------------------------------------------------------------------------- fn num_to_rpo_digest(n: u64) -> RpoDigest { - RpoDigest::new(num_to_word(n)) -} - -fn num_to_word(n: u64) -> Word { - [Felt::ZERO, Felt::ZERO, Felt::ZERO, Felt::new(n)] + RpoDigest::new([Felt::ZERO, Felt::ZERO, Felt::ZERO, Felt::new(n)]) } fn num_to_nullifier(n: u64) -> Nullifier { diff --git a/store/src/errors.rs b/store/src/errors.rs index c5b8d4d13..2856b5f96 100644 --- a/store/src/errors.rs +++ b/store/src/errors.rs @@ -3,7 +3,6 @@ use std::io; use deadpool_sqlite::PoolError; use miden_objects::{ crypto::{ - hash::rpo::RpoDigest, merkle::{MerkleError, MmrError}, utils::DeserializationError, }, @@ -14,7 +13,7 @@ use rusqlite::types::FromSqlError; use thiserror::Error; use tokio::sync::oneshot::error::RecvError; -use crate::types::{AccountId, BlockNumber}; +use crate::types::BlockNumber; // INTERNAL ERRORS // ================================================================================================= @@ -47,32 +46,8 @@ pub enum DatabaseError { InteractError(String), #[error("Deserialization of BLOB data from database failed: {0}")] DeserializationError(DeserializationError), - #[error("Corrupted data: {0}")] - CorruptedData(String), - #[error("Account error: {0}")] - AccountError(AccountError), #[error("Block applying was broken because of closed channel on state side: {0}")] ApplyBlockFailedClosedChannel(RecvError), - #[error("Public account ({0}) details not found on-chain")] - AccountNotOnChain(AccountId), - #[error("Failed to apply block because of on-chain account final hashes mismatch (expected {expected}, \ - but calculated is {calculated}")] - ApplyBlockFailedAccountHashesMismatch { - expected: RpoDigest, - calculated: RpoDigest, - }, -} - -impl From for DatabaseError { - fn from(value: DeserializationError) -> Self { - Self::DeserializationError(value) - } -} - -impl From for DatabaseError { - fn from(value: AccountError) -> Self { - Self::AccountError(value) - } } // INITIALIZATION ERRORS diff --git a/store/src/server/api.rs b/store/src/server/api.rs index d229c374e..aa64855bd 100644 --- a/store/src/server/api.rs +++ b/store/src/server/api.rs @@ -8,22 +8,22 @@ use miden_node_proto::{ note::NoteSyncRecord, requests::{ ApplyBlockRequest, CheckNullifiersRequest, GetBlockHeaderByNumberRequest, - GetBlockInputsRequest, GetPublicAccountDetailsRequest, GetTransactionInputsRequest, - ListAccountsRequest, ListNotesRequest, ListNullifiersRequest, SyncStateRequest, + GetBlockInputsRequest, GetTransactionInputsRequest, ListAccountsRequest, + ListNotesRequest, ListNullifiersRequest, SyncStateRequest, }, responses::{ AccountHashUpdate, AccountTransactionInputRecord, ApplyBlockResponse, CheckNullifiersResponse, GetBlockHeaderByNumberResponse, GetBlockInputsResponse, - GetPublicAccountDetailsResponse, GetTransactionInputsResponse, ListAccountsResponse, - ListNotesResponse, ListNullifiersResponse, NullifierTransactionInputRecord, - NullifierUpdate, SyncStateResponse, + GetTransactionInputsResponse, ListAccountsResponse, ListNotesResponse, + ListNullifiersResponse, NullifierTransactionInputRecord, NullifierUpdate, + SyncStateResponse, }, smt::SmtLeafEntry, store::api_server, }, AccountState, }; -use miden_objects::{notes::Nullifier, transaction::AccountDetails, BlockHeader, Felt, ZERO}; +use miden_objects::{notes::Nullifier, BlockHeader, Felt, ZERO}; use tonic::{Response, Status}; use tracing::{debug, info, instrument}; @@ -159,32 +159,6 @@ impl api_server::Api for StoreApi { })) } - /// Returns details for public (on-chain) account by id. - #[instrument( - target = "miden-store", - name = "store:get_public_account_details", - skip_all, - ret(level = "debug"), - err - )] - async fn get_public_account_details( - &self, - request: tonic::Request, - ) -> Result, Status> { - let request = request.into_inner(); - let account = self - .state - .get_account_details( - request.account_id.ok_or(invalid_argument("Account missing id"))?.into(), - ) - .await - .map_err(internal_error)?; - - Ok(Response::new(GetPublicAccountDetailsResponse { - details: Some((&account).into()), - })) - } - // BLOCK PRODUCER ENDPOINTS // -------------------------------------------------------------------------------------------- @@ -216,16 +190,11 @@ impl api_server::Api for StoreApi { .accounts .into_iter() .map(|account_update| { - let account_details: Option = - account_update.details.as_ref().map(TryInto::try_into).transpose().map_err( - |err: ConversionError| Status::invalid_argument(err.to_string()), - )?; let account_state: AccountState = account_update .try_into() .map_err(|err: ConversionError| Status::invalid_argument(err.to_string()))?; Ok(( account_state.account_id.into(), - account_details, account_state .account_hash .ok_or(invalid_argument("Account update missing account hash"))?, diff --git a/store/src/state.rs b/store/src/state.rs index e53d54386..d27bb2611 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -7,13 +7,11 @@ use std::{mem, sync::Arc}; use miden_node_proto::{AccountInputRecord, NullifierWitness}; use miden_node_utils::formatting::{format_account_id, format_array}; use miden_objects::{ - accounts::Account, crypto::{ hash::rpo::RpoDigest, merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, }, notes::{NoteMetadata, NoteType, Nullifier, NOTE_LEAF_DEPTH}, - transaction::AccountDetails, AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, }; use tokio::{ @@ -107,7 +105,7 @@ impl State { &self, block_header: BlockHeader, nullifiers: Vec, - accounts: Vec<(AccountId, Option, RpoDigest)>, + accounts: Vec<(AccountId, RpoDigest)>, notes: Vec, ) -> Result<(), ApplyBlockError> { let _ = self.writer.try_lock().map_err(|_| ApplyBlockError::ConcurrentWrite)?; @@ -181,7 +179,7 @@ impl State { // update account tree let mut account_tree = inner.account_tree.clone(); - for (account_id, _, account_hash) in accounts.iter() { + for (account_id, account_hash) in accounts.iter() { account_tree.insert(LeafIndex::new_max_depth(*account_id), account_hash.into()); } @@ -469,14 +467,6 @@ impl State { pub async fn list_notes(&self) -> Result, DatabaseError> { self.db.select_notes().await } - - /// Returns details for public (on-chain) account. - pub async fn get_account_details( - &self, - id: AccountId, - ) -> Result { - self.db.get_account_details(id).await - } } // UTILITIES From 618e24ec8949212386ad3518a2dae7b7c91b848e Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Sat, 30 Mar 2024 16:21:29 +0500 Subject: [PATCH 16/23] fix: compilation errors --- Cargo.lock | 72 +++++++++---------- .../src/block_builder/prover/tests.rs | 2 +- block-producer/src/test_utils/proven_tx.rs | 4 +- faucet/Cargo.toml | 4 +- proto/src/domain/notes.rs | 2 +- store/src/errors.rs | 4 +- store/src/state.rs | 11 +-- 7 files changed, 51 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8438034b6..0e7a982fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -216,7 +216,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -386,7 +386,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -397,7 +397,7 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -513,7 +513,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -694,7 +694,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1485,7 +1485,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1606,7 +1606,7 @@ dependencies = [ [[package]] name = "miden-lib" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#acfb52888ad4d76291186c1cae33d98a193e9921" dependencies = [ "miden-assembly", "miden-objects 0.2.0", @@ -1673,10 +1673,10 @@ dependencies = [ "derive_more", "figment", "miden-client", - "miden-lib 0.2.0", + "miden-lib 0.1.0", "miden-node-proto 0.2.0", "miden-node-utils 0.2.0", - "miden-objects 0.2.0", + "miden-objects 0.1.1", "serde", "tracing", "tracing-subscriber", @@ -1773,7 +1773,7 @@ name = "miden-node-test-macro" version = "0.1.0" dependencies = [ "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1823,7 +1823,7 @@ dependencies = [ [[package]] name = "miden-objects" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#acfb52888ad4d76291186c1cae33d98a193e9921" dependencies = [ "miden-assembly", "miden-core", @@ -1882,7 +1882,7 @@ dependencies = [ [[package]] name = "miden-tx" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#cc2bec3511ad9a22416a8be0fc7977eb42c4014c" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#acfb52888ad4d76291186c1cae33d98a193e9921" dependencies = [ "miden-lib 0.2.0", "miden-objects 0.2.0", @@ -1931,7 +1931,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2047,7 +2047,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2132,7 +2132,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2168,14 +2168,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2208,7 +2208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" dependencies = [ "proc-macro2", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2237,7 +2237,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "version_check", "yansi", ] @@ -2289,7 +2289,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.55", + "syn 2.0.57", "tempfile", "which", ] @@ -2304,7 +2304,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2605,7 +2605,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2738,7 +2738,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2775,9 +2775,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ "proc-macro2", "quote", @@ -2840,7 +2840,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2936,7 +2936,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3046,7 +3046,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3101,7 +3101,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3324,7 +3324,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "wasm-bindgen-shared", ] @@ -3346,7 +3346,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3588,9 +3588,9 @@ dependencies = [ [[package]] name = "winter-math" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c91111b368b08c5a76009514e9b6d26af41fbb28604ea77a249282323b64d5" +checksum = "9c36d2a04b4f79f2c8c6945aab6545b7310a0cd6ae47b9210750400df6775a04" dependencies = [ "serde", "winter-utils", @@ -3675,7 +3675,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] diff --git a/block-producer/src/block_builder/prover/tests.rs b/block-producer/src/block_builder/prover/tests.rs index 10d23502e..5c698cfa0 100644 --- a/block-producer/src/block_builder/prover/tests.rs +++ b/block-producer/src/block_builder/prover/tests.rs @@ -383,7 +383,7 @@ async fn test_compute_note_root_success() { .map(|(note_digest, &account_id)| { NoteEnvelope::new( note_digest.into(), - NoteMetadata::new(account_id, NoteType::OffChain, Felt::new(1u64)), + NoteMetadata::new(account_id, NoteType::OffChain, 0.into(), ONE).unwrap(), ) }) .collect(); diff --git a/block-producer/src/test_utils/proven_tx.rs b/block-producer/src/test_utils/proven_tx.rs index 8a9f5a280..9496407c9 100644 --- a/block-producer/src/test_utils/proven_tx.rs +++ b/block-producer/src/test_utils/proven_tx.rs @@ -6,7 +6,7 @@ use miden_objects::{ notes::{NoteEnvelope, NoteMetadata, NoteType, Nullifier}, transaction::{ProvenTransaction, ProvenTransactionBuilder}, vm::ExecutionProof, - Digest, Felt, Hasher, ONE, + Digest, Felt, Hasher, ONE, ZERO, }; use winterfell::StarkProof; @@ -84,7 +84,7 @@ impl MockProvenTxBuilder { NoteEnvelope::new( note_hash.into(), - NoteMetadata::new(self.account_id, NoteType::OffChain, ONE), + NoteMetadata::new(self.account_id, NoteType::OffChain, 0.into(), ZERO).unwrap(), ) }) .collect(); diff --git a/faucet/Cargo.toml b/faucet/Cargo.toml index 50fc69be6..3142474cf 100644 --- a/faucet/Cargo.toml +++ b/faucet/Cargo.toml @@ -15,11 +15,11 @@ actix-files = "0.6.5" actix-cors = "0.7.0" derive_more = "0.99.17" figment = { version = "0.10", features = ["toml", "env"] } -miden-lib = { workspace = true } +miden-lib = { version = "0.1" } # Need to set older version because client doesn't support newest miden-objects yet miden-client = { version = "0.1.0", features = ["concurrent"] } miden-node-proto = { path = "../proto", version = "0.2" } miden-node-utils = { path = "../utils", version = "0.2" } -miden-objects = { workspace = true } +miden-objects = { version = "0.1" } # Need to set older version because client doesn't support newest miden-objects yet serde = { version = "1.0", features = ["derive"] } clap = { version = "4.5.1", features = ["derive"] } async-mutex = "1.4.0" diff --git a/proto/src/domain/notes.rs b/proto/src/domain/notes.rs index 8e03252e6..c8b800ffc 100644 --- a/proto/src/domain/notes.rs +++ b/proto/src/domain/notes.rs @@ -25,7 +25,7 @@ impl From<(u64, NoteEnvelope)> for note::NoteCreated { Self { note_id: Some(note.note_id().into()), sender: Some(note.metadata().sender().into()), - tag: note.metadata().tag().into(), + tag: u32::from(note.metadata().tag()).into(), note_index: note_idx as u32, } } diff --git a/store/src/errors.rs b/store/src/errors.rs index 2856b5f96..9cc54c3dd 100644 --- a/store/src/errors.rs +++ b/store/src/errors.rs @@ -7,7 +7,7 @@ use miden_objects::{ utils::DeserializationError, }, notes::Nullifier, - AccountError, BlockHeader, + AccountError, BlockHeader, NoteError, }; use rusqlite::types::FromSqlError; use thiserror::Error; @@ -108,6 +108,8 @@ pub enum ApplyBlockError { DatabaseError(#[from] DatabaseError), #[error("Account error: {0}")] AccountError(#[from] AccountError), + #[error("Note error: {0}")] + NoteError(#[from] NoteError), #[error("Concurrent write detected")] ConcurrentWrite, #[error("New block number must be 1 greater than the current block number")] diff --git a/store/src/state.rs b/store/src/state.rs index d27bb2611..3f840cb2c 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -12,7 +12,7 @@ use miden_objects::{ merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, }, notes::{NoteMetadata, NoteType, Nullifier, NOTE_LEAF_DEPTH}, - AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, + AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, ZERO, }; use tokio::{ sync::{oneshot, Mutex, RwLock}, @@ -484,10 +484,11 @@ pub fn build_notes_tree( let note_metadata = NoteMetadata::new( note.sender.try_into()?, NoteType::OffChain, // TODO: provide correct note type - note.tag - .try_into() - .expect("tag value is greater than or equal to the field modulus"), - ); + u32::try_from(note.tag) + .expect("tag value is greater than or equal to the field modulus") + .into(), + ZERO, + )?; let index = note.note_index as u64; entries.push((index, note.note_id.into())); entries.push((index + 1, note_metadata.into())); From bd473985e66a5823a792319e8a829c52e1aed6fc Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Mon, 1 Apr 2024 20:49:42 +0500 Subject: [PATCH 17/23] fix: use note tag conversion from `u64` --- Cargo.lock | 6 +++--- proto/src/domain/notes.rs | 2 +- store/src/state.rs | 11 ++++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e7a982fc..62d29d6e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1606,7 +1606,7 @@ dependencies = [ [[package]] name = "miden-lib" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#acfb52888ad4d76291186c1cae33d98a193e9921" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#3175580f3eae7b2dfa7885e7959bce671afff433" dependencies = [ "miden-assembly", "miden-objects 0.2.0", @@ -1823,7 +1823,7 @@ dependencies = [ [[package]] name = "miden-objects" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#acfb52888ad4d76291186c1cae33d98a193e9921" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#3175580f3eae7b2dfa7885e7959bce671afff433" dependencies = [ "miden-assembly", "miden-core", @@ -1882,7 +1882,7 @@ dependencies = [ [[package]] name = "miden-tx" version = "0.2.0" -source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#acfb52888ad4d76291186c1cae33d98a193e9921" +source = "git+https://github.com/0xPolygonMiden/miden-base.git?branch=next#3175580f3eae7b2dfa7885e7959bce671afff433" dependencies = [ "miden-lib 0.2.0", "miden-objects 0.2.0", diff --git a/proto/src/domain/notes.rs b/proto/src/domain/notes.rs index c8b800ffc..8e03252e6 100644 --- a/proto/src/domain/notes.rs +++ b/proto/src/domain/notes.rs @@ -25,7 +25,7 @@ impl From<(u64, NoteEnvelope)> for note::NoteCreated { Self { note_id: Some(note.note_id().into()), sender: Some(note.metadata().sender().into()), - tag: u32::from(note.metadata().tag()).into(), + tag: note.metadata().tag().into(), note_index: note_idx as u32, } } diff --git a/store/src/state.rs b/store/src/state.rs index 3f840cb2c..06246d958 100644 --- a/store/src/state.rs +++ b/store/src/state.rs @@ -12,7 +12,7 @@ use miden_objects::{ merkle::{LeafIndex, Mmr, MmrDelta, MmrPeaks, SimpleSmt, SmtProof, ValuePath}, }, notes::{NoteMetadata, NoteType, Nullifier, NOTE_LEAF_DEPTH}, - AccountError, BlockHeader, Word, ACCOUNT_TREE_DEPTH, ZERO, + AccountError, BlockHeader, NoteError, Word, ACCOUNT_TREE_DEPTH, ZERO, }; use tokio::{ sync::{oneshot, Mutex, RwLock}, @@ -481,12 +481,13 @@ pub fn build_notes_tree( let mut entries: Vec<(u64, Word)> = Vec::with_capacity(notes.len() * 2); for note in notes.iter() { + let note_type = NoteType::OffChain; // TODO: provide correct note type let note_metadata = NoteMetadata::new( note.sender.try_into()?, - NoteType::OffChain, // TODO: provide correct note type - u32::try_from(note.tag) - .expect("tag value is greater than or equal to the field modulus") - .into(), + note_type, + note.tag + .try_into() + .map_err(|_| NoteError::InconsistentNoteTag(note_type, note.tag))?, ZERO, )?; let index = note.note_index as u64; From 42b0c2255a13d4da8bd7c504a4a207825fd6bac4 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:33:37 +0500 Subject: [PATCH 18/23] refactor: remove account details protobuf messages --- proto/proto/account.proto | 83 --------- proto/src/domain/accounts.rs | 322 +-------------------------------- proto/src/generated/account.rs | 147 --------------- 3 files changed, 2 insertions(+), 550 deletions(-) diff --git a/proto/proto/account.proto b/proto/proto/account.proto index 6819ccfa0..25d63bf73 100644 --- a/proto/proto/account.proto +++ b/proto/proto/account.proto @@ -15,86 +15,3 @@ message AccountInfo { digest.Digest account_hash = 2; fixed32 block_num = 3; } - -message FungibleAsset { - // Faucet ID. - AccountId faucet_id = 1; - // Amount of asset. - uint64 amount = 2; -} - -message NonFungibleAsset { - // Non-fungible asset in internal (`Word`) representation. - digest.Digest asset = 1; -} - -message Asset { - // Asset enumeration. - oneof asset { - FungibleAsset fungible = 1; - NonFungibleAsset non_fungible = 2; - } -} - -message AssetVault { - // Assets vector. - repeated Asset assets = 1; -} - -message AccountStorage { - // Full account storage serialized using Miden serialization procedure. - bytes data = 1; -} - -message AccountCode { - // Module AST tree serialized using Miden serialization procedure. - bytes module = 1; - // Procedures vector. - repeated digest.Digest procedures = 2; -} - -message AccountFullDetails { - // Account ID. - AccountId id = 1; - // All account's assets. - AssetVault vault = 2; - // Account storage. - AccountStorage storage = 3; - // Account code. - AccountCode code = 4; - // Account nonce. - uint64 nonce = 5; -} - -message AccountStorageDelta { - // Items to be cleared in the account's storage. - bytes cleared_items = 1; - // Vector of slots to be updated in the account's storage in the same order, as items. - bytes updated_storage_slots = 2; - // Vector of items to be updated in the account's storage in the same order, as slots. - repeated digest.Digest updated_items = 3; -} - -message AccountVaultDelta { - // Assets to be added into the account's vault. - repeated Asset added_assets = 1; - // Assets to be removed from the account's vault. - repeated Asset removed_assets = 2; -} - -message AccountDelta { - // Account's storage delta. - AccountStorageDelta storage = 1; - // Account's assets vault delta. - AccountVaultDelta vault = 2; - // Account's new nonce. - optional uint64 nonce = 3; -} - -message AccountDetails { - // Details enumeration for public accounts. - oneof details { - account.AccountFullDetails full = 1; - account.AccountDelta delta = 2; - } -} diff --git a/proto/src/domain/accounts.rs b/proto/src/domain/accounts.rs index 337a1c77d..3c4257f00 100644 --- a/proto/src/domain/accounts.rs +++ b/proto/src/domain/accounts.rs @@ -1,37 +1,15 @@ use std::fmt::{Debug, Display, Formatter}; use miden_node_utils::formatting::format_opt; -use miden_objects::{ - accounts::{ - Account, AccountCode, AccountDelta, AccountId, AccountStorage, AccountStorageDelta, - AccountVaultDelta, - }, - assembly::{AstSerdeOptions, ModuleAst}, - assets::{Asset, AssetVault, FungibleAsset, NonFungibleAsset}, - crypto::{hash::rpo::RpoDigest, merkle::MerklePath}, - transaction::AccountDetails, - utils::{Deserializable, Serializable}, - Digest, Felt, Word, -}; +use miden_objects::{accounts::AccountId, crypto::merkle::MerklePath, Digest}; use crate::{ - convert, errors::{ConversionError, MissingFieldHelper}, generated::{ - account::{ - account_details::{Details as DetailsPb, Details}, - asset::Asset as AssetEnumPb, - AccountCode as AccountCodePb, AccountDelta as AccountDeltaPb, - AccountDetails as AccountDetailsPb, AccountFullDetails as AccountFullDetailsPb, - AccountId as AccountIdPb, AccountStorage as AccountStoragePb, - AccountStorageDelta as AccountStorageDeltaPb, AccountVaultDelta as AccountVaultDeltaPb, - Asset as AssetPb, AssetVault as AssetVaultPb, FungibleAsset as FungibleAssetPb, - NonFungibleAsset as NonFungibleAssetPb, - }, + account::AccountId as AccountIdPb, requests::AccountUpdate, responses::{AccountBlockInputRecord, AccountTransactionInputRecord}, }, - try_convert, }; // ACCOUNT ID @@ -89,302 +67,6 @@ impl TryFrom for AccountId { } } -// INTO ACCOUNT DETAILS -// ================================================================================================ - -impl From<&FungibleAsset> for FungibleAssetPb { - fn from(fungible: &FungibleAsset) -> Self { - Self { - faucet_id: Some(fungible.faucet_id().into()), - amount: fungible.amount(), - } - } -} - -impl From<&NonFungibleAsset> for NonFungibleAssetPb { - fn from(non_fungible: &NonFungibleAsset) -> Self { - Self { - asset: Some(non_fungible.vault_key().into()), - } - } -} - -impl From<&Asset> for AssetPb { - fn from(asset: &Asset) -> Self { - let asset = Some(match asset { - Asset::Fungible(fungible) => AssetEnumPb::Fungible(fungible.into()), - Asset::NonFungible(non_fungible) => AssetEnumPb::NonFungible(non_fungible.into()), - }); - - Self { asset } - } -} - -impl From for AssetPb { - fn from(asset: Asset) -> Self { - asset.into() - } -} - -impl From<&AssetVault> for AssetVaultPb { - fn from(vault: &AssetVault) -> Self { - Self { - assets: convert(vault.assets()), - } - } -} - -impl From<&AccountStorage> for AccountStoragePb { - fn from(storage: &AccountStorage) -> Self { - Self { - data: storage.to_bytes(), - } - } -} - -impl From<&AccountCode> for AccountCodePb { - fn from(code: &AccountCode) -> Self { - Self { - module: code.module().to_bytes(AstSerdeOptions::new(true)), - procedures: convert(code.procedures()), - } - } -} - -impl From<&Account> for AccountFullDetailsPb { - fn from(account: &Account) -> Self { - Self { - id: Some(account.id().into()), - vault: Some(account.vault().into()), - storage: Some(account.storage().into()), - code: Some(account.code().into()), - nonce: account.nonce().as_int(), - } - } -} - -impl From<&AccountStorageDelta> for AccountStorageDeltaPb { - fn from(delta: &AccountStorageDelta) -> Self { - Self { - cleared_items: delta.cleared_items.clone(), - updated_storage_slots: delta.updated_items.iter().map(|(slot, _)| *slot).collect(), - updated_items: delta - .updated_items - .iter() - .map(|(_, value)| Into::::into(value)) - .map(Into::into) - .collect(), - } - } -} - -impl From<&AccountVaultDelta> for AccountVaultDeltaPb { - fn from(delta: &AccountVaultDelta) -> Self { - Self { - added_assets: convert(delta.added_assets.iter()), - removed_assets: convert(delta.removed_assets.iter()), - } - } -} - -impl From<&AccountDelta> for AccountDeltaPb { - fn from(delta: &AccountDelta) -> Self { - Self { - storage: Some(delta.storage().into()), - vault: Some(delta.vault().into()), - nonce: delta.nonce().as_ref().map(Felt::as_int), - } - } -} - -impl From<&AccountDetails> for AccountDetailsPb { - fn from(details: &AccountDetails) -> Self { - let details = Some(match details { - AccountDetails::Full(full) => DetailsPb::Full(full.into()), - AccountDetails::Delta(delta) => DetailsPb::Delta(delta.into()), - }); - - Self { details } - } -} - -// FROM ACCOUNT DETAILS -// ================================================================================================ - -impl TryFrom<&FungibleAssetPb> for FungibleAsset { - type Error = ConversionError; - - fn try_from(fungible: &FungibleAssetPb) -> Result { - let faucet_id = fungible - .faucet_id - .clone() - .ok_or(FungibleAssetPb::missing_field(stringify!(faucet_id)))? - .try_into()?; - - Ok(Self::new(faucet_id, fungible.amount)?) - } -} - -impl TryFrom<&NonFungibleAssetPb> for NonFungibleAsset { - type Error = ConversionError; - - fn try_from(non_fungible: &NonFungibleAssetPb) -> Result { - let asset: Word = non_fungible - .asset - .clone() - .ok_or(NonFungibleAssetPb::missing_field(stringify!(asset)))? - .try_into()?; - - Ok(Self::try_from(asset)?) - } -} - -impl TryFrom<&AssetPb> for Asset { - type Error = ConversionError; - - fn try_from(asset: &AssetPb) -> Result { - let from = asset.asset.as_ref().ok_or(AssetPb::missing_field(stringify!(asset)))?; - Ok(match from { - AssetEnumPb::Fungible(fungible) => Asset::Fungible(fungible.try_into()?), - AssetEnumPb::NonFungible(non_fungible) => Asset::NonFungible(non_fungible.try_into()?), - }) - } -} - -impl TryFrom<&AssetVaultPb> for AssetVault { - type Error = ConversionError; - - fn try_from(vault: &AssetVaultPb) -> Result { - let assets = try_convert(vault.assets.iter())?; - - Ok(Self::new(&assets)?) - } -} - -impl TryFrom<&AccountStoragePb> for AccountStorage { - type Error = ConversionError; - - fn try_from(storage: &AccountStoragePb) -> Result { - Ok(Self::read_from_bytes(&storage.data)?) - } -} - -impl TryFrom<&AccountCodePb> for AccountCode { - type Error = ConversionError; - - fn try_from(code: &AccountCodePb) -> Result { - let module = ModuleAst::from_bytes(&code.module)?; - let procedures = try_convert(&code.procedures)?; - - Ok(Self::from_parts(module, procedures)) - } -} - -impl TryFrom<&AccountFullDetailsPb> for Account { - type Error = ConversionError; - - fn try_from(account: &AccountFullDetailsPb) -> Result { - Ok(Self::new( - account - .id - .clone() - .ok_or(AccountFullDetailsPb::missing_field(stringify!(id)))? - .try_into()?, - account - .vault - .as_ref() - .ok_or(AccountFullDetailsPb::missing_field(stringify!(vault)))? - .try_into()?, - account - .storage - .as_ref() - .ok_or(AccountFullDetailsPb::missing_field(stringify!(storage)))? - .try_into()?, - account - .code - .as_ref() - .ok_or(AccountFullDetailsPb::missing_field(stringify!(code)))? - .try_into()?, - Felt::new(account.nonce), - )) - } -} - -impl TryFrom<&AccountStorageDeltaPb> for AccountStorageDelta { - type Error = ConversionError; - - fn try_from(from: &AccountStorageDeltaPb) -> Result { - let updated_items: Result<_, ConversionError> = from - .updated_storage_slots - .iter() - .zip(from.updated_items.iter()) - .map(|(slot, value)| Ok((*slot, value.try_into()?))) - .collect(); - let storage_delta = Self { - cleared_items: from.cleared_items.clone(), - updated_items: updated_items?, - }; - - storage_delta.validate()?; - - Ok(storage_delta) - } -} - -impl TryFrom<&AccountVaultDeltaPb> for AccountVaultDelta { - type Error = ConversionError; - - fn try_from(delta: &AccountVaultDeltaPb) -> Result { - Ok(Self { - added_assets: try_convert(delta.added_assets.iter())?, - removed_assets: try_convert(delta.removed_assets.iter())?, - }) - } -} - -impl TryFrom<&AccountDeltaPb> for AccountDelta { - type Error = ConversionError; - - fn try_from(delta: &AccountDeltaPb) -> Result { - Ok(Self::new( - delta - .storage - .as_ref() - .ok_or(AccountDeltaPb::missing_field(stringify!(storage)))? - .try_into()?, - delta - .vault - .as_ref() - .ok_or(AccountDeltaPb::missing_field(stringify!(vault)))? - .try_into()?, - delta.nonce.map(Felt::new), - )?) - } -} - -impl TryFrom<&DetailsPb> for AccountDetails { - type Error = ConversionError; - - fn try_from(details: &DetailsPb) -> Result { - Ok(match details { - Details::Full(full) => AccountDetails::Full(full.try_into()?), - Details::Delta(delta) => AccountDetails::Delta(delta.try_into()?), - }) - } -} - -impl TryFrom<&AccountDetailsPb> for AccountDetails { - type Error = ConversionError; - - fn try_from(details: &AccountDetailsPb) -> Result { - details - .details - .as_ref() - .ok_or(AccountDetailsPb::missing_field(stringify!(details)))? - .try_into() - } -} - // INTO ACCOUNT UPDATE // ================================================================================================ diff --git a/proto/src/generated/account.rs b/proto/src/generated/account.rs index 39a28184a..923c1d896 100644 --- a/proto/src/generated/account.rs +++ b/proto/src/generated/account.rs @@ -20,150 +20,3 @@ pub struct AccountInfo { #[prost(fixed32, 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 FungibleAsset { - /// Faucet ID. - #[prost(message, optional, tag = "1")] - pub faucet_id: ::core::option::Option, - /// Amount of asset. - #[prost(uint64, tag = "2")] - pub amount: u64, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct NonFungibleAsset { - /// Non-fungible asset in internal (`Word`) representation. - #[prost(message, optional, tag = "1")] - pub asset: ::core::option::Option, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Asset { - /// Asset enumeration. - #[prost(oneof = "asset::Asset", tags = "1, 2")] - pub asset: ::core::option::Option, -} -/// Nested message and enum types in `Asset`. -pub mod asset { - /// Asset enumeration. - #[derive(Eq, PartialOrd, Ord, Hash)] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Asset { - #[prost(message, tag = "1")] - Fungible(super::FungibleAsset), - #[prost(message, tag = "2")] - NonFungible(super::NonFungibleAsset), - } -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AssetVault { - /// Assets vector. - #[prost(message, repeated, tag = "1")] - pub assets: ::prost::alloc::vec::Vec, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountStorage { - /// Full account storage serialized using Miden serialization procedure. - #[prost(bytes = "vec", tag = "1")] - pub data: ::prost::alloc::vec::Vec, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountCode { - /// Module AST tree serialized using Miden serialization procedure. - #[prost(bytes = "vec", tag = "1")] - pub module: ::prost::alloc::vec::Vec, - /// Procedures vector. - #[prost(message, repeated, tag = "2")] - pub procedures: ::prost::alloc::vec::Vec, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountFullDetails { - /// Account ID. - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option, - /// All account's assets. - #[prost(message, optional, tag = "2")] - pub vault: ::core::option::Option, - /// Account storage. - #[prost(message, optional, tag = "3")] - pub storage: ::core::option::Option, - /// Account code. - #[prost(message, optional, tag = "4")] - pub code: ::core::option::Option, - /// Account nonce. - #[prost(uint64, tag = "5")] - pub nonce: u64, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountStorageDelta { - /// Items to be cleared in the account's storage. - #[prost(bytes = "vec", tag = "1")] - pub cleared_items: ::prost::alloc::vec::Vec, - /// Vector of slots to be updated in the account's storage in the same order, as items. - #[prost(bytes = "vec", tag = "2")] - pub updated_storage_slots: ::prost::alloc::vec::Vec, - /// Vector of items to be updated in the account's storage in the same order, as slots. - #[prost(message, repeated, tag = "3")] - pub updated_items: ::prost::alloc::vec::Vec, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountVaultDelta { - /// Assets to be added into the account's vault. - #[prost(message, repeated, tag = "1")] - pub added_assets: ::prost::alloc::vec::Vec, - /// Assets to be removed from the account's vault. - #[prost(message, repeated, tag = "2")] - pub removed_assets: ::prost::alloc::vec::Vec, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountDelta { - /// Account's storage delta. - #[prost(message, optional, tag = "1")] - pub storage: ::core::option::Option, - /// Account's assets vault delta. - #[prost(message, optional, tag = "2")] - pub vault: ::core::option::Option, - /// Account's new nonce. - #[prost(uint64, optional, tag = "3")] - pub nonce: ::core::option::Option, -} -#[derive(Eq, PartialOrd, Ord, Hash)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountDetails { - /// Details enumeration for public accounts. - #[prost(oneof = "account_details::Details", tags = "1, 2")] - pub details: ::core::option::Option, -} -/// Nested message and enum types in `AccountDetails`. -pub mod account_details { - /// Details enumeration for public accounts. - #[derive(Eq, PartialOrd, Ord, Hash)] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Details { - #[prost(message, tag = "1")] - Full(super::AccountFullDetails), - #[prost(message, tag = "2")] - Delta(super::AccountDelta), - } -} From bb6e18e960e904a4e398b817565abbbe0facc5d4 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:18:56 +0500 Subject: [PATCH 19/23] fix: remove unused error invariants --- block-producer/src/errors.rs | 2 -- proto/src/errors.rs | 22 +--------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/block-producer/src/errors.rs b/block-producer/src/errors.rs index ae77ce9db..144e8d3bc 100644 --- a/block-producer/src/errors.rs +++ b/block-producer/src/errors.rs @@ -113,8 +113,6 @@ pub enum BlockInputsError { #[derive(Debug, PartialEq, Eq, Error)] pub enum ApplyBlockError { - #[error("Merkle error: {0}")] - MerkleError(#[from] MerkleError), #[error("gRPC client failed with error: {0}")] GrpcClientError(String), } diff --git a/proto/src/errors.rs b/proto/src/errors.rs index 28cdb438a..63876e450 100644 --- a/proto/src/errors.rs +++ b/proto/src/errors.rs @@ -1,10 +1,6 @@ use std::any::type_name; -use miden_objects::{ - crypto::merkle::{SmtLeafError, SmtProofError}, - utils::DeserializationError, - AccountDeltaError, AssetError, AssetVaultError, -}; +use miden_objects::crypto::merkle::{SmtLeafError, SmtProofError}; use thiserror::Error; #[derive(Error, Debug, Clone, PartialEq)] @@ -15,20 +11,10 @@ pub enum ConversionError { SmtLeafError(#[from] SmtLeafError), #[error("SMT proof error: {0}")] SmtProofError(#[from] SmtProofError), - #[error("Account delta error: {0}")] - AccountDeltaError(#[from] AccountDeltaError), - #[error("Asset error: {0}")] - AssetError(#[from] AssetError), - #[error("Asset vault error: {0}")] - AssetVaultError(#[from] AssetVaultError), - #[error("Deserialization error: {0}")] - DeserializationError(DeserializationError), #[error("Too much data, expected {expected}, got {got}")] TooMuchData { expected: usize, got: usize }, #[error("Not enough data, expected {expected}, got {got}")] InsufficientData { expected: usize, got: usize }, - #[error("Number of MmrPeaks doesn't fit into memory")] - TooManyMmrPeaks, #[error("Value is not in the range 0..MODULUS")] NotAValidFelt, #[error("Field `{field_name}` required to be filled in protobuf representation of {entity}")] @@ -38,12 +24,6 @@ pub enum ConversionError { }, } -impl From for ConversionError { - fn from(value: DeserializationError) -> Self { - Self::DeserializationError(value) - } -} - pub trait MissingFieldHelper { fn missing_field(field_name: &'static str) -> ConversionError; } From 535797e39c4302da0ad23c213efc33886932b68f Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:43:37 +0500 Subject: [PATCH 20/23] refactor: introduce `UpdatedAccount` struct --- block-producer/src/batch_builder/batch.rs | 9 ++++- block-producer/src/block.rs | 3 +- block-producer/src/block_builder/mod.rs | 6 +-- .../src/block_builder/prover/block_witness.rs | 39 +++++++++++-------- .../src/block_builder/prover/tests.rs | 7 +++- block-producer/src/block_builder/tests.rs | 12 ++++-- block-producer/src/state_view/mod.rs | 11 ++---- .../src/state_view/tests/apply_block.rs | 20 ++++++++-- block-producer/src/test_utils/block.rs | 23 +++++------ block-producer/src/test_utils/store.rs | 4 +- proto/src/domain/accounts.rs | 18 ++++++--- 11 files changed, 96 insertions(+), 56 deletions(-) diff --git a/block-producer/src/batch_builder/batch.rs b/block-producer/src/batch_builder/batch.rs index 2f4752f1d..c918a3e02 100644 --- a/block-producer/src/batch_builder/batch.rs +++ b/block-producer/src/batch_builder/batch.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; +use miden_node_proto::domain::accounts::UpdatedAccount; use miden_objects::{ accounts::AccountId, crypto::{ @@ -110,10 +111,14 @@ impl TransactionBatch { /// Returns an iterator over (account_id, new_state_hash) tuples for accounts that were /// modified in this transaction batch. - pub fn updated_accounts(&self) -> impl Iterator + '_ { + pub fn updated_accounts(&self) -> impl Iterator + '_ { self.updated_accounts .iter() - .map(|(account_id, account_states)| (*account_id, account_states.final_state)) + .map(|(&account_id, account_states)| UpdatedAccount { + account_id, + final_state_hash: account_states.final_state, + details: account_states.details.clone(), + }) } /// Returns an iterator over produced nullifiers for all consumed notes. diff --git a/block-producer/src/block.rs b/block-producer/src/block.rs index 1f1c677b6..469e635ef 100644 --- a/block-producer/src/block.rs +++ b/block-producer/src/block.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use miden_node_proto::{ + domain::accounts::UpdatedAccount, errors::{ConversionError, MissingFieldHelper}, generated::responses::GetBlockInputsResponse, AccountInputRecord, NullifierWitness, @@ -17,7 +18,7 @@ use crate::store::BlockInputsError; #[derive(Debug, Clone)] pub struct Block { pub header: BlockHeader, - pub updated_accounts: Vec<(AccountId, Digest)>, + pub updated_accounts: Vec, pub created_notes: BTreeMap, pub produced_nullifiers: Vec, // TODO: diff --git a/block-producer/src/block_builder/mod.rs b/block-producer/src/block_builder/mod.rs index d92bd7943..f675d6551 100644 --- a/block-producer/src/block_builder/mod.rs +++ b/block-producer/src/block_builder/mod.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use async_trait::async_trait; use miden_node_utils::formatting::{format_array, format_blake3_digest}; -use miden_objects::{accounts::AccountId, notes::Nullifier, Digest, MAX_NOTES_PER_BATCH}; +use miden_objects::{notes::Nullifier, MAX_NOTES_PER_BATCH}; use tracing::{debug, info, instrument}; use crate::{ @@ -77,7 +77,7 @@ where batches = %format_array(batches.iter().map(|batch| format_blake3_digest(batch.id()))), ); - let updated_accounts: Vec<(AccountId, Digest)> = + let updated_accounts: Vec<_> = batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let created_notes = batches .iter() @@ -95,7 +95,7 @@ where let block_inputs = self .store .get_block_inputs( - updated_accounts.iter().map(|(account_id, _)| account_id), + updated_accounts.iter().map(|update| &update.account_id), produced_nullifiers.iter(), ) .await?; diff --git a/block-producer/src/block_builder/prover/block_witness.rs b/block-producer/src/block_builder/prover/block_witness.rs index 87bcbcd0e..971a4ec6a 100644 --- a/block-producer/src/block_builder/prover/block_witness.rs +++ b/block-producer/src/block_builder/prover/block_witness.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, BTreeSet}; +use miden_node_proto::domain::accounts::UpdatedAccount; use miden_objects::{ accounts::AccountId, crypto::merkle::{EmptySubtreeRoots, MerklePath, MerkleStore, MmrPeaks, SmtProof}, @@ -48,23 +49,27 @@ impl BlockWitness { batches .iter() .flat_map(|batch| batch.updated_accounts()) - .map(|(account_id, final_state_hash)| { - let initial_state_hash = account_initial_states - .remove(&account_id) - .expect("already validated that key exists"); - let proof = account_merkle_proofs - .remove(&account_id) - .expect("already validated that key exists"); - - ( - account_id, - AccountUpdate { - initial_state_hash, - final_state_hash, - proof, - }, - ) - }) + .map( + |UpdatedAccount {account_id, final_state_hash, + .. + }| { + let initial_state_hash = account_initial_states + .remove(&account_id) + .expect("already validated that key exists"); + let proof = account_merkle_proofs + .remove(&account_id) + .expect("already validated that key exists"); + + ( + account_id, + AccountUpdate { + initial_state_hash, + final_state_hash, + proof, + }, + ) + }, + ) .collect() }; diff --git a/block-producer/src/block_builder/prover/tests.rs b/block-producer/src/block_builder/prover/tests.rs index 5c698cfa0..3869064d1 100644 --- a/block-producer/src/block_builder/prover/tests.rs +++ b/block-producer/src/block_builder/prover/tests.rs @@ -1,5 +1,6 @@ use std::{collections::BTreeMap, iter}; +use miden_node_proto::domain::accounts::UpdatedAccount; use miden_objects::{ accounts::AccountId, crypto::merkle::{ @@ -235,7 +236,11 @@ async fn test_compute_account_root_success() { account_ids .iter() .zip(account_final_states.iter()) - .map(|(&account_id, &account_hash)| (account_id, account_hash.into())) + .map(|(&account_id, &account_hash)| UpdatedAccount { + account_id, + final_state_hash: account_hash.into(), + details: None, + }) .collect(), ) .build(); diff --git a/block-producer/src/block_builder/tests.rs b/block-producer/src/block_builder/tests.rs index bb2e4b985..df3ce2f2b 100644 --- a/block-producer/src/block_builder/tests.rs +++ b/block-producer/src/block_builder/tests.rs @@ -1,9 +1,15 @@ // block builder tests (higher level) // `apply_block()` is called -use miden_objects::Felt; -use super::*; -use crate::test_utils::{MockProvenTxBuilder, MockStoreFailure, MockStoreSuccessBuilder}; +use std::sync::Arc; + +use miden_objects::{accounts::AccountId, Digest, Felt}; + +use crate::{ + batch_builder::TransactionBatch, + block_builder::{BlockBuilder, BuildBlockError, DefaultBlockBuilder}, + test_utils::{MockProvenTxBuilder, MockStoreFailure, MockStoreSuccessBuilder}, +}; /// Tests that `build_block()` succeeds when the transaction batches are not empty #[tokio::test] diff --git a/block-producer/src/state_view/mod.rs b/block-producer/src/state_view/mod.rs index bafbf4e2d..8af9ebff6 100644 --- a/block-producer/src/state_view/mod.rs +++ b/block-producer/src/state_view/mod.rs @@ -127,18 +127,13 @@ where let mut locked_nullifiers_in_flight = self.nullifiers_in_flight.write().await; // Remove account ids of transactions in block - let account_ids_in_block = block - .updated_accounts - .iter() - .map(|(account_id, _final_account_hash)| account_id); - - for account_id in account_ids_in_block { - let was_in_flight = locked_accounts_in_flight.remove(account_id); + for update in &block.updated_accounts { + let was_in_flight = locked_accounts_in_flight.remove(&update.account_id); debug_assert!(was_in_flight); } // Remove new nullifiers of transactions in block - for nullifier in block.produced_nullifiers.iter() { + for nullifier in &block.produced_nullifiers { let was_in_flight = locked_nullifiers_in_flight.remove(nullifier); debug_assert!(was_in_flight); } diff --git a/block-producer/src/state_view/tests/apply_block.rs b/block-producer/src/state_view/tests/apply_block.rs index ac4a52348..0db199277 100644 --- a/block-producer/src/state_view/tests/apply_block.rs +++ b/block-producer/src/state_view/tests/apply_block.rs @@ -6,6 +6,8 @@ use std::iter; +use miden_node_proto::domain::accounts::UpdatedAccount; + use super::*; use crate::test_utils::{block::MockBlockBuilder, MockStoreSuccessBuilder}; @@ -32,7 +34,11 @@ async fn test_apply_block_ab1() { .await .account_updates( std::iter::once(account) - .map(|mock_account| (mock_account.id, mock_account.states[1])) + .map(|mock_account| UpdatedAccount { + account_id: mock_account.id, + final_state_hash: mock_account.states[1], + details: None, + }) .collect(), ) .build(); @@ -75,7 +81,11 @@ async fn test_apply_block_ab2() { .account_updates( accounts_in_block .into_iter() - .map(|mock_account| (mock_account.id, mock_account.states[1])) + .map(|mock_account| UpdatedAccount { + account_id: mock_account.id, + final_state_hash: mock_account.states[1], + details: None, + }) .collect(), ) .build(); @@ -120,7 +130,11 @@ async fn test_apply_block_ab3() { accounts .clone() .into_iter() - .map(|mock_account| (mock_account.id, mock_account.states[1])) + .map(|mock_account| UpdatedAccount { + account_id: mock_account.id, + final_state_hash: mock_account.states[1], + details: None, + }) .collect(), ) .build(); diff --git a/block-producer/src/test_utils/block.rs b/block-producer/src/test_utils/block.rs index a158a8d72..71bd1a1d5 100644 --- a/block-producer/src/test_utils/block.rs +++ b/block-producer/src/test_utils/block.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; +use miden_node_proto::domain::accounts::UpdatedAccount; use miden_objects::{ - accounts::AccountId, crypto::merkle::{Mmr, SimpleSmt}, notes::{NoteEnvelope, Nullifier}, BlockHeader, Digest, ACCOUNT_TREE_DEPTH, BLOCK_OUTPUT_NOTES_TREE_DEPTH, MAX_NOTES_PER_BATCH, @@ -25,12 +25,12 @@ pub async fn build_expected_block_header( let last_block_header = *store.last_block_header.read().await; // Compute new account root - let updated_accounts: Vec<(AccountId, Digest)> = + let updated_accounts: Vec<_> = batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let new_account_root = { let mut store_accounts = store.accounts.read().await.clone(); - for (account_id, new_account_state) in updated_accounts { - store_accounts.insert(account_id.into(), new_account_state.into()); + for update in updated_accounts { + store_accounts.insert(update.account_id.into(), update.final_state_hash.into()); } store_accounts.root() @@ -67,14 +67,14 @@ pub async fn build_actual_block_header( store: &MockStoreSuccess, batches: Vec, ) -> BlockHeader { - let updated_accounts: Vec<(AccountId, Digest)> = - batches.iter().flat_map(|batch| batch.updated_accounts()).collect(); + let updated_accounts: Vec<_> = + batches.iter().flat_map(TransactionBatch::updated_accounts).collect(); let produced_nullifiers: Vec = batches.iter().flat_map(|batch| batch.produced_nullifiers()).collect(); let block_inputs_from_store: BlockInputs = store .get_block_inputs( - updated_accounts.iter().map(|(account_id, _)| account_id), + updated_accounts.iter().map(|update| &update.account_id), produced_nullifiers.iter(), ) .await @@ -91,7 +91,7 @@ pub struct MockBlockBuilder { store_chain_mmr: Mmr, last_block_header: BlockHeader, - updated_accounts: Option>, + updated_accounts: Option>, created_notes: Option>, produced_nullifiers: Option>, } @@ -111,10 +111,11 @@ impl MockBlockBuilder { pub fn account_updates( mut self, - updated_accounts: Vec<(AccountId, Digest)>, + updated_accounts: Vec, ) -> Self { - for &(account_id, new_account_state) in updated_accounts.iter() { - self.store_accounts.insert(account_id.into(), new_account_state.into()); + for update in &updated_accounts { + self.store_accounts + .insert(update.account_id.into(), update.final_state_hash.into()); } self.updated_accounts = Some(updated_accounts); diff --git a/block-producer/src/test_utils/store.rs b/block-producer/src/test_utils/store.rs index 00f26a2a1..669047bd6 100644 --- a/block-producer/src/test_utils/store.rs +++ b/block-producer/src/test_utils/store.rs @@ -180,8 +180,8 @@ impl ApplyBlock for MockStoreSuccess { let mut locked_produced_nullifiers = self.produced_nullifiers.write().await; // update accounts - for &(account_id, account_hash) in block.updated_accounts.iter() { - locked_accounts.insert(account_id.into(), account_hash.into()); + for update in &block.updated_accounts { + locked_accounts.insert(update.account_id.into(), update.final_state_hash.into()); } debug_assert_eq!(locked_accounts.root(), block.header.account_root()); diff --git a/proto/src/domain/accounts.rs b/proto/src/domain/accounts.rs index 3c4257f00..49edf6310 100644 --- a/proto/src/domain/accounts.rs +++ b/proto/src/domain/accounts.rs @@ -67,14 +67,22 @@ impl TryFrom for AccountId { } } -// INTO ACCOUNT UPDATE +// ACCOUNT UPDATE // ================================================================================================ -impl From<(AccountId, Digest)> for AccountUpdate { - fn from((account_id, account_hash): (AccountId, Digest)) -> Self { +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UpdatedAccount { + pub account_id: AccountId, + pub final_state_hash: Digest, + pub details: Option, +} + +impl From<&UpdatedAccount> for AccountUpdate { + fn from(update: &UpdatedAccount) -> Self { Self { - account_id: Some(account_id.into()), - account_hash: Some(account_hash.into()), + account_id: Some(update.account_id.into()), + account_hash: Some(update.final_state_hash.into()), + details: update.details.to_bytes(), } } } From 3266818da25c4459367dac3df8bf59c685c714cf Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 5 Apr 2024 10:17:23 +0500 Subject: [PATCH 21/23] fix: rollback details conversion --- block-producer/src/batch_builder/batch.rs | 2 +- proto/src/domain/accounts.rs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/block-producer/src/batch_builder/batch.rs b/block-producer/src/batch_builder/batch.rs index c918a3e02..48edf4260 100644 --- a/block-producer/src/batch_builder/batch.rs +++ b/block-producer/src/batch_builder/batch.rs @@ -117,7 +117,7 @@ impl TransactionBatch { .map(|(&account_id, account_states)| UpdatedAccount { account_id, final_state_hash: account_states.final_state, - details: account_states.details.clone(), + details: None, // TODO: In the next PR: account_states.details.clone(), }) } diff --git a/proto/src/domain/accounts.rs b/proto/src/domain/accounts.rs index 49edf6310..9669fea75 100644 --- a/proto/src/domain/accounts.rs +++ b/proto/src/domain/accounts.rs @@ -1,7 +1,9 @@ use std::fmt::{Debug, Display, Formatter}; use miden_node_utils::formatting::format_opt; -use miden_objects::{accounts::AccountId, crypto::merkle::MerklePath, Digest}; +use miden_objects::{ + accounts::AccountId, crypto::merkle::MerklePath, transaction::AccountDetails, Digest, +}; use crate::{ errors::{ConversionError, MissingFieldHelper}, @@ -82,7 +84,7 @@ impl From<&UpdatedAccount> for AccountUpdate { Self { account_id: Some(update.account_id.into()), account_hash: Some(update.final_state_hash.into()), - details: update.details.to_bytes(), + // details: update.details.to_bytes(), } } } From fcdc33153f44d3b4d57cdc88c38a287382684e54 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 5 Apr 2024 10:17:32 +0500 Subject: [PATCH 22/23] fix: compilation error --- block-producer/src/store/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-producer/src/store/mod.rs b/block-producer/src/store/mod.rs index bd0fd81e3..b02f9fa41 100644 --- a/block-producer/src/store/mod.rs +++ b/block-producer/src/store/mod.rs @@ -135,7 +135,7 @@ impl ApplyBlock for DefaultStore { ) -> Result<(), ApplyBlockError> { let request = tonic::Request::new(ApplyBlockRequest { block: Some(block.header.into()), - accounts: convert(block.updated_accounts), + accounts: convert(&block.updated_accounts), nullifiers: convert(block.produced_nullifiers), notes: convert(block.created_notes), }); From 20f0756fb620df396544b07944ef5d8e5a599c6f Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Fri, 5 Apr 2024 13:40:48 +0500 Subject: [PATCH 23/23] format: reformat using rustfmt --- block-producer/src/block_builder/prover/block_witness.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block-producer/src/block_builder/prover/block_witness.rs b/block-producer/src/block_builder/prover/block_witness.rs index be7df16b3..c72c84ddc 100644 --- a/block-producer/src/block_builder/prover/block_witness.rs +++ b/block-producer/src/block_builder/prover/block_witness.rs @@ -50,7 +50,9 @@ impl BlockWitness { .iter() .flat_map(|batch| batch.updated_accounts()) .map( - |UpdatedAccount {account_id, final_state_hash, + |UpdatedAccount { + account_id, + final_state_hash, .. }| { let initial_state_hash = account_initial_states