Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: return tx block height info (decoupled approach) #386

Merged
merged 9 commits into from
Jun 18, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Changelog

* Return a list of `TransactionSummary` objects instead of just transaction IDs in the state sync endpoint (#386).
* Fix faucet note script so that it uses the `aux` input (#387).
* Added `aux` column to notes table (#384).
* Standardised CI and Makefile across Miden repositories (#367)
Expand Down
15 changes: 8 additions & 7 deletions crates/proto/proto/responses.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "merkle.proto";
import "mmr.proto";
import "note.proto";
import "smt.proto";
import "transaction.proto";

message ApplyBlockResponse {}

Expand Down Expand Up @@ -39,20 +40,20 @@ message SyncStateResponse {
// Block header of the block with the first note matching the specified criteria
block_header.BlockHeader block_header = 2;

// Data needed to update the partial MMR from `block_num + 1` to `block_header.block_num`
// Data needed to update the partial MMR from `request.block_num + 1` to `response.block_header.block_num`
mmr.MmrDelta mmr_delta = 3;

// List of account hashes updated after `block_num + 1` but not after `block_header.block_num`
// List of account hashes updated after `request.block_num + 1` but not after `response.block_header.block_num`
repeated account.AccountSummary accounts = 5;

// List of IDs for transactions executed against requested accounts between
// `block_num + 1` and `block_header.block_num`
repeated digest.Digest transactions = 6;
// List of transactions executed against requested accounts between `request.block_num + 1` and
// `response.block_header.block_num`
repeated transaction.TransactionSummary transactions = 6;

// List of all notes together with the Merkle paths from `block_header.note_root`
// List of all notes together with the Merkle paths from `response.block_header.note_root`
repeated note.NoteSyncRecord notes = 7;

// List of nullifiers created between `block_num + 1` and `block_header.block_num`
// List of nullifiers created between `request.block_num + 1` and `response.block_header.block_num`
repeated NullifierUpdate nullifiers = 8;
}

Expand Down
16 changes: 16 additions & 0 deletions crates/proto/proto/transaction.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
syntax = "proto3";
package transaction;

import "account.proto";
import "digest.proto";

message TransactionId {
digest.Digest id = 1;
}

message TransactionSummary {
TransactionId transaction_id = 1;
fixed32 block_num = 2;
account.AccountId account_id = 3;
}

1 change: 1 addition & 0 deletions crates/proto/src/domain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod digest;
pub mod merkle;
pub mod notes;
pub mod nullifiers;
pub mod transactions;

// UTILITIES
// ================================================================================================
Expand Down
59 changes: 59 additions & 0 deletions crates/proto/src/domain/transactions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use miden_objects::{crypto::hash::rpo::RpoDigest, transaction::TransactionId};

use crate::{
errors::ConversionError,
generated::{digest::Digest, transaction::TransactionId as TransactionIdPb},
};

// FROM TRANSACTION ID
// ================================================================================================

impl From<&TransactionId> for Digest {
fn from(value: &TransactionId) -> Self {
(*value).inner().into()
}
}

impl From<TransactionId> for Digest {
fn from(value: TransactionId) -> Self {
value.inner().into()
}
}

impl From<&TransactionId> for TransactionIdPb {
fn from(value: &TransactionId) -> Self {
TransactionIdPb { id: Some(value.into()) }
}
}

impl From<TransactionId> for TransactionIdPb {
fn from(value: TransactionId) -> Self {
(&value).into()
}
}

// INTO TRANSACTION ID
// ================================================================================================

impl TryFrom<Digest> for TransactionId {
type Error = ConversionError;

fn try_from(value: Digest) -> Result<Self, Self::Error> {
let digest: RpoDigest = value.try_into()?;
Ok(digest.into())
}
}

impl TryFrom<TransactionIdPb> for TransactionId {
type Error = ConversionError;

fn try_from(value: TransactionIdPb) -> Result<Self, Self::Error> {
value
.id
.ok_or(ConversionError::MissingFieldInProtobufRepresentation {
entity: "TransactionId",
field_name: "id",
})?
.try_into()
}
}
1 change: 1 addition & 0 deletions crates/proto/src/generated/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ pub mod responses;
pub mod rpc;
pub mod smt;
pub mod store;
pub mod transaction;
14 changes: 7 additions & 7 deletions crates/proto/src/generated/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,20 @@ pub struct SyncStateResponse {
/// Block header of the block with the first note matching the specified criteria
#[prost(message, optional, tag = "2")]
pub block_header: ::core::option::Option<super::block_header::BlockHeader>,
/// Data needed to update the partial MMR from `block_num + 1` to `block_header.block_num`
/// Data needed to update the partial MMR from `request.block_num + 1` to `response.block_header.block_num`
#[prost(message, optional, tag = "3")]
pub mmr_delta: ::core::option::Option<super::mmr::MmrDelta>,
/// List of account hashes updated after `block_num + 1` but not after `block_header.block_num`
/// List of account hashes updated after `request.block_num + 1` but not after `response.block_header.block_num`
#[prost(message, repeated, tag = "5")]
pub accounts: ::prost::alloc::vec::Vec<super::account::AccountSummary>,
/// List of IDs for transactions executed against requested accounts between
/// `block_num + 1` and `block_header.block_num`
/// List of transactions executed against requested accounts between `request.block_num + 1` and
/// `response.block_header.block_num`
#[prost(message, repeated, tag = "6")]
pub transactions: ::prost::alloc::vec::Vec<super::digest::Digest>,
/// List of all notes together with the Merkle paths from `block_header.note_root`
pub transactions: ::prost::alloc::vec::Vec<super::transaction::TransactionSummary>,
/// List of all notes together with the Merkle paths from `response.block_header.note_root`
#[prost(message, repeated, tag = "7")]
pub notes: ::prost::alloc::vec::Vec<super::note::NoteSyncRecord>,
/// List of nullifiers created between `block_num + 1` and `block_header.block_num`
/// List of nullifiers created between `request.block_num + 1` and `response.block_header.block_num`
#[prost(message, repeated, tag = "8")]
pub nullifiers: ::prost::alloc::vec::Vec<NullifierUpdate>,
}
Expand Down
17 changes: 17 additions & 0 deletions crates/proto/src/generated/transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This file is @generated by prost-build.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TransactionId {
#[prost(message, optional, tag = "1")]
pub id: ::core::option::Option<super::digest::Digest>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TransactionSummary {
#[prost(message, optional, tag = "1")]
pub transaction_id: ::core::option::Option<TransactionId>,
#[prost(fixed32, tag = "2")]
pub block_num: u32,
#[prost(message, optional, tag = "3")]
pub account_id: ::core::option::Option<super::account::AccountId>,
}
11 changes: 7 additions & 4 deletions crates/rpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,13 @@ 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`: `[AccountSummary]` – account summaries for accounts 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`.
- `mmr_delta`: `MmrDelta` – data needed to update the partial MMR from `request.block_num + 1` to `response.block_header.block_num`.
- `accounts`: `[AccountSummary]` – account summaries for accounts updated after `request.block_num + 1` but not after `response.block_header.block_num`.
- `transactions`: `[TransactionSummary]` – transaction summaries for transactions included after `request.block_num + 1` but not after `response.block_header.block_num`.
- Each `TransactionSummary` consists of the `transaction_id` the transaction identifier, `account_id` of the account that executed that transaction, `block_num` the block number in which the transaction was included.
- `notes`: `[NoteSyncRecord]` – a list of all notes together with the Merkle paths from `response.block_header.note_root`.
- `nullifiers`: `[NullifierUpdate]` – a list of nullifiers created between `request.block_num + 1` and `response.block_header.block_num`.
- Each `NullifierUpdate` consists of the `nullifier` and `block_num` the block number in which the note corresponding to that nullifier was consumed.

### SubmitProvenTransaction

Expand Down
11 changes: 7 additions & 4 deletions crates/store/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,13 @@ 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`: `[AccountSummary]` – account summaries for accounts 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`.
- `mmr_delta`: `MmrDelta` – data needed to update the partial MMR from `request.block_num + 1` to `response.block_header.block_num`.
- `accounts`: `[AccountSummary]` – account summaries for accounts updated after `request.block_num + 1` but not after `response.block_header.block_num`.
- `transactions`: `[TransactionSummary]` – transaction summaries for transactions included after `request.block_num + 1` but not after `response.block_header.block_num`.
- Each `TransactionSummary` consists of the `transaction_id` the transaction identifier, `account_id` of the account that executed that transaction, `block_num` the block number in which the transaction was included.
- `notes`: `[NoteSyncRecord]` – a list of all notes together with the Merkle paths from `response.block_header.note_root`.
- `nullifiers`: `[NullifierUpdate]` – a list of nullifiers created between `request.block_num + 1` and `response.block_header.block_num`.
- Each `NullifierUpdate` consists of the `nullifier` and `block_num` the block number in which the note corresponding to that nullifier was consumed.

## Methods for testing purposes

Expand Down
10 changes: 9 additions & 1 deletion crates/store/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use miden_objects::{
block::{Block, BlockNoteIndex},
crypto::{hash::rpo::RpoDigest, merkle::MerklePath, utils::Deserializable},
notes::{NoteId, NoteMetadata, Nullifier},
transaction::TransactionId,
utils::Serializable,
BlockHeader, GENESIS_BLOCK,
};
Expand Down Expand Up @@ -48,6 +49,13 @@ pub struct NullifierInfo {
pub block_num: BlockNumber,
}

#[derive(Debug, PartialEq)]
pub struct TransactionSummary {
pub account_id: AccountId,
pub block_num: BlockNumber,
pub transaction_id: TransactionId,
}

#[derive(Debug, Clone, PartialEq)]
pub struct NoteRecord {
pub block_num: BlockNumber,
Expand Down Expand Up @@ -77,7 +85,7 @@ pub struct StateSyncUpdate {
pub block_header: BlockHeader,
pub chain_tip: BlockNumber,
pub account_updates: Vec<AccountSummary>,
pub transactions: Vec<RpoDigest>,
pub transactions: Vec<TransactionSummary>,
pub nullifiers: Vec<NullifierInfo>,
}

Expand Down
15 changes: 10 additions & 5 deletions crates/store/src/db/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use miden_objects::{
block::{BlockAccountUpdate, BlockNoteIndex},
crypto::{hash::rpo::RpoDigest, merkle::MerklePath},
notes::{NoteId, NoteMetadata, NoteType, Nullifier},
transaction::TransactionId,
utils::serde::{Deserializable, Serializable},
BlockHeader,
};
Expand All @@ -17,7 +18,7 @@ use rusqlite::{
Connection, OptionalExtension, Transaction,
};

use super::{NoteRecord, NullifierInfo, Result, StateSyncUpdate};
use super::{NoteRecord, NullifierInfo, Result, StateSyncUpdate, TransactionSummary};
use crate::{
errors::{DatabaseError, StateSyncError},
types::{AccountId, BlockNumber},
Expand Down Expand Up @@ -688,12 +689,14 @@ pub fn select_transactions_by_accounts_and_block_range(
block_start: BlockNumber,
block_end: BlockNumber,
account_ids: &[AccountId],
) -> Result<Vec<RpoDigest>> {
) -> Result<Vec<TransactionSummary>> {
let account_ids: Vec<Value> = account_ids.iter().copied().map(u64_to_value).collect();

let mut stmt = conn.prepare(
"
SELECT
account_id,
block_num,
transaction_id
FROM
transactions
Expand All @@ -710,10 +713,12 @@ pub fn select_transactions_by_accounts_and_block_range(

let mut result = vec![];
while let Some(row) = rows.next()? {
let transaction_id_data = row.get_ref(0)?.as_blob()?;
let transaction_id = RpoDigest::read_from_bytes(transaction_id_data)?;
let account_id = column_value_as_u64(row, 0)?;
let block_num = row.get(1)?;
let transaction_id_data = row.get_ref(2)?.as_blob()?;
let transaction_id = TransactionId::read_from_bytes(transaction_id_data)?;

result.push(transaction_id);
result.push(TransactionSummary { account_id, block_num, transaction_id });
}

Ok(result)
Expand Down
4 changes: 2 additions & 2 deletions crates/store/src/db/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use miden_objects::{
use rusqlite::{vtab::array, Connection};

use super::{sql, AccountInfo, NoteRecord, NullifierInfo};
use crate::db::migrations::apply_migrations;
use crate::db::{migrations::apply_migrations, TransactionSummary};

fn create_db() -> Connection {
let mut conn = Connection::open_in_memory().unwrap();
Expand Down Expand Up @@ -108,7 +108,7 @@ fn test_sql_insert_transactions() {

#[test]
fn test_sql_select_transactions() {
fn query_transactions(conn: &mut Connection) -> Vec<RpoDigest> {
fn query_transactions(conn: &mut Connection) -> Vec<TransactionSummary> {
sql::select_transactions_by_accounts_and_block_range(conn, 0, 2, &[1]).unwrap()
}

Expand Down
11 changes: 10 additions & 1 deletion crates/store/src/server/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use miden_node_proto::{
},
smt::SmtLeafEntry,
store::api_server,
transaction::TransactionSummary,
},
try_convert,
};
Expand Down Expand Up @@ -141,7 +142,15 @@ impl api_server::Api for StoreApi {
})
.collect();

let transactions = state.transactions.into_iter().map(Into::into).collect();
let transactions = state
.transactions
.into_iter()
.map(|transaction_summary| TransactionSummary {
account_id: Some(transaction_summary.account_id.into()),
block_num: transaction_summary.block_num,
transaction_id: Some(transaction_summary.transaction_id.into()),
})
.collect();

let notes = state
.notes
Expand Down
Loading