Skip to content

Commit

Permalink
On-chain accounts protobuf & domain objects (#287)
Browse files Browse the repository at this point in the history
* feat: add `account_details` table to the DB

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

* refactor: use `BETWEEN` in interval comparison checks

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

* feat: (WIP) implement account details support

* feat: (WIP) implement account details support

* feat: (WIP) implement account details support

* feat: (WIP) implement account details support

* fix: db creation

* docs: remove TODO

* refactor: apply formatting

* feat: implement endpoint for getting public account details

* tests: add test for storage

* feat: add rpc endpoint for getting account details

* refactor: keep only domain object changes

* fix: compilation errors

* fix: use note tag conversion from `u64`

* refactor: remove account details protobuf messages

* fix: remove unused error invariants

* refactor: introduce `UpdatedAccount` struct

* fix: rollback details conversion

* fix: compilation error

* format: reformat using rustfmt
  • Loading branch information
polydez authored Apr 5, 2024
1 parent 1cbe5a8 commit bb79cb2
Show file tree
Hide file tree
Showing 20 changed files with 169 additions and 119 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ target/
# VS Code
.vscode/

# JetBrains IDEs
.idea/
.fleet/

# Genesis files
/accounts
genesis.dat
Expand All @@ -25,3 +29,7 @@ genesis.dat
*.sqlite3-shm
*.sqlite3-wal
db/

# Configs
/genesis.toml
/miden.toml
9 changes: 7 additions & 2 deletions block-producer/src/batch_builder/batch.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::BTreeMap;

use miden_node_proto::domain::accounts::UpdatedAccount;
use miden_objects::{
accounts::AccountId,
batches::BatchNoteTree,
Expand Down Expand Up @@ -108,10 +109,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<Item = (AccountId, Digest)> + '_ {
pub fn updated_accounts(&self) -> impl Iterator<Item = UpdatedAccount> + '_ {
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: None, // TODO: In the next PR: account_states.details.clone(),
})
}

/// Returns an iterator over produced nullifiers for all consumed notes.
Expand Down
9 changes: 5 additions & 4 deletions block-producer/src/block.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::collections::BTreeMap;

use miden_node_proto::{
errors::{MissingFieldHelper, ParseError},
domain::accounts::UpdatedAccount,
errors::{ConversionError, MissingFieldHelper},
generated::responses::GetBlockInputsResponse,
AccountInputRecord, NullifierWitness,
};
Expand All @@ -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<UpdatedAccount>,
pub created_notes: Vec<(usize, usize, NoteEnvelope)>,
pub produced_nullifiers: Vec<Nullifier>,
// TODO:
Expand Down Expand Up @@ -94,7 +95,7 @@ impl TryFrom<GetBlockInputsResponse> for BlockInputs {
};
Ok((domain.account_id, witness))
})
.collect::<Result<BTreeMap<_, _>, ParseError>>()?;
.collect::<Result<BTreeMap<_, _>, ConversionError>>()?;

let nullifiers = get_block_inputs
.nullifiers
Expand All @@ -103,7 +104,7 @@ impl TryFrom<GetBlockInputsResponse> for BlockInputs {
let witness: NullifierWitness = entry.try_into()?;
Ok((witness.nullifier, witness.proof))
})
.collect::<Result<BTreeMap<_, _>, ParseError>>()?;
.collect::<Result<BTreeMap<_, _>, ConversionError>>()?;

Ok(Self {
block_header,
Expand Down
6 changes: 3 additions & 3 deletions block-producer/src/block_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
use miden_objects::notes::Nullifier;
use tracing::{debug, info, instrument};

use crate::{
Expand Down Expand Up @@ -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()
Expand All @@ -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?;
Expand Down
41 changes: 24 additions & 17 deletions block-producer/src/block_builder/prover/block_witness.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -48,23 +49,29 @@ 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()
};

Expand Down
7 changes: 6 additions & 1 deletion block-producer/src/block_builder/prover/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{collections::BTreeMap, iter};

use miden_node_proto::domain::accounts::UpdatedAccount;
use miden_objects::{
accounts::AccountId,
crypto::merkle::{
Expand Down Expand Up @@ -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();
Expand Down
12 changes: 9 additions & 3 deletions block-producer/src/block_builder/tests.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand Down
8 changes: 3 additions & 5 deletions block-producer/src/errors.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -101,7 +101,7 @@ pub enum BlockProverError {
#[derive(Debug, PartialEq, Eq, 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}")]
Expand All @@ -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),
}
Expand Down Expand Up @@ -153,7 +151,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,
}
11 changes: 3 additions & 8 deletions block-producer/src/state_view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
20 changes: 17 additions & 3 deletions block-producer/src/state_view/tests/apply_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use std::iter;

use miden_node_proto::domain::accounts::UpdatedAccount;

use super::*;
use crate::test_utils::{block::MockBlockBuilder, MockStoreSuccessBuilder};

Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
6 changes: 3 additions & 3 deletions block-producer/src/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -83,7 +83,7 @@ impl Display for TransactionInputs {
}

impl TryFrom<GetTransactionInputsResponse> for TransactionInputs {
type Error = ParseError;
type Error = ConversionError;

fn try_from(response: GetTransactionInputsResponse) -> Result<Self, Self::Error> {
let AccountState {
Expand Down Expand Up @@ -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),
});
Expand Down
23 changes: 12 additions & 11 deletions block-producer/src/test_utils/block.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use miden_node_proto::domain::accounts::UpdatedAccount;
use miden_objects::{
accounts::AccountId,
block::BlockNoteTree,
crypto::merkle::{Mmr, SimpleSmt},
notes::{NoteEnvelope, Nullifier},
Expand All @@ -23,12 +23,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()
Expand Down Expand Up @@ -65,14 +65,14 @@ pub async fn build_actual_block_header(
store: &MockStoreSuccess,
batches: Vec<TransactionBatch>,
) -> 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<Nullifier> =
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
Expand All @@ -89,7 +89,7 @@ pub struct MockBlockBuilder {
store_chain_mmr: Mmr,
last_block_header: BlockHeader,

updated_accounts: Option<Vec<(AccountId, Digest)>>,
updated_accounts: Option<Vec<UpdatedAccount>>,
created_notes: Option<Vec<(usize, usize, NoteEnvelope)>>,
produced_nullifiers: Option<Vec<Nullifier>>,
}
Expand All @@ -109,10 +109,11 @@ impl MockBlockBuilder {

pub fn account_updates(
mut self,
updated_accounts: Vec<(AccountId, Digest)>,
updated_accounts: Vec<UpdatedAccount>,
) -> 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);
Expand Down
Loading

0 comments on commit bb79cb2

Please sign in to comment.