Skip to content

Commit

Permalink
Merge branch 'next' into phklive-offset-baset-storage-access
Browse files Browse the repository at this point in the history
  • Loading branch information
phklive committed Aug 2, 2024
2 parents 009ccee + 493e193 commit ecd788d
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 126 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Added `CHANGELOG.md` warning message on CI (#799).
- Account deltas can now be merged (#797).
- Changed `AccountCode` procedures from merkle tree to sequential hash + added storage_offset support (#763).
- [BREAKING] Refactored and simplified `NoteOrigin` and `NoteInclusionProof` structs (#810, #814).

## 0.4.0 (2024-07-03)

Expand Down
43 changes: 23 additions & 20 deletions miden-lib/src/transaction/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use alloc::vec::Vec;
use miden_objects::{
accounts::{Account, AccountProcedureInfo},
transaction::{
ChainMmr, ExecutedTransaction, InputNote, InputNotes, PreparedTransaction, TransactionArgs,
ChainMmr, ExecutedTransaction, InputNote, PreparedTransaction, TransactionArgs,
TransactionInputs, TransactionScript, TransactionWitness,
},
vm::{AdviceInputs, StackInputs},
Expand Down Expand Up @@ -92,7 +92,7 @@ fn extend_advice_inputs(
// build the advice map and Merkle store for relevant components
add_chain_mmr_to_advice_inputs(tx_inputs.block_chain(), advice_inputs);
add_account_to_advice_inputs(tx_inputs.account(), tx_inputs.account_seed(), advice_inputs);
add_input_notes_to_advice_inputs(tx_inputs.input_notes(), tx_args, advice_inputs);
add_input_notes_to_advice_inputs(tx_inputs, tx_args, advice_inputs);
advice_inputs.extend(tx_args.advice_inputs().clone());
}

Expand Down Expand Up @@ -267,29 +267,29 @@ fn add_account_to_advice_inputs(
/// The advice provider is populated with:
///
/// - For each note:
/// - The note's details (serial number, script root, and its' input / assets hash).
/// - The note's details (serial number, script root, and its input / assets hash).
/// - The note's private arguments.
/// - The note's public metadata.
/// - The note's public inputs data. Prefixed by its length and padded to an even word length.
/// - The note's asset padded. Prefixed by its length and padded to an even word length.
/// - For autheticated notes (determined by the `is_authenticated` flag):
/// - For authenticated notes (determined by the `is_authenticated` flag):
/// - The note's authentication path against its block's note tree.
/// - The block number, sub hash, note root.
/// - The note's position in the note tree
///
/// The data above is processed by `prologue::process_input_notes_data`.
fn add_input_notes_to_advice_inputs(
notes: &InputNotes<InputNote>,
tx_inputs: &TransactionInputs,
tx_args: &TransactionArgs,
inputs: &mut AdviceInputs,
) {
// if there are no input notes, nothing is added to the advice inputs
if notes.is_empty() {
if tx_inputs.input_notes().is_empty() {
return;
}

let mut note_data = Vec::new();
for input_note in notes.iter() {
for input_note in tx_inputs.input_notes().iter() {
let note = input_note.note();
let assets = note.assets();
let recipient = note.recipient();
Expand Down Expand Up @@ -320,6 +320,16 @@ fn add_input_notes_to_advice_inputs(
// insert note authentication path nodes into the Merkle store
match input_note {
InputNote::Authenticated { note, proof } => {
let block_num = proof.location().block_num();
let note_block_header = if block_num == tx_inputs.block_header().block_num() {
tx_inputs.block_header()
} else {
tx_inputs
.block_chain()
.get_block(block_num)
.expect("block not found in chain MMR")
};

// NOTE: keep in sync with the `prologue::process_input_note` kernel procedure
// Push the `is_authenticated` flag
note_data.push(Felt::ONE);
Expand All @@ -328,20 +338,13 @@ fn add_input_notes_to_advice_inputs(
inputs.extend_merkle_store(
proof
.note_path()
.inner_nodes(proof.origin().node_index.value(), note.hash())
.inner_nodes(proof.location().node_index_in_block().into(), note.hash())
.unwrap(),
);
note_data.push(proof.origin().block_num.into());
note_data.extend(*proof.sub_hash());
note_data.extend(*proof.note_root());
note_data.push(
proof
.origin()
.node_index
.value()
.try_into()
.expect("value is greater than or equal to the field modulus"),
);
note_data.push(proof.location().block_num().into());
note_data.extend(note_block_header.sub_hash());
note_data.extend(note_block_header.note_root());
note_data.push(proof.location().node_index_in_block().into());
},
InputNote::Unauthenticated { .. } => {
// NOTE: keep in sync with the `prologue::process_input_note` kernel procedure
Expand All @@ -352,5 +355,5 @@ fn add_input_notes_to_advice_inputs(
}

// NOTE: keep map in sync with the `prologue::process_input_notes_data` kernel procedure
inputs.extend_map([(notes.commitment(), note_data)]);
inputs.extend_map([(tx_inputs.input_notes().commitment(), note_data)]);
}
9 changes: 1 addition & 8 deletions miden-tx/src/compiler/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,7 @@ fn test_transaction_compilation_succeeds() {
let _account_code = tx_compiler.load_account(account_id, account_code_ast).unwrap();

let notes = mock_input_notes(&mut tx_compiler, account_id);
let mock_inclusion_proof = NoteInclusionProof::new(
Default::default(),
Default::default(),
Default::default(),
0,
Default::default(),
)
.unwrap();
let mock_inclusion_proof = NoteInclusionProof::new(0, 0, Default::default()).unwrap();
let notes = notes
.into_iter()
.map(|note| InputNote::authenticated(note, mock_inclusion_proof.clone()))
Expand Down
6 changes: 3 additions & 3 deletions objects/src/batches/note_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ use miden_crypto::{

use crate::{
notes::{NoteId, NoteMetadata},
BATCH_OUTPUT_NOTES_TREE_DEPTH,
BATCH_NOTES_TREE_DEPTH,
};

/// Wrapper over [SimpleSmt<BATCH_OUTPUT_NOTES_TREE_DEPTH>] for batch note tree.
/// Wrapper over [SimpleSmt<BATCH_NOTES_TREE_DEPTH>] for batch note tree.
///
/// Each note is stored as two adjacent leaves: odd leaf for id, even leaf for metadata hash.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct BatchNoteTree(SimpleSmt<BATCH_OUTPUT_NOTES_TREE_DEPTH>);
pub struct BatchNoteTree(SimpleSmt<BATCH_NOTES_TREE_DEPTH>);

impl BatchNoteTree {
/// Wrapper around [`SimpleSmt::with_contiguous_leaves`] which populates notes at contiguous indices
Expand Down
19 changes: 11 additions & 8 deletions objects/src/block/note_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ use miden_crypto::{
use crate::{
notes::NoteMetadata,
utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
BLOCK_OUTPUT_NOTES_TREE_DEPTH, MAX_NOTES_PER_BATCH,
BLOCK_NOTES_TREE_DEPTH, MAX_NOTES_PER_BATCH, MAX_NOTES_PER_BLOCK,
};

/// Wrapper over [SimpleSmt<BLOCK_OUTPUT_NOTES_TREE_DEPTH>] for notes tree.
/// Wrapper over [SimpleSmt<BLOCK_NOTES_TREE_DEPTH>] for notes tree.
///
/// Each note is stored as two adjacent leaves: odd leaf for id, even leaf for metadata hash.
/// ID's leaf index is calculated as [(batch_idx * MAX_NOTES_PER_BATCH + note_idx_in_batch) * 2].
/// Metadata hash leaf is stored the next after id leaf: [id_index + 1].
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct BlockNoteTree(SimpleSmt<BLOCK_OUTPUT_NOTES_TREE_DEPTH>);
pub struct BlockNoteTree(SimpleSmt<BLOCK_NOTES_TREE_DEPTH>);

impl BlockNoteTree {
/// Returns a new [BlockNoteTree] instantiated with entries set as specified by the provided entries.
Expand All @@ -35,7 +35,7 @@ impl BlockNoteTree {
entries: impl IntoIterator<Item = (BlockNoteIndex, RpoDigest, NoteMetadata)>,
) -> Result<Self, MerkleError> {
let interleaved = entries.into_iter().flat_map(|(index, note_id, metadata)| {
let id_index = index.leaf_index();
let id_index = index.leaf_index().into();
[(id_index, note_id.into()), (id_index + 1, metadata.into())]
});

Expand All @@ -52,7 +52,7 @@ impl BlockNoteTree {
/// The returned path is to the node which is the parent of both note and note metadata node.
pub fn get_note_path(&self, index: BlockNoteIndex) -> Result<MerklePath, MerkleError> {
// get the path to the leaf containing the note (path len = 21)
let leaf_index = LeafIndex::new(index.leaf_index())?;
let leaf_index = LeafIndex::new(index.leaf_index().into())?;

// move up the path by removing the first node, this path now points to the parent of the
// note path
Expand Down Expand Up @@ -92,11 +92,14 @@ impl BlockNoteIndex {
}

/// Returns an index to the node which the parent of both the note and note metadata.
pub fn to_absolute_index(&self) -> u64 {
(self.batch_idx() * MAX_NOTES_PER_BATCH + self.note_idx_in_batch()) as u64
pub fn to_absolute_index(&self) -> u32 {
const _: () = assert!(MAX_NOTES_PER_BLOCK <= u32::MAX as usize);
(self.batch_idx() * MAX_NOTES_PER_BATCH + self.note_idx_in_batch()) as u32
}

fn leaf_index(&self) -> u64 {
/// Returns an index of the leaf containing the note.
fn leaf_index(&self) -> u32 {
const _: () = assert!(MAX_NOTES_PER_BLOCK * 2 <= u32::MAX as usize);
self.to_absolute_index() * 2
}
}
Expand Down
21 changes: 10 additions & 11 deletions objects/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,13 @@ pub const MIN_PROOF_SECURITY_LEVEL: u32 = 96;
///
/// A single note uses two leaves in the tree. The even leaf is used to store the note's id, the
/// odd leaf is used to store the note's metadata.
pub const BATCH_OUTPUT_NOTES_TREE_DEPTH: u8 = 13;
pub const BATCH_NOTES_TREE_DEPTH: u8 = 13;

/// The maximum number of notes that can be created in a single batch.
///
/// Because the tree used in a batch has fixed depth, and each note takes two leaves, the maximum
/// number of notes is the number of leaves in the tree.
pub const MAX_NOTES_PER_BATCH: usize = 2_usize.pow((BATCH_OUTPUT_NOTES_TREE_DEPTH - 1) as u32);

/// The maximum number of transaction in a single batch.
pub const MAX_TRANSACTIONS_PER_BATCH: usize = MAX_NOTES_PER_BATCH / MAX_OUTPUT_NOTES_PER_TX;
pub const MAX_NOTES_PER_BATCH: usize = 2_usize.pow((BATCH_NOTES_TREE_DEPTH - 1) as u32);

// BLOCK
// ================================================================================================
Expand All @@ -48,16 +45,18 @@ pub const MAX_TRANSACTIONS_PER_BATCH: usize = MAX_NOTES_PER_BATCH / MAX_OUTPUT_N
/// This value can be interpreted as:
///
/// - The depth of a tree with the leaves set to a batch output note tree root.
/// - The level at which the batches create note trees are merged, creating a new tree with this many
/// additional new levels.
pub const BLOCK_OUTPUT_NOTES_BATCH_TREE_DEPTH: u8 = 8;
/// - The level at which the batches create note trees are merged, creating a new tree with this
/// many additional new levels.
pub const BLOCK_NOTES_BATCH_TREE_DEPTH: u8 = 8;

/// The final depth of the Sparse Merkle Tree used to store all notes created in a block.
pub const BLOCK_OUTPUT_NOTES_TREE_DEPTH: u8 =
BATCH_OUTPUT_NOTES_TREE_DEPTH + BLOCK_OUTPUT_NOTES_BATCH_TREE_DEPTH;
pub const BLOCK_NOTES_TREE_DEPTH: u8 = BATCH_NOTES_TREE_DEPTH + BLOCK_NOTES_BATCH_TREE_DEPTH;

/// Maximum number of batches that can be inserted into a single block.
pub const MAX_BATCHES_PER_BLOCK: usize = 2_usize.pow(BLOCK_OUTPUT_NOTES_BATCH_TREE_DEPTH as u32);
pub const MAX_BATCHES_PER_BLOCK: usize = 2_usize.pow(BLOCK_NOTES_BATCH_TREE_DEPTH as u32);

/// Maximum number of output notes that can be created in a single block.
pub const MAX_NOTES_PER_BLOCK: usize = MAX_NOTES_PER_BATCH * MAX_BATCHES_PER_BLOCK;

/// The block height of the genesis block
pub const GENESIS_BLOCK: u32 = 0;
6 changes: 3 additions & 3 deletions objects/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub enum NoteError {
InvalidNoteTagUseCase(u16),
InvalidNoteType(NoteType),
InvalidNoteTypeValue(u64),
InvalidOriginIndex(String),
InvalidLocationIndex(String),
InvalidStubDataLen(usize),
NetworkExecutionRequiresOnChainAccount,
NetworkExecutionRequiresPublicNote(NoteType),
Expand All @@ -166,8 +166,8 @@ impl NoteError {
Self::DuplicateNonFungibleAsset(asset)
}

pub fn invalid_origin_index(msg: String) -> Self {
Self::InvalidOriginIndex(msg)
pub fn invalid_location_index(msg: String) -> Self {
Self::InvalidLocationIndex(msg)
}

pub fn too_many_assets(num_assets: usize) -> Self {
Expand Down
9 changes: 1 addition & 8 deletions objects/src/notes/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,7 @@ mod tests {
#[test]
fn serialize_with_proof() {
let note = create_example_note();
let mock_inclusion_proof = NoteInclusionProof::new(
Default::default(),
Default::default(),
Default::default(),
0,
Default::default(),
)
.unwrap();
let mock_inclusion_proof = NoteInclusionProof::new(0, 0, Default::default()).unwrap();
let file = NoteFile::NoteWithProof(note.clone(), mock_inclusion_proof.clone());
let mut buffer = Vec::new();
file.write_into(&mut buffer);
Expand Down
Loading

0 comments on commit ecd788d

Please sign in to comment.